From dab9409d14d226cb784441c530666baa12968e22 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 29 Sep 2020 16:09:04 -0700 Subject: Add debug logs to BlastBufferQueue Bug: 168917217 Test: Enable logs and check logcat Test: atest BLASTBufferQueueTest Change-Id: I6139b01167ee9325fb4982cf4ece85ab37c9e8b5 --- libs/gui/BLASTBufferQueue.cpp | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 56591bdc63..3b2788a599 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "BLASTBufferQueue" #define ATRACE_TAG ATRACE_TAG_GRAPHICS +// #define LOG_NDEBUG 0 #include #include @@ -29,8 +30,20 @@ using namespace std::chrono_literals; +namespace { +inline const char* toString(bool b) { + return b ? "true" : "false"; +} +} // namespace + namespace android { +// Macros to include adapter info in log messages +#define BQA_LOGV(x, ...) \ + ALOGV("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) +#define BQA_LOGE(x, ...) \ + ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) + void BLASTBufferItemConsumer::onDisconnect() { Mutex::Autolock lock(mFrameEventHistoryMutex); mPreviouslyConnected = mCurrentlyConnected; @@ -93,9 +106,10 @@ void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* ne if (needsDisconnect != nullptr) *needsDisconnect = disconnect; } -BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, int height, - bool enableTripleBuffering) - : mSurfaceControl(surface), +BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp& surface, + int width, int height, bool enableTripleBuffering) + : mName(name), + mSurfaceControl(surface), mWidth(width), mHeight(height), mNextTransaction(nullptr) { @@ -110,9 +124,9 @@ BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, true); static int32_t id = 0; - auto name = std::string("BLAST Consumer") + std::to_string(id); + auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id); id++; - mBufferItemConsumer->setName(String8(name.c_str())); + mBufferItemConsumer->setName(String8(consumerName.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); mBufferItemConsumer->setBufferFreedListener(this); mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight); @@ -127,7 +141,7 @@ BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, mPendingReleaseItem.releaseFence = nullptr; } -void BLASTBufferQueue::update(const sp& surface, int width, int height) { +void BLASTBufferQueue::update(const sp& surface, uint32_t width, uint32_t height) { std::unique_lock _lock{mMutex}; mSurfaceControl = surface; @@ -153,6 +167,8 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const spsetTransformHint(mTransformHint); @@ -195,6 +211,8 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const spdup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); - t->setFrame(mSurfaceControl, {0, 0, mWidth, mHeight}); + t->setFrame(mSurfaceControl, + {0, 0, static_cast(mWidth), static_cast(mHeight)}); t->setCrop(mSurfaceControl, computeCrop(bufferItem)); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); @@ -255,6 +274,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { if (applyTransaction) { t->apply(); } + + BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 + " applyTransaction=%s mTimestamp=%" PRId64, + mWidth, mHeight, bufferItem.mFrameNumber, toString(applyTransaction), + bufferItem.mTimestamp); } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { @@ -268,7 +292,10 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; - if (mNextTransaction != nullptr) { + const bool nextTransactionSet = mNextTransaction != nullptr; + BQA_LOGV("onFrameAvailable nextTransactionSet=%s", toString(nextTransactionSet)); + + if (nextTransactionSet) { while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) { mCallbackCV.wait(_lock); } -- cgit v1.2.3-59-g8ed1b From 6b7c5c9425496be2166fccf2ab14e061b5a20fa3 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 29 Sep 2020 17:27:05 -0700 Subject: Pass in framenumbers if submitting buffers via BlastBufferQueue The framenumber generated by the graphics producer is forwarded to mimic BufferQueue behaviour. Test: atest SurfaceViewBufferTests Bug: 168504870 Change-Id: Ic652a585d10d7e14c9dd94afaabd0e485e209ede --- libs/gui/BLASTBufferQueue.cpp | 1 + libs/gui/LayerState.cpp | 12 +++++++++--- libs/gui/SurfaceComposerClient.cpp | 18 ++++++++++++++++-- libs/gui/include/gui/LayerState.h | 12 +++++++++--- libs/gui/include/gui/SurfaceComposerClient.h | 2 ++ services/surfaceflinger/BufferLayer.h | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 4 ++-- services/surfaceflinger/BufferStateLayer.h | 3 ++- services/surfaceflinger/Layer.cpp | 14 +++++++------- services/surfaceflinger/Layer.h | 6 ++++-- services/surfaceflinger/RefreshRateOverlay.cpp | 6 ++++-- services/surfaceflinger/SurfaceFlinger.cpp | 13 +++++++++---- services/surfaceflinger/SurfaceInterceptor.cpp | 4 ++-- 13 files changed, 68 insertions(+), 29 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 3b2788a599..ba72f9b45f 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -270,6 +270,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); t->setDesiredPresentTime(bufferItem.mTimestamp); + t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber); if (applyTransaction) { t->apply(); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 6ff4a3d4e2..150a36d745 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -45,7 +45,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.write, crop_legacy); SAFE_PARCEL(output.writeStrongBinder, barrierHandle_legacy); SAFE_PARCEL(output.writeStrongBinder, reparentHandle); - SAFE_PARCEL(output.writeUint64, frameNumber_legacy); + SAFE_PARCEL(output.writeUint64, barrierFrameNumber); SAFE_PARCEL(output.writeInt32, overrideScalingMode); SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(barrierGbp_legacy)); SAFE_PARCEL(output.writeStrongBinder, relativeLayerHandle); @@ -108,6 +108,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, frameRate); SAFE_PARCEL(output.writeByte, frameRateCompatibility); SAFE_PARCEL(output.writeUint32, fixedTransformHint); + SAFE_PARCEL(output.writeUint64, frameNumber); return NO_ERROR; } @@ -134,7 +135,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.read, crop_legacy); SAFE_PARCEL(input.readNullableStrongBinder, &barrierHandle_legacy); SAFE_PARCEL(input.readNullableStrongBinder, &reparentHandle); - SAFE_PARCEL(input.readUint64, &frameNumber_legacy); + SAFE_PARCEL(input.readUint64, &barrierFrameNumber); SAFE_PARCEL(input.readInt32, &overrideScalingMode); sp tmpBinder; @@ -213,6 +214,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readByte, &frameRateCompatibility); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); + SAFE_PARCEL(input.readUint64, &frameNumber); return NO_ERROR; } @@ -340,7 +342,7 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eDeferTransaction_legacy; barrierHandle_legacy = other.barrierHandle_legacy; barrierGbp_legacy = other.barrierGbp_legacy; - frameNumber_legacy = other.frameNumber_legacy; + barrierFrameNumber = other.barrierFrameNumber; } if (other.what & eOverrideScalingModeChanged) { what |= eOverrideScalingModeChanged; @@ -456,6 +458,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFixedTransformHintChanged; fixedTransformHint = other.fixedTransformHint; } + if (other.what & eFrameNumberChanged) { + what |= eFrameNumberChanged; + frameNumber = other.frameNumber; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIu64 " what=0x%" PRIu64, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8d2a7d9abc..f24dfca680 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1000,7 +1000,7 @@ SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const spwhat |= layer_state_t::eDeferTransaction_legacy; s->barrierHandle_legacy = handle; - s->frameNumber_legacy = frameNumber; + s->barrierFrameNumber = frameNumber; registerSurfaceControlForCallback(sc); return *this; @@ -1017,7 +1017,7 @@ SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const spwhat |= layer_state_t::eDeferTransaction_legacy; s->barrierGbp_legacy = barrierSurface->getIGraphicBufferProducer(); - s->frameNumber_legacy = frameNumber; + s->barrierFrameNumber = frameNumber; registerSurfaceControlForCallback(sc); return *this; @@ -1307,6 +1307,20 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyPr return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameNumber( + const sp& sc, uint64_t frameNumber) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eFrameNumberChanged; + s->frameNumber = frameNumber; + + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren( const sp& sc) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 7a9bb120cf..96ff61b67b 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -125,6 +125,7 @@ struct layer_state_t { eBackgroundBlurRadiusChanged = 0x80'00000000, eProducerDisconnect = 0x100'00000000, eFixedTransformHintChanged = 0x200'00000000, + eFrameNumberChanged = 0x400'00000000, }; layer_state_t() @@ -142,7 +143,7 @@ struct layer_state_t { crop_legacy(Rect::INVALID_RECT), cornerRadius(0.0f), backgroundBlurRadius(0), - frameNumber_legacy(0), + barrierFrameNumber(0), overrideScalingMode(-1), transform(0), transformToDisplayInverse(false), @@ -159,7 +160,8 @@ struct layer_state_t { frameRateSelectionPriority(-1), frameRate(0.0f), frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), - fixedTransformHint(ui::Transform::ROT_INVALID) { + fixedTransformHint(ui::Transform::ROT_INVALID), + frameNumber(0) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -195,7 +197,7 @@ struct layer_state_t { uint32_t backgroundBlurRadius; sp barrierHandle_legacy; sp reparentHandle; - uint64_t frameNumber_legacy; + uint64_t barrierFrameNumber; int32_t overrideScalingMode; sp barrierGbp_legacy; @@ -259,6 +261,10 @@ struct layer_state_t { // a buffer of a different size. -1 means the transform hint is not set, // otherwise the value will be a valid ui::Rotation. ui::Transform::RotationFlags fixedTransformHint; + + // Used by BlastBufferQueue to forward the framenumber generated by the + // graphics producer. + uint64_t frameNumber; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 6cac287d77..ed2bf07aa4 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -487,6 +487,8 @@ public: // ONLY FOR BLAST ADAPTER Transaction& notifyProducerDisconnect(const sp& sc); + // Set the framenumber generated by the graphics producer to mimic BufferQueue behaviour. + Transaction& setFrameNumber(const sp& sc, uint64_t frameNumber); // Detaches all child surfaces (and their children recursively) // from their SurfaceControl. diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 4cbfdffd8f..1cd753b65b 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -167,7 +167,7 @@ protected: void updateCloneBufferInfo() override; uint64_t mPreviousFrameNumber = 0; - virtual uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const; + uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const override; void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index ea1f78c048..9f99feeea1 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -258,12 +258,12 @@ bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t post bool BufferStateLayer::setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, - const client_cache_t& clientCacheId) { + const client_cache_t& clientCacheId, uint64_t frameNumber) { if (mCurrentState.buffer) { mReleasePreviousBuffer = true; } - mCurrentState.frameNumber++; + mCurrentState.frameNumber = frameNumber; mCurrentState.buffer = buffer; mCurrentState.clientCacheId = clientCacheId; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 81959ae2f3..c13f5e8252 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -70,7 +70,8 @@ public: bool setCrop(const Rect& crop) override; bool setFrame(const Rect& frame) override; bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, - nsecs_t desiredPresentTime, const client_cache_t& clientCacheId) override; + nsecs_t desiredPresentTime, const client_cache_t& clientCacheId, + uint64_t frameNumber) override; bool setAcquireFence(const sp& fence) override; bool setDataspace(ui::Dataspace dataspace) override; bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 85046a4194..58291d4ca0 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -800,10 +800,10 @@ void Layer::pushPendingState() { // to be applied as per normal (no synchronization). mCurrentState.barrierLayer_legacy = nullptr; } else { - auto syncPoint = std::make_shared(mCurrentState.frameNumber_legacy, this); + auto syncPoint = std::make_shared(mCurrentState.barrierFrameNumber, this); if (barrierLayer->addSyncPoint(syncPoint)) { std::stringstream ss; - ss << "Adding sync point " << mCurrentState.frameNumber_legacy; + ss << "Adding sync point " << mCurrentState.barrierFrameNumber; ATRACE_NAME(ss.str().c_str()); mRemoteSyncPoints.push_back(std::move(syncPoint)); } else { @@ -844,7 +844,7 @@ bool Layer::applyPendingStates(State* stateToCommit) { } if (mRemoteSyncPoints.front()->getFrameNumber() != - mPendingStates[0].frameNumber_legacy) { + mPendingStates[0].barrierFrameNumber) { ALOGE("[%s] Unexpected sync point frame number found", getDebugName()); // Signal our end of the sync point and then dispose of it @@ -1463,13 +1463,13 @@ void Layer::deferTransactionUntil_legacy(const sp& barrierLayer, uint64_t } mCurrentState.barrierLayer_legacy = barrierLayer; - mCurrentState.frameNumber_legacy = frameNumber; + mCurrentState.barrierFrameNumber = frameNumber; // We don't set eTransactionNeeded, because just receiving a deferral // request without any other state updates shouldn't actually induce a delay mCurrentState.modified = true; pushPendingState(); mCurrentState.barrierLayer_legacy = nullptr; - mCurrentState.frameNumber_legacy = 0; + mCurrentState.barrierFrameNumber = 0; mCurrentState.modified = false; } @@ -2234,7 +2234,7 @@ LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const DisplayDevice* display) { - ui::Transform transform = getTransform(); + const ui::Transform transform = getTransform(); if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { for (const auto& pendingState : mPendingStatesSnapshot) { @@ -2242,7 +2242,7 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, if (barrierLayer != nullptr) { BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer(); barrierLayerProto->set_id(barrierLayer->sequence); - barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy); + barrierLayerProto->set_frame_number(pendingState.barrierFrameNumber); } } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 88ece5058b..bdc4f848dc 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -187,7 +187,7 @@ public: // If set, defers this state update until the identified Layer // receives a frame with the given frameNumber wp barrierLayer_legacy; - uint64_t frameNumber_legacy; + uint64_t barrierFrameNumber; // the transparentRegion hint is a bit special, it's latched only // when we receive a buffer -- this is because it's "content" @@ -406,7 +406,7 @@ public: virtual bool setFrame(const Rect& /*frame*/) { return false; }; virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, - const client_cache_t& /*clientCacheId*/) { + const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */) { return false; }; virtual bool setAcquireFence(const sp& /*fence*/) { return false; }; @@ -510,6 +510,8 @@ public: virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; } + virtual uint64_t getHeadFrameNumber(nsecs_t /* expectedPresentTime */) const { return 0; } + /* * called after composition. * returns true if the layer latched a new buffer this frame. diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index d8477e7bc2..99d061daa3 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -241,7 +241,8 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) { mCurrentFps = refreshRate.getFps(); auto buffer = mBufferCache[*mCurrentFps][mFrame]; - mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}); + mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}, + mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */)); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } @@ -252,7 +253,8 @@ void RefreshRateOverlay::onInvalidate() { const auto& buffers = mBufferCache[*mCurrentFps]; mFrame = (mFrame + 1) % buffers.size(); auto buffer = buffers[mFrame]; - mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}); + mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}, + mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */)); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8ac459b05a..1aec382eba 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3681,13 +3681,13 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::eDeferTransaction_legacy) { if (s.barrierHandle_legacy != nullptr) { - layer->deferTransactionUntil_legacy(s.barrierHandle_legacy, s.frameNumber_legacy); + layer->deferTransactionUntil_legacy(s.barrierHandle_legacy, s.barrierFrameNumber); } else if (s.barrierGbp_legacy != nullptr) { const sp& gbp = s.barrierGbp_legacy; if (authenticateSurfaceTextureLocked(gbp)) { const auto& otherLayer = (static_cast(gbp.get()))->getLayer(); - layer->deferTransactionUntil_legacy(otherLayer, s.frameNumber_legacy); + layer->deferTransactionUntil_legacy(otherLayer, s.barrierFrameNumber); } else { ALOGE("Attempt to defer transaction to to an" " unrecognized GraphicBufferProducer"); @@ -3818,8 +3818,13 @@ uint32_t SurfaceFlinger::setClientStateLocked( buffer = s.buffer; } if (buffer) { - if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, - s.cachedBuffer)) { + const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged; + const uint64_t frameNumber = frameNumberChanged + ? s.frameNumber + : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1; + + if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, s.cachedBuffer, + frameNumber)) { flags |= eTraversalNeeded; } } diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 9d705e5999..ae7fcc3be1 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -148,7 +148,7 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment, if (layer->mCurrentState.barrierLayer_legacy != nullptr) { addDeferTransactionLocked(transaction, layerId, layer->mCurrentState.barrierLayer_legacy.promote(), - layer->mCurrentState.frameNumber_legacy); + layer->mCurrentState.barrierFrameNumber); } addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode()); addFlagsLocked(transaction, layerId, layer->mCurrentState.flags, @@ -483,7 +483,7 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, ALOGE("Attempt to defer transaction to to an unrecognized GraphicBufferProducer"); } } - addDeferTransactionLocked(transaction, layerId, otherLayer, state.frameNumber_legacy); + addDeferTransactionLocked(transaction, layerId, otherLayer, state.barrierFrameNumber); } if (state.what & layer_state_t::eOverrideScalingModeChanged) { addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode); -- cgit v1.2.3-59-g8ed1b From 670b3f73e9f97dc6031e71405e7dcb4da118ba37 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 29 Sep 2020 17:52:18 -0700 Subject: Add buffer rejection logic to BlastBufferQueue If the client sets the buffer scaling mode to freeze, then we want to reject any buffers that do not match default width and size of the buffer. Additionally, we add logic to wait for the first callback before acquiring a second buffer this is to ensure we will present the first buffer if multiple buffers are queued in succession. Test: atest SurfaceViewBufferTests Bug: 168504870 Change-Id: I987f8ce4047a6f7f52726cfd404fbe9d565f83a2 --- libs/gui/BLASTBufferQueue.cpp | 32 +++++++++++++++++++++++++++----- libs/gui/include/gui/BLASTBufferQueue.h | 3 +++ 2 files changed, 30 insertions(+), 5 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index ba72f9b45f..cce434a643 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -166,8 +166,8 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp& stats) { std::unique_lock _lock{mMutex}; ATRACE_CALL(); - BQA_LOGV("transactionCallback"); + mInitialCallbackReceived = true; if (!stats.empty()) { mTransformHint = stats[0].transformHint; @@ -185,7 +185,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const spreleaseBuffer(mPendingReleaseItem.item, @@ -198,7 +198,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const spgetWidth(), buffer->getHeight()); + mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); + return; + } + mNumAcquired++; mSubmitted.push(bufferItem); @@ -311,4 +324,13 @@ void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) mNextTransaction = t; } +bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) const { + if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { + // Only reject buffers if scaling mode is freeze. + return false; + } + + // reject buffers if the buffer size doesn't match. + return item.mGraphicBuffer->getWidth() != mWidth || item.mGraphicBuffer->getHeight() != mHeight; +} } // namespace android diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 35c656ab15..5b1a018ca9 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -94,6 +94,8 @@ private: void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex); Rect computeCrop(const BufferItem& item); + // Return true if we need to reject the buffer based on the scaling mode and the buffer size. + bool rejectBuffer(const BufferItem& item) const; std::string mName; sp mSurfaceControl; @@ -107,6 +109,7 @@ private: int32_t mNumFrameAvailable GUARDED_BY(mMutex); int32_t mNumAcquired GUARDED_BY(mMutex); + bool mInitialCallbackReceived GUARDED_BY(mMutex) = false; struct PendingReleaseItem { BufferItem item; sp releaseFence; -- cgit v1.2.3-59-g8ed1b From e1a4232e2a804c087f3498aad8328bcf140a54e3 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 2 Oct 2020 17:42:04 -0700 Subject: Handle buffer orientation when rejecting buffers via blast Bug: 168504870 Test: SurfaceViewBufferTests Test: go/wm-smoke with `adb shell device_config put window_manager_native_boot wm_use_blast_adapter true` Test: atest libgui_test Change-Id: Ib699b3d388b1b62346515d32bcde81bf03e6f5fd --- libs/gui/BLASTBufferQueue.cpp | 16 ++++++++++++---- libs/gui/tests/BLASTBufferQueue_test.cpp | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index cce434a643..87f797200c 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -18,7 +18,7 @@ #define LOG_TAG "BLASTBufferQueue" #define ATRACE_TAG ATRACE_TAG_GRAPHICS -// #define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #include #include @@ -252,8 +252,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } if (rejectBuffer(bufferItem)) { - BQA_LOGE("rejecting buffer: configured width=%d, height=%d, buffer{w=%d, h=%d}", mWidth, - mHeight, buffer->getWidth(), buffer->getHeight()); + BQA_LOGE("rejecting buffer:configured size=%dx%d, buffer{size=%dx%d transform=%d}", mWidth, + mHeight, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform); mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); return; } @@ -330,7 +330,15 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) const { return false; } + uint32_t bufWidth = item.mGraphicBuffer->getWidth(); + uint32_t bufHeight = item.mGraphicBuffer->getHeight(); + + // Take the buffer's orientation into account + if (item.mTransform & ui::Transform::ROT_90) { + std::swap(bufWidth, bufHeight); + } + // reject buffers if the buffer size doesn't match. - return item.mGraphicBuffer->getWidth() != mWidth || item.mGraphicBuffer->getHeight() != mHeight; + return bufWidth != mWidth || bufHeight != mHeight; } } // namespace android diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 35fff0a966..9299721be3 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -490,8 +490,8 @@ public: IGraphicBufferProducer::QueueBufferOutput qbOutput; IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, Rect(bufWidth, bufHeight), - NATIVE_WINDOW_SCALING_MODE_FREEZE, tr, - Fence::NO_FENCE); + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, + tr, Fence::NO_FENCE); igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); -- cgit v1.2.3-59-g8ed1b From 7eb670ae5357ea9f609e1630759a57ea31537271 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 15 Oct 2020 12:16:10 -0700 Subject: BlastBufferQueue: Add a function to flush the shadow queue If the function is called, the next queue buffer will wait until the the adapter processes the previously queued buffers. Test: enable blast and test split screen resize Change-Id: Ica9b3be9459dd174a7e80311abddb691976e83e3 --- libs/gui/BLASTBufferQueue.cpp | 11 +++++++---- libs/gui/include/gui/BLASTBufferQueue.h | 4 ++++ 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 87f797200c..c3f045e868 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -254,8 +254,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { if (rejectBuffer(bufferItem)) { BQA_LOGE("rejecting buffer:configured size=%dx%d, buffer{size=%dx%d transform=%d}", mWidth, mHeight, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform); - mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); - return; + // TODO(b/168917217) temporarily don't reject buffers until we can synchronize buffer size + // changes from ViewRootImpl. } mNumAcquired++; @@ -307,13 +307,16 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) { std::unique_lock _lock{mMutex}; const bool nextTransactionSet = mNextTransaction != nullptr; - BQA_LOGV("onFrameAvailable nextTransactionSet=%s", toString(nextTransactionSet)); + BQA_LOGV("onFrameAvailable nextTransactionSet=%s mFlushShadowQueue=%s", + toString(nextTransactionSet), toString(mFlushShadowQueue)); - if (nextTransactionSet) { + if (nextTransactionSet || mFlushShadowQueue) { while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) { + BQA_LOGV("waiting in onFrameAvailable..."); mCallbackCV.wait(_lock); } } + mFlushShadowQueue = false; // add to shadow queue mNumFrameAvailable++; processNextBufferLocked(true); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 5b1a018ca9..d1a0eece0d 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -82,6 +82,7 @@ public: void setNextTransaction(SurfaceComposerClient::Transaction *t); void update(const sp& surface, uint32_t width, uint32_t height); + void flushShadowQueue() { mFlushShadowQueue = true; } virtual ~BLASTBufferQueue() = default; @@ -130,6 +131,9 @@ private: sp mBufferItemConsumer; SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex); + // If set to true, the next queue buffer will wait until the shadow queue has been processed by + // the adapter. + bool mFlushShadowQueue = false; }; } // namespace android -- cgit v1.2.3-59-g8ed1b From bf25577c69c51ad2d1fc54532bb54510da5ddc7c Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 16 Oct 2020 10:54:41 -0700 Subject: BlastBufferQueue: Fix wait in onFrameAvailable Use the same logic in both onFrameAvailable and processNextBufferLocked to check if we can acquire a buffer. Otherwise, there is a chance we will not be waiting long enough in onFrameAvailable. Also add error logs if we return unexpectedly when trying to acquire a buffer. Test: go/wm-smoke with blast enabled Test: atest SurfaceViewBufferTests Change-Id: I2f8afa2fc2efb0371ccc86b422524e474e3f6170 Change-Id: Ibf2733725f7a4334eff38b516f0f5cec87dfd493 --- libs/gui/BLASTBufferQueue.cpp | 20 ++++++++++++++------ libs/gui/include/gui/BLASTBufferQueue.h | 5 +++-- 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index c3f045e868..0b942199c3 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -213,12 +213,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { ATRACE_CALL(); BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction)); - // Wait to acquire a buffer if there are no frames available or we have acquired the maximum + // Wait to acquire a buffer if there are no frames available or we have acquired the max // number of buffers. - // As a special case, we wait for the first callback before acquiring the second buffer so we - // can ensure the first buffer is presented if multiple buffers are queued in succession. - if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 || - (!mInitialCallbackReceived && mNumAcquired == 1)) { + if (mNumFrameAvailable == 0 || maxBuffersAcquired()) { BQA_LOGV("processNextBufferLocked waiting for frame available or callback"); return; } @@ -241,6 +238,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, -1, false); if (status != OK) { + BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str()); return; } auto buffer = bufferItem.mGraphicBuffer; @@ -248,6 +246,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { if (buffer == nullptr) { mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); + BQA_LOGE("Buffer was empty"); return; } @@ -311,7 +310,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) { toString(nextTransactionSet), toString(mFlushShadowQueue)); if (nextTransactionSet || mFlushShadowQueue) { - while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) { + while (mNumFrameAvailable > 0 || maxBuffersAcquired()) { BQA_LOGV("waiting in onFrameAvailable..."); mCallbackCV.wait(_lock); } @@ -344,4 +343,13 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) const { // reject buffers if the buffer size doesn't match. return bufWidth != mWidth || bufHeight != mHeight; } + +// Check if we have acquired the maximum number of buffers. +// As a special case, we wait for the first callback before acquiring the second buffer so we +// can ensure the first buffer is presented if multiple buffers are queued in succession. +bool BLASTBufferQueue::maxBuffersAcquired() const { + return mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 || + (!mInitialCallbackReceived && mNumAcquired == 1); +} + } // namespace android diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index d1a0eece0d..634a7aa058 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -94,9 +94,10 @@ private: BLASTBufferQueue(const BLASTBufferQueue& rhs); void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex); - Rect computeCrop(const BufferItem& item); + Rect computeCrop(const BufferItem& item) REQUIRES(mMutex); // Return true if we need to reject the buffer based on the scaling mode and the buffer size. - bool rejectBuffer(const BufferItem& item) const; + bool rejectBuffer(const BufferItem& item) const REQUIRES(mMutex); + bool maxBuffersAcquired() const REQUIRES(mMutex); std::string mName; sp mSurfaceControl; -- cgit v1.2.3-59-g8ed1b From 05086b2572be79b7d86033e77e5ce117ce6dbd08 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 13 Oct 2020 18:22:51 -0700 Subject: BLASTBufferQueue: Handler allocateBuffers on thread. allocateBuffers is a one-way method in the IGBP interface. In the non-BLAST case the IGBP is hosted in SF and allocateBuffers is therefore a one-way binder call executed asynchronously on an SF binder thread. In the BLAST case the IGBP will be in process and so allocateBuffers will execute in a blocking fashion. Callers don't like being blocked when they weren't before, so we want to emulate this behavior in BLASTBufferQueue. We introduce a Surface subclass (BBQSurface) which overrides allocateBuffers and pushes the operation to a new thread. Bug: 168504871 Test: asit/perf/appstartup_all_apps_cyclic_dropcache_test . Enabling BLAST triggers regression, but applying this removes the regression. Change-Id: If6bb411e021ba2e0886dfe96b1a1a1489e3627b8 --- libs/gui/BLASTBufferQueue.cpp | 23 +++++++++++++++++++++++ libs/gui/include/gui/BLASTBufferQueue.h | 1 + libs/gui/include/gui/Surface.h | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 0b942199c3..82c963be7b 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -352,4 +353,26 @@ bool BLASTBufferQueue::maxBuffersAcquired() const { (!mInitialCallbackReceived && mNumAcquired == 1); } +class BBQSurface : public Surface { +public: + BBQSurface(const sp& igbp, bool controlledByApp) : + Surface(igbp, controlledByApp) { + } + void allocateBuffers() override { + uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; + uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; + auto gbp = getIGraphicBufferProducer(); + std::thread ([reqWidth, reqHeight, gbp=getIGraphicBufferProducer(), + reqFormat=mReqFormat, reqUsage=mReqUsage] () { + gbp->allocateBuffers(reqWidth, reqHeight, + reqFormat, reqUsage); + + }).detach(); + } +}; + +sp BLASTBufferQueue::getSurface() { + return new BBQSurface(mProducer, true); +} + } // namespace android diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 634a7aa058..d9644d10ab 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -72,6 +72,7 @@ public: sp getIGraphicBufferProducer() const { return mProducer; } + sp getSurface(); void onBufferFreed(const wp&/* graphicBuffer*/) override { /* TODO */ } void onFrameReplaced(const BufferItem& item) override {onFrameAvailable(item);} diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index a68f2e7ce8..800b8efd24 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -120,7 +120,7 @@ public: * delay during dequeueBuffer. If there are already the maximum number of * buffers allocated, this function has no effect. */ - void allocateBuffers(); + virtual void allocateBuffers(); /* Sets the generation number on the IGraphicBufferProducer and updates the * generation number on any buffers attached to the Surface after this call. -- cgit v1.2.3-59-g8ed1b From 9c006e030fed1d41891d5f096e62696082560f89 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 14 Oct 2020 13:41:57 -0700 Subject: BLASTBufferQueue: Support setFrameRate Surface::setFrameRate calls through to SurfaceFlinger using the IGBP as a token. But of course in the case of BBQ we have no IGBP on the server side, and this will produce errors. To fix this we continue overriding Surface methods in the BBQSurface , and forward through to the SurfaceControl variants of the function. Bug: 170890018 Test: Existing tests pass Change-Id: Ia2f5584a1fa871cff9511ddba155e6c957cefc3f --- libs/gui/BLASTBufferQueue.cpp | 28 +++++++++++++++++++++++++--- libs/gui/include/gui/BLASTBufferQueue.h | 2 ++ libs/gui/include/gui/Surface.h | 2 +- 3 files changed, 28 insertions(+), 4 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 82c963be7b..6ae6df196d 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -354,10 +354,15 @@ bool BLASTBufferQueue::maxBuffersAcquired() const { } class BBQSurface : public Surface { +private: + sp mBbq; public: - BBQSurface(const sp& igbp, bool controlledByApp) : - Surface(igbp, controlledByApp) { + BBQSurface(const sp& igbp, bool controlledByApp, + const sp& bbq) : + Surface(igbp, controlledByApp), + mBbq(bbq) { } + void allocateBuffers() override { uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; @@ -369,10 +374,27 @@ public: }).detach(); } + + status_t setFrameRate(float frameRate, int8_t compatibility) override { + if (!ValidateFrameRate(frameRate, compatibility, "BBQSurface::setFrameRate")) { + return BAD_VALUE; + } + return mBbq->setFrameRate(frameRate, compatibility); + } }; +// TODO: Can we coalesce this with frame updates? Need to confirm +// no timing issues. +status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility) { + std::unique_lock _lock{mMutex}; + SurfaceComposerClient::Transaction t; + + return t.setFrameRate(mSurfaceControl, frameRate, compatibility) + .apply(); +} + sp BLASTBufferQueue::getSurface() { - return new BBQSurface(mProducer, true); + return new BBQSurface(mProducer, true, this); } } // namespace android diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index d9644d10ab..d477bea3ac 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -85,6 +85,8 @@ public: void update(const sp& surface, uint32_t width, uint32_t height); void flushShadowQueue() { mFlushShadowQueue = true; } + status_t setFrameRate(float frameRate, int8_t compatibility); + virtual ~BLASTBufferQueue() = default; private: diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 800b8efd24..6a1eaa2075 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -179,7 +179,7 @@ public: status_t getUniqueId(uint64_t* outId) const; status_t getConsumerUsage(uint64_t* outUsage) const; - status_t setFrameRate(float frameRate, int8_t compatibility); + virtual status_t setFrameRate(float frameRate, int8_t compatibility); protected: virtual ~Surface(); -- cgit v1.2.3-59-g8ed1b From 9b611b7f4d1a8b8b5e519007b5d841ace3ed696c Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 19 Oct 2020 12:00:23 -0700 Subject: BLASTBufferQueue: Support setFrameTimelineVsync Surface::setFrameTimelineVsync calls through to SurfaceFlinger using the IGBP as a token. But of course in the case of BBQ we have no IGBP on the server side, and this will produce errors. To fix this we continue overriding Surface methods in the BBQSurface , and forward through to the SurfaceControl variants of the function. Unlike the previous CL for setFrameRate, this is a currently un-released API, and so I'd also like to investigate as a follow-up...can we go SurfaceControl path only? Bug: 170890018 Test: Existing tests pass Change-Id: I5316c38f462c3808d5769ede6666594b911c8242 --- libs/gui/BLASTBufferQueue.cpp | 12 ++++++++++++ libs/gui/LayerState.cpp | 2 ++ libs/gui/Surface.cpp | 7 ++++++- libs/gui/SurfaceComposerClient.cpp | 13 +++++++++++++ libs/gui/include/gui/BLASTBufferQueue.h | 1 + libs/gui/include/gui/LayerState.h | 3 +++ libs/gui/include/gui/Surface.h | 1 + libs/gui/include/gui/SurfaceComposerClient.h | 3 +++ services/surfaceflinger/SurfaceFlinger.cpp | 9 +++++++-- 9 files changed, 48 insertions(+), 3 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 6ae6df196d..c8e1f3d1a0 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -381,6 +381,10 @@ public: } return mBbq->setFrameRate(frameRate, compatibility); } + + status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override { + return mBbq->setFrameTimelineVsync(frameTimelineVsyncId); + } }; // TODO: Can we coalesce this with frame updates? Need to confirm @@ -393,6 +397,14 @@ status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility) { .apply(); } +status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { + std::unique_lock _lock{mMutex}; + SurfaceComposerClient::Transaction t; + + return t.setFrameTimelineVsync(mSurfaceControl, frameTimelineVsyncId) + .apply(); +} + sp BLASTBufferQueue::getSurface() { return new BBQSurface(mProducer, true, this); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 2e4d279a5b..433312639d 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -146,6 +146,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeByte, frameRateCompatibility); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); + SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId); return NO_ERROR; } @@ -250,6 +251,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); + SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId); return NO_ERROR; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 9ce8442579..167bef1449 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1521,7 +1521,7 @@ int Surface::dispatchSetFrameTimelineVsync(va_list args) { auto frameTimelineVsyncId = static_cast(va_arg(args, int64_t)); ALOGV("Surface::dispatchSetFrameTimelineVsync"); - return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, frameTimelineVsyncId); + return setFrameTimelineVsync(frameTimelineVsyncId); } bool Surface::transformToDisplayInverse() { @@ -2288,4 +2288,9 @@ status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility); } +status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { + return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, + frameTimelineVsyncId); +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 105969bd42..791750fd37 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1510,6 +1510,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync( + const sp& sc, int64_t frameTimelineVsyncId) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eFrameTimelineVsyncChanged; + s->frameTimelineVsyncId = frameTimelineVsyncId; + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index d477bea3ac..1410b12e12 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -86,6 +86,7 @@ public: void flushShadowQueue() { mFlushShadowQueue = true; } status_t setFrameRate(float frameRate, int8_t compatibility); + status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); virtual ~BLASTBufferQueue() = default; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 5942fd03af..ff3a87d98f 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -127,6 +127,7 @@ struct layer_state_t { eProducerDisconnect = 0x100'00000000, eFixedTransformHintChanged = 0x200'00000000, eFrameNumberChanged = 0x400'00000000, + eFrameTimelineVsyncChanged = 0x800'00000000, }; layer_state_t(); @@ -227,6 +228,8 @@ struct layer_state_t { // Used by BlastBufferQueue to forward the framenumber generated by the // graphics producer. uint64_t frameNumber; + + int64_t frameTimelineVsyncId; }; struct ComposerState { diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 6a1eaa2075..c2b5ec4c4d 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -180,6 +180,7 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const; virtual status_t setFrameRate(float frameRate, int8_t compatibility); + virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); protected: virtual ~Surface(); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index ce1a0a5f30..138f82cd21 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -532,6 +532,9 @@ public: // Sets the frame timeline vsync id received from choreographer that corresponds // to the transaction. Transaction& setFrameTimelineVsync(int64_t frameTimelineVsyncId); + // Variant that only applies to a specific SurfaceControl. + Transaction& setFrameTimelineVsync(const sp& sc, + int64_t frameTimelineVsyncId); status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 964bd015f2..b6ed68fa49 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3770,6 +3770,13 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } + if (what & layer_state_t::eFrameTimelineVsyncChanged) { + layer->setFrameTimelineVsyncForTransaction(s.frameTimelineVsyncId, postTime); + } else { + // TODO (b/171252403) We are calling this too much, potentially triggering + // unnecessary work + layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime); + } if (what & layer_state_t::eFixedTransformHintChanged) { if (layer->setFixedTransformHint(s.fixedTransformHint)) { flags |= eTraversalNeeded | eTransformHintUpdateNeeded; @@ -3829,8 +3836,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } - layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime); - if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; // Do not put anything that updates layer state or modifies flags after // setTransactionCompletedListener -- cgit v1.2.3-59-g8ed1b From aef1de99600e7a68101227ab901526f2334dfdfb Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 22 Oct 2020 12:15:53 -0700 Subject: BlastBufferQueue: Handle onFrameReplaced If a buffer is replaced, we should not call onFrameAvailable which will incorrectly increase the number of buffers BBQ expects to acquire. Test: manual tests, atest CtsWindowManagerDeviceTestCases, check that we are not stuck in onFrameAvailable Change-Id: Ib6fc3b11905fbf24c2528e14b1fb2409d1f43ff6 --- libs/gui/BLASTBufferQueue.cpp | 11 ++++++++--- libs/gui/include/gui/BLASTBufferQueue.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index c8e1f3d1a0..0ebf8527cc 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -302,13 +302,13 @@ Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { return item.mCrop; } -void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) { +void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; const bool nextTransactionSet = mNextTransaction != nullptr; - BQA_LOGV("onFrameAvailable nextTransactionSet=%s mFlushShadowQueue=%s", - toString(nextTransactionSet), toString(mFlushShadowQueue)); + BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s mFlushShadowQueue=%s", + item.mFrameNumber, toString(nextTransactionSet), toString(mFlushShadowQueue)); if (nextTransactionSet || mFlushShadowQueue) { while (mNumFrameAvailable > 0 || maxBuffersAcquired()) { @@ -322,6 +322,11 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) { processNextBufferLocked(true); } +void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) { + BQA_LOGV("onFrameReplaced framenumber=%" PRIu64, item.mFrameNumber); + // Do nothing since we are not storing unacquired buffer items locally. +} + void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) { std::lock_guard _lock{mMutex}; mNextTransaction = t; diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 1410b12e12..51ba6b1271 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -75,7 +75,7 @@ public: sp getSurface(); void onBufferFreed(const wp&/* graphicBuffer*/) override { /* TODO */ } - void onFrameReplaced(const BufferItem& item) override {onFrameAvailable(item);} + void onFrameReplaced(const BufferItem& item) override; void onFrameAvailable(const BufferItem& item) override; void transactionCallback(nsecs_t latchTime, const sp& presentFence, -- cgit v1.2.3-59-g8ed1b From 992496bd2e1af9c93bce33216034dd5419acb444 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 22 Oct 2020 17:27:21 -0700 Subject: Allow creating child surfaces from BlastBufferQueue App such as Chrome create child surfaces and parent them to surfaces provided by SurfaceView. When we enable the blast adapter for SurfaceView, the IGBP returned to the app is created in the client and SurfaceFlinger does not know about it. When the app creates a child surface and provides the IGBP as the parent surface identifier, SF fails to validate the IGBP and the surface is not created. This can be avoid if the client creates the child surface from the SV SurfaceControl but we still need to support existing APIs. To fix this, when we create a Surface from the adapter, pass in the handle of the Blast SurfaceControl. When calling ASurfaceControl_createFromWindow, use this handle to identify the parent. Bug: 168917217 Test: adb shell settings put global use_blast_adapter_sv 1 & launch chrome Change-Id: I404bbd29b63044260f5403aae60f039a36eeea8b --- libs/gui/BLASTBufferQueue.cpp | 17 ++++++++++------- libs/gui/Surface.cpp | 4 +++- libs/gui/SurfaceComposerClient.cpp | 12 ++++-------- libs/gui/include/gui/BLASTBufferQueue.h | 2 +- libs/gui/include/gui/Surface.h | 18 +++++++++++++++--- libs/gui/include/gui/SurfaceComposerClient.h | 20 ++++++++++---------- libs/gui/include/gui/view/Surface.h | 2 ++ libs/gui/view/Surface.cpp | 5 ++++- services/surfaceflinger/tests/EffectLayer_test.cpp | 6 +++--- .../surfaceflinger/tests/InvalidHandles_test.cpp | 2 +- services/surfaceflinger/tests/LayerTransactionTest.h | 5 +++-- services/surfaceflinger/tests/LayerUpdate_test.cpp | 5 +++-- .../surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp | 8 ++++---- 13 files changed, 63 insertions(+), 43 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index c8e1f3d1a0..0e47676dd6 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -357,11 +357,9 @@ class BBQSurface : public Surface { private: sp mBbq; public: - BBQSurface(const sp& igbp, bool controlledByApp, - const sp& bbq) : - Surface(igbp, controlledByApp), - mBbq(bbq) { - } + BBQSurface(const sp& igbp, bool controlledByApp, + const sp& scHandle, const sp& bbq) + : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {} void allocateBuffers() override { uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; @@ -405,8 +403,13 @@ status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { .apply(); } -sp BLASTBufferQueue::getSurface() { - return new BBQSurface(mProducer, true, this); +sp BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) { + std::unique_lock _lock{mMutex}; + sp scHandle = nullptr; + if (includeSurfaceControlHandle && mSurfaceControl) { + scHandle = mSurfaceControl->getHandle(); + } + return new BBQSurface(mProducer, true, scHandle, this); } } // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 167bef1449..c1155ab73a 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -63,7 +63,8 @@ bool isInterceptorRegistrationOp(int op) { } // namespace -Surface::Surface(const sp& bufferProducer, bool controlledByApp) +Surface::Surface(const sp& bufferProducer, bool controlledByApp, + const sp& surfaceControlHandle) : mGraphicBufferProducer(bufferProducer), mCrop(Rect::EMPTY_RECT), mBufferAge(0), @@ -111,6 +112,7 @@ Surface::Surface(const sp& bufferProducer, bool controll mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; mMaxBufferCount = NUM_BUFFER_SLOTS; + mSurfaceControlHandle = surfaceControlHandle; } Surface::~Surface() { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 60966e1915..4b7d4b1a5d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1628,11 +1628,11 @@ void SurfaceComposerClient::dispose() { sp SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, - SurfaceControl* parent, + const sp& parentHandle, LayerMetadata metadata, uint32_t* outTransformHint) { sp s; - createSurfaceChecked(name, w, h, format, &s, flags, parent, std::move(metadata), + createSurfaceChecked(name, w, h, format, &s, flags, parentHandle, std::move(metadata), outTransformHint); return s; } @@ -1669,20 +1669,16 @@ sp SurfaceComposerClient::createWithSurfaceParent(const String8& status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h, PixelFormat format, sp* outSurface, uint32_t flags, - SurfaceControl* parent, LayerMetadata metadata, + const sp& parentHandle, + LayerMetadata metadata, uint32_t* outTransformHint) { sp sur; status_t err = mStatus; if (mStatus == NO_ERROR) { sp handle; - sp parentHandle; sp gbp; - if (parent != nullptr) { - parentHandle = parent->getHandle(); - } - uint32_t transformHint = 0; int32_t id = -1; err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata), diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 1410b12e12..0d457bfe4a 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -72,7 +72,7 @@ public: sp getIGraphicBufferProducer() const { return mProducer; } - sp getSurface(); + sp getSurface(bool includeSurfaceControlHandle); void onBufferFreed(const wp&/* graphicBuffer*/) override { /* TODO */ } void onFrameReplaced(const BufferItem& item) override {onFrameAvailable(item);} diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index c2b5ec4c4d..4aa076e7b2 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -68,7 +68,6 @@ class Surface : public ANativeObjectBase { public: - /* * creates a Surface from the given IGraphicBufferProducer (which concrete * implementation is a BufferQueue). @@ -83,9 +82,15 @@ public: * * the controlledByApp flag indicates that this Surface (producer) is * controlled by the application. This flag is used at connect time. + * + * Pass in the SurfaceControlHandle to store a weak reference to the layer + * that the Surface was created from. This handle can be used to create a + * child surface without using the IGBP to identify the layer. This is used + * for surfaces created by the BlastBufferQueue whose IGBP is created on the + * client and cannot be verified in SF. */ - explicit Surface(const sp& bufferProducer, - bool controlledByApp = false); + explicit Surface(const sp& bufferProducer, bool controlledByApp = false, + const sp& surfaceControlHandle = nullptr); /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this * Surface was created with. Usually it's an error to use the @@ -93,6 +98,8 @@ public: */ sp getIGraphicBufferProducer() const; + sp getSurfaceControlHandle() const { return mSurfaceControlHandle; } + /* convenience function to check that the given surface is non NULL as * well as its IGraphicBufferProducer */ static bool isValid(const sp& surface) { @@ -541,6 +548,11 @@ protected: bool mEnableFrameTimestamps = false; std::unique_ptr mFrameEventHistory; + // Reference to the SurfaceFlinger layer that was used to create this + // surface. This is only populated when the Surface is created from + // a BlastBufferQueue. + sp mSurfaceControlHandle; + bool mReportRemovedBuffers = false; std::vector> mRemovedBuffers; int mMaxBufferCount; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 138f82cd21..fb01dc4ba4 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -253,13 +253,13 @@ public: static sp getDefault(); //! Create a surface - sp createSurface(const String8& name, // name of the surface - uint32_t w, // width in pixel - uint32_t h, // height in pixel - PixelFormat format, // pixel-format desired - uint32_t flags = 0, // usage flags - SurfaceControl* parent = nullptr, // parent - LayerMetadata metadata = LayerMetadata(), // metadata + sp createSurface(const String8& name, // name of the surface + uint32_t w, // width in pixel + uint32_t h, // height in pixel + PixelFormat format, // pixel-format desired + uint32_t flags = 0, // usage flags + const sp& parentHandle = nullptr, // parentHandle + LayerMetadata metadata = LayerMetadata(), // metadata uint32_t* outTransformHint = nullptr); status_t createSurfaceChecked(const String8& name, // name of the surface @@ -267,9 +267,9 @@ public: uint32_t h, // height in pixel PixelFormat format, // pixel-format desired sp* outSurface, - uint32_t flags = 0, // usage flags - SurfaceControl* parent = nullptr, // parent - LayerMetadata metadata = LayerMetadata(), // metadata + uint32_t flags = 0, // usage flags + const sp& parentHandle = nullptr, // parentHandle + LayerMetadata metadata = LayerMetadata(), // metadata uint32_t* outTransformHint = nullptr); //! Create a surface diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h index cc64fd45dd..f7dcbc698d 100644 --- a/libs/gui/include/gui/view/Surface.h +++ b/libs/gui/include/gui/view/Surface.h @@ -21,6 +21,7 @@ #include #include +#include #include namespace android { @@ -43,6 +44,7 @@ class Surface : public Parcelable { String16 name; sp graphicBufferProducer; + sp surfaceControlHandle; virtual status_t writeToParcel(Parcel* parcel) const override; virtual status_t readFromParcel(const Parcel* parcel) override; diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp index d64dfd55be..3e49de6dc8 100644 --- a/libs/gui/view/Surface.cpp +++ b/libs/gui/view/Surface.cpp @@ -45,7 +45,9 @@ status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const { if (res != OK) return res; } - return IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel); + res = IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel); + if (res != OK) return res; + return parcel->writeStrongBinder(surfaceControlHandle); } status_t Surface::readFromParcel(const Parcel* parcel) { @@ -68,6 +70,7 @@ status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) { } graphicBufferProducer = IGraphicBufferProducer::createFromParcel(parcel); + surfaceControlHandle = parcel->readStrongBinder(); return OK; } diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp index 3dca3916e4..fafb49efba 100644 --- a/services/surfaceflinger/tests/EffectLayer_test.cpp +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -51,7 +51,7 @@ TEST_F(EffectLayerTest, DefaultEffectLayerHasSolidBlackFill) { sp effectLayer = mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect, - mParentLayer.get()); + mParentLayer->getHandle()); EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl"; asTransaction([&](Transaction& t) { @@ -72,7 +72,7 @@ TEST_F(EffectLayerTest, EffectLayerWithNoFill) { PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect | ISurfaceComposerClient::eNoColorFill, - mParentLayer.get()); + mParentLayer->getHandle()); EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl"; asTransaction([&](Transaction& t) { @@ -93,7 +93,7 @@ TEST_F(EffectLayerTest, EffectLayerCanSetColor) { PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect | ISurfaceComposerClient::eNoColorFill, - mParentLayer.get()); + mParentLayer->getHandle()); EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl"; asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp index cfec0d2b51..152d2d26f4 100644 --- a/services/surfaceflinger/tests/InvalidHandles_test.cpp +++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp @@ -56,7 +56,7 @@ TEST_F(InvalidHandleTest, createSurfaceInvalidHandle) { auto notSc = makeNotSurfaceControl(); ASSERT_EQ(nullptr, mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0, - notSc.get()) + notSc->getHandle()) .get()); } diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index d4e952aa21..25d3211f6b 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -75,8 +75,9 @@ protected: PixelFormat format, uint32_t flags, SurfaceControl* parent = nullptr, uint32_t* outTransformHint = nullptr) { - auto layer = client->createSurface(String8(name), width, height, format, flags, parent, - LayerMetadata(), outTransformHint); + sp parentHandle = (parent) ? parent->getHandle() : nullptr; + auto layer = client->createSurface(String8(name), width, height, format, flags, + parentHandle, LayerMetadata(), outTransformHint); EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl"; return layer; } diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index 0cafd001ff..29473f20a4 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -1028,12 +1028,13 @@ TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) { TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) { sp boundlessLayer = mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888, - 0 /* flags */, mFGSurfaceControl.get()); + 0 /* flags */, mFGSurfaceControl->getHandle()); ASSERT_TRUE(boundlessLayer != nullptr); ASSERT_TRUE(boundlessLayer->isValid()); sp colorLayer = mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, + boundlessLayer->getHandle()); ASSERT_TRUE(colorLayer != nullptr); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index 1606f2241e..6c654c07e3 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -1469,7 +1469,7 @@ protected: Base::SetUp(); mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, - Base::mFGSurfaceControl.get()); + Base::mFGSurfaceControl->getHandle()); fillSurfaceRGBA8(mChild, LIGHT_GRAY); Base::sFakeComposer->runVSyncAndWait(); @@ -1653,7 +1653,7 @@ protected: sp childNewClient = newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, - Base::mFGSurfaceControl.get()); + Base::mFGSurfaceControl->getHandle()); ASSERT_TRUE(childNewClient != nullptr); ASSERT_TRUE(childNewClient->isValid()); fillSurfaceRGBA8(childNewClient, LIGHT_GRAY); @@ -1732,7 +1732,7 @@ protected: mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden, - Base::mFGSurfaceControl.get()); + Base::mFGSurfaceControl->getHandle()); // Show the child layer in a deferred transaction { @@ -1819,7 +1819,7 @@ protected: Base::mComposerClient->createSurface(String8("Child surface"), 0, 0, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect, - Base::mFGSurfaceControl.get()); + Base::mFGSurfaceControl->getHandle()); { TransactionScope ts(*Base::sFakeComposer); ts.setColor(Base::mChild, -- cgit v1.2.3-59-g8ed1b From fbcbb4c0258b0e05b310e35d76310480e4933d63 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 2 Nov 2020 14:14:34 -0800 Subject: BLASTBufferQueue: Hold sp in transactionCallbackThunk When expecting a callback we perform an incStrong on the BBQ in order to ensure the lifetime extends at least as long as the callback. We remove this reference in BBQ::transactionCallback. The current implementation however has a bug, notice the scope of the lock around mMutex in transactionCallback extends to the whole function. This means after calling decStrong, we may then attempt to unlock the mutex when exiting the function, but we've already destroyed the object. We could move the decStrong to transactionCallbackThunk but the most clear/least brittle fix seems to simply be to hold a sp from transactionCallbackThunk and prevent the object from being destroyed while in a member method. Bug: 168506246 Test: Existing tests pass Change-Id: I905469f58dc7a2e2831b3b29726a42abd394f819 --- libs/gui/BLASTBufferQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index ff64d65312..678613b1ff 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -159,7 +159,7 @@ static void transactionCallbackThunk(void* context, nsecs_t latchTime, if (context == nullptr) { return; } - BLASTBufferQueue* bq = static_cast(context); + sp bq = static_cast(context); bq->transactionCallback(latchTime, presentFence, stats); } -- cgit v1.2.3-59-g8ed1b From 4608442db90c07dccc833dbdf1cea78f57c7b96d Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Tue, 13 Oct 2020 12:33:42 +0200 Subject: Add shouldBeSeamless to setFrameRate This CL adds a new parameter shouldBeSeamless to the existing setFrameRate APIs. This parameter indicates whether the desired refresh rate should be achieved only seamlessly or also switches with visual interruptions for the user are allowed. The default value of the new parameter is "true". Test: atest RefreshRateConfigsTest Test: atest SetFrameRateTest Test: atest libsurfaceflinger_unittest Test: atest libgui_test Bug: 161776961 Change-Id: I0df16e09f77c8c198fd3733fb581a2aaadfed685 --- include/android/surface_control.h | 38 +++++-- libs/gui/BLASTBufferQueue.cpp | 10 +- libs/gui/ISurfaceComposer.cpp | 16 ++- libs/gui/LayerState.cpp | 4 + libs/gui/Surface.cpp | 8 +- libs/gui/SurfaceComposerClient.cpp | 4 +- libs/gui/include/gui/BLASTBufferQueue.h | 2 +- libs/gui/include/gui/ISurfaceComposer.h | 2 +- libs/gui/include/gui/LayerState.h | 1 + libs/gui/include/gui/Surface.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 2 +- libs/gui/tests/Surface_test.cpp | 2 +- libs/nativewindow/ANativeWindow.cpp | 13 ++- libs/nativewindow/include/android/native_window.h | 51 ++++++--- libs/nativewindow/include/system/window.h | 4 +- libs/nativewindow/libnativewindow.map.txt | 1 + services/surfaceflinger/Layer.cpp | 11 +- services/surfaceflinger/Layer.h | 11 +- services/surfaceflinger/Scheduler/LayerHistory.cpp | 21 +++- .../surfaceflinger/Scheduler/LayerHistoryV2.cpp | 11 +- services/surfaceflinger/Scheduler/LayerInfoV2.cpp | 4 +- services/surfaceflinger/Scheduler/LayerInfoV2.h | 19 ++-- .../Scheduler/RefreshRateConfigs.cpp | 65 ++++++++++- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 4 + services/surfaceflinger/Scheduler/StrongTyping.h | 4 + services/surfaceflinger/SurfaceFlinger.cpp | 9 +- services/surfaceflinger/SurfaceFlinger.h | 2 +- .../surfaceflinger/tests/LayerTransactionTest.h | 4 +- .../surfaceflinger/tests/SetFrameRate_test.cpp | 23 ++-- .../tests/TransactionTestHarnesses.h | 8 +- .../tests/unittests/LayerHistoryTestV2.cpp | 2 +- .../tests/unittests/RefreshRateConfigsTest.cpp | 122 ++++++++++++++++++++- .../tests/unittests/RefreshRateStatsTest.cpp | 46 ++++---- 33 files changed, 402 insertions(+), 124 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/include/android/surface_control.h b/include/android/surface_control.h index cbcf6ec5c0..9758c9c8c3 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -410,7 +410,23 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio #if __ANDROID_API__ >= 30 /** - * Sets the intended frame rate for |surface_control|. + * Same as ASurfaceTransaction_setFrameRateWithSeamlessness(transaction, surface_control, + * frameRate, compatibility, true). + * + * See ASurfaceTransaction_setFrameRateWithSeamlessness(). + * + * Available since API level 30. + */ +void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, + ASurfaceControl* surface_control, float frameRate, + int8_t compatibility) __INTRODUCED_IN(30); + +#endif // __ANDROID_API__ >= 30 + +#if __ANDROID_API__ >= 31 + +/** + * Sets the intended frame rate for \a surface_control. * * On devices that are capable of running the display at different refresh rates, the system may * choose a display refresh rate to better match this surface's frame rate. Usage of this API won't @@ -419,24 +435,30 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio * callback timings, and changes to the time interval at which the system releases buffers back to * the application. * - * |frameRate| is the intended frame rate of this surface, in frames per second. 0 is a special + * \param frameRate is the intended frame rate of this surface, in frames per second. 0 is a special * value that indicates the app will accept the system's choice for the display frame rate, which is * the default behavior if this function isn't called. The frameRate param does not need to * be a valid refresh rate for this device's display - e.g., it's fine to pass 30fps to a device * that can only run the display at 60fps. * - * |compatibility| The frame rate compatibility of this surface. The compatibility value may + * \param compatibility The frame rate compatibility of this surface. The compatibility value may * influence the system's choice of display frame rate. To specify a compatibility use the * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum. * - * Available since API level 30. + * \param shouldBeSeamless Whether display refresh rate transitions should be seamless. A + * seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. True indicates that any frame rate changes caused by this + * request should be seamless. False indicates that non-seamless refresh rates are also + * acceptable. + * + * Available since API level 31. */ -void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, +void ASurfaceTransaction_setFrameRateWithSeamlessness(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, float frameRate, - int8_t compatibility) __INTRODUCED_IN(30); - -#endif // __ANDROID_API__ >= 30 + int8_t compatibility, bool shouldBeSeamless) + __INTRODUCED_IN(31); +#endif // __ANDROID_API__ >= 31 __END_DECLS #endif // ANDROID_SURFACE_CONTROL_H diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 678613b1ff..ac1c7369b6 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -378,11 +378,11 @@ public: }).detach(); } - status_t setFrameRate(float frameRate, int8_t compatibility) override { + status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless) override { if (!ValidateFrameRate(frameRate, compatibility, "BBQSurface::setFrameRate")) { return BAD_VALUE; } - return mBbq->setFrameRate(frameRate, compatibility); + return mBbq->setFrameRate(frameRate, compatibility, shouldBeSeamless); } status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override { @@ -392,12 +392,12 @@ public: // TODO: Can we coalesce this with frame updates? Need to confirm // no timing issues. -status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility) { +status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility, + bool shouldBeSeamless) { std::unique_lock _lock{mMutex}; SurfaceComposerClient::Transaction t; - return t.setFrameRate(mSurfaceControl, frameRate, compatibility) - .apply(); + return t.setFrameRate(mSurfaceControl, frameRate, compatibility, shouldBeSeamless).apply(); } status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 6f92233935..a9fe5bf319 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1114,7 +1114,7 @@ public: } virtual status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility) { + int8_t compatibility, bool shouldBeSeamless) { Parcel data, reply; status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { @@ -1140,6 +1140,12 @@ public: return err; } + err = data.writeBool(shouldBeSeamless); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing bool: %s (%d)", strerror(-err), -err); + return err; + } + err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); if (err != NO_ERROR) { ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); @@ -2033,7 +2039,13 @@ status_t BnSurfaceComposer::onTransact( ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err); return err; } - status_t result = setFrameRate(surface, frameRate, compatibility); + bool shouldBeSeamless; + err = data.readBool(&shouldBeSeamless); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read bool: %s (%d)", strerror(-err), -err); + return err; + } + status_t result = setFrameRate(surface, frameRate, compatibility, shouldBeSeamless); reply->writeInt32(result); return NO_ERROR; } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 9722f368f4..90999faa78 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -59,6 +59,7 @@ layer_state_t::layer_state_t() frameRateSelectionPriority(-1), frameRate(0.0f), frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), + shouldBeSeamless(true), fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0) { matrix.dsdx = matrix.dtdy = 1.0f; @@ -144,6 +145,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority); SAFE_PARCEL(output.writeFloat, frameRate); SAFE_PARCEL(output.writeByte, frameRateCompatibility); + SAFE_PARCEL(output.writeBool, shouldBeSeamless); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId); @@ -262,6 +264,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readInt32, &frameRateSelectionPriority); SAFE_PARCEL(input.readFloat, &frameRate); SAFE_PARCEL(input.readByte, &frameRateCompatibility); + SAFE_PARCEL(input.readBool, &shouldBeSeamless); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); @@ -521,6 +524,7 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameRateChanged; frameRate = other.frameRate; frameRateCompatibility = other.frameRateCompatibility; + shouldBeSeamless = other.shouldBeSeamless; } if (other.what & eFixedTransformHintChanged) { what |= eFixedTransformHintChanged; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index c1155ab73a..94390aa86c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1443,7 +1443,8 @@ int Surface::dispatchGetLastQueueDuration(va_list args) { int Surface::dispatchSetFrameRate(va_list args) { float frameRate = static_cast(va_arg(args, double)); int8_t compatibility = static_cast(va_arg(args, int)); - return setFrameRate(frameRate, compatibility); + bool shouldBeSeamless = static_cast(va_arg(args, int)); + return setFrameRate(frameRate, compatibility, shouldBeSeamless); } int Surface::dispatchAddCancelInterceptor(va_list args) { @@ -2279,7 +2280,7 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vectoronBuffersDiscarded(discardedBufs); } -status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { +status_t Surface::setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless) { ATRACE_CALL(); ALOGV("Surface::setFrameRate"); @@ -2287,7 +2288,8 @@ status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { return BAD_VALUE; } - return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility); + return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility, + shouldBeSeamless); } status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 039e9008e8..a822598d82 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1474,7 +1474,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setShado } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate( - const sp& sc, float frameRate, int8_t compatibility) { + const sp& sc, float frameRate, int8_t compatibility, + bool shouldBeSeamless) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1487,6 +1488,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame s->what |= layer_state_t::eFrameRateChanged; s->frameRate = frameRate; s->frameRateCompatibility = compatibility; + s->shouldBeSeamless = shouldBeSeamless; return *this; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 2300e81aa7..7741d8c38a 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -85,7 +85,7 @@ public: void update(const sp& surface, uint32_t width, uint32_t height); void flushShadowQueue() { mFlushShadowQueue = true; } - status_t setFrameRate(float frameRate, int8_t compatibility); + status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); virtual ~BLASTBufferQueue() = default; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 5cd9356449..9e96b79b8c 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -475,7 +475,7 @@ public: * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info. */ virtual status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility) = 0; + int8_t compatibility, bool shouldBeSeamless) = 0; /* * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired, diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index a73d9a68a5..d9f280684f 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -218,6 +218,7 @@ struct layer_state_t { // Layer frame rate and compatibility. See ANativeWindow_setFrameRate(). float frameRate; int8_t frameRateCompatibility; + bool shouldBeSeamless; // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 4aa076e7b2..82bc5c9efb 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -186,7 +186,7 @@ public: status_t getUniqueId(uint64_t* outId) const; status_t getConsumerUsage(uint64_t* outUsage) const; - virtual status_t setFrameRate(float frameRate, int8_t compatibility); + virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); protected: diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 73909a30bb..6289c6a3cd 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -524,7 +524,7 @@ public: Transaction& setShadowRadius(const sp& sc, float cornerRadius); Transaction& setFrameRate(const sp& sc, float frameRate, - int8_t compatibility); + int8_t compatibility, bool shouldBeSeamless); // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 0cd3962aa1..2392ae5ccd 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -869,7 +869,7 @@ public: } status_t setFrameRate(const sp& /*surface*/, float /*frameRate*/, - int8_t /*compatibility*/) override { + int8_t /*compatibility*/, bool /*shouldBeSeamless*/) override { return NO_ERROR; } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index fd1793b6bc..b406a9c2fe 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -159,10 +159,8 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) { } int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) { - if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { - return -EINVAL; - } - return native_window_set_frame_rate(window, frameRate, compatibility); + return ANativeWindow_setFrameRateWithSeamlessness(window, frameRate, compatibility, + /*shouldBeSeamless*/ true); } void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { @@ -172,6 +170,13 @@ void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS); } +int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, + int8_t compatibility, bool shouldBeSeamless) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { + return -EINVAL; + } + return native_window_set_frame_rate(window, frameRate, compatibility, shouldBeSeamless); +} /************************************************************************************************** * vndk-stable diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 36aad2eced..deea59b9fb 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -34,6 +34,7 @@ #define ANDROID_NATIVE_WINDOW_H #include +#include #include #include @@ -255,6 +256,31 @@ enum ANativeWindow_FrameRateCompatibility { ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1 }; +/** + * Same as ANativeWindow_setFrameRateWithSeamlessness(window, frameRate, compatibility, true). + * + * See ANativeWindow_setFrameRateWithSeamlessness(). + * + * Available since API level 30. + */ +int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) + __INTRODUCED_IN(30); + +/** + * Provides a hint to the window that buffers should be preallocated ahead of + * time. Note that the window implementation is not guaranteed to preallocate + * any buffers, for instance if an implementation disallows allocation of new + * buffers, or if there is insufficient memory in the system to preallocate + * additional buffers + * + * Available since API level 30. + */ +void ANativeWindow_tryAllocateBuffers(ANativeWindow* window); + +#endif // __ANDROID_API__ >= 30 + +#if __ANDROID_API__ >= 31 + /** * Sets the intended frame rate for this window. * @@ -271,7 +297,7 @@ enum ANativeWindow_FrameRateCompatibility { * this ANativeWindow is consumed by something other than the system compositor, * e.g. a media codec, this call has no effect. * - * Available since API level 30. + * Available since API level 31. * * \param frameRate The intended frame rate of this window, in frames per * second. 0 is a special value that indicates the app will accept the system's @@ -284,24 +310,19 @@ enum ANativeWindow_FrameRateCompatibility { * compatibility value may influence the system's choice of display refresh * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. * + * \param shouldBeSeamless Whether display refresh rate transitions should be seamless. A + * seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. True indicates that any frame rate changes caused by this + * request should be seamless. False indicates that non-seamless refresh rates are also + * acceptable. + * * \return 0 for success, -EINVAL if the window, frame rate, or compatibility * value are invalid. */ -int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) - __INTRODUCED_IN(30); +int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, + int8_t compatibility, bool shouldBeSeamless) __INTRODUCED_IN(31); -/** - * Provides a hint to the window that buffers should be preallocated ahead of - * time. Note that the window implementation is not guaranteed to preallocate - * any buffers, for instance if an implementation disallows allocation of new - * buffers, or if there is insufficient memory in the system to preallocate - * additional buffers - * - * Available since API level 30. - */ -void ANativeWindow_tryAllocateBuffers(ANativeWindow* window); - -#endif // __ANDROID_API__ >= 30 +#endif // __ANDROID_API__ >= 31 #ifdef __cplusplus }; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 138e08f490..82d2e661b4 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1018,9 +1018,9 @@ static inline int native_window_set_auto_prerotation(struct ANativeWindow* windo } static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, - int8_t compatibility) { + int8_t compatibility, bool shouldBeSeamless) { return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, - (int)compatibility); + (int)compatibility, (int)shouldBeSeamless); } static inline int native_window_set_frame_timeline_vsync(struct ANativeWindow* window, diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 1b5d20dff7..de48ec25dd 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -46,6 +46,7 @@ LIBNATIVEWINDOW { ANativeWindow_setBuffersTransform; ANativeWindow_setDequeueTimeout; # apex # introduced=30 ANativeWindow_setFrameRate; # introduced=30 + ANativeWindow_setFrameRateWithSeamlessness; # introduced=31 ANativeWindow_setSharedBufferMode; # llndk ANativeWindow_setSwapInterval; # llndk ANativeWindow_setUsage; # llndk diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 94819664ce..79e2ad0dbd 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1687,8 +1687,9 @@ void Layer::miniDump(std::string& result, const DisplayDevice& display) const { crop.bottom); if (layerState.frameRate.rate != 0 || layerState.frameRate.type != FrameRateCompatibility::Default) { - StringAppendF(&result, "% 6.2ffps %15s", layerState.frameRate.rate, - frameRateCompatibilityString(layerState.frameRate.type).c_str()); + StringAppendF(&result, "% 6.2ffps %15s seamless=%d", layerState.frameRate.rate, + frameRateCompatibilityString(layerState.frameRate.type).c_str(), + layerState.frameRate.shouldBeSeamless); } else { StringAppendF(&result, " "); } @@ -2750,6 +2751,12 @@ bool Layer::getPrimaryDisplayOnly() const { // --------------------------------------------------------------------------- +std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { + return stream << "{rate=" << rate.rate + << " type=" << Layer::frameRateCompatibilityString(rate.type) + << " shouldBeSeamless=" << rate.shouldBeSeamless << "}"; +} + }; // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b1ab9ec306..1a784aa778 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -153,12 +153,15 @@ public: struct FrameRate { float rate; FrameRateCompatibility type; + bool shouldBeSeamless; - FrameRate() : rate(0), type(FrameRateCompatibility::Default) {} - FrameRate(float rate, FrameRateCompatibility type) : rate(rate), type(type) {} + FrameRate() : rate(0), type(FrameRateCompatibility::Default), shouldBeSeamless(true) {} + FrameRate(float rate, FrameRateCompatibility type, bool shouldBeSeamless = true) + : rate(rate), type(type), shouldBeSeamless(shouldBeSeamless) {} bool operator==(const FrameRate& other) const { - return rate == other.rate && type == other.type; + return rate == other.rate && type == other.type && + shouldBeSeamless == other.shouldBeSeamless; } bool operator!=(const FrameRate& other) const { return !(*this == other); } @@ -1126,4 +1129,6 @@ private: const std::vector& getBlurRegions() const; }; +std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); + } // namespace android diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 36433c20ed..28af930bbe 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -125,12 +125,23 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { return LayerVoteType::NoVote; } }(); - summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f, - layerFocused}); + summary.push_back( + RefreshRateConfigs::LayerRequirement{.name = layer->getName(), + .vote = voteType, + .desiredRefreshRate = frameRate.rate, + .shouldBeSeamless = + frameRate.shouldBeSeamless, + .weight = 1.0f, + .focused = layerFocused}); } else if (recent) { - summary.push_back({layer->getName(), LayerVoteType::Heuristic, - info->getRefreshRate(now), - /* weight */ 1.0f, layerFocused}); + summary.push_back( + RefreshRateConfigs::LayerRequirement{.name = layer->getName(), + .vote = LayerVoteType::Heuristic, + .desiredRefreshRate = + info->getRefreshRate(now), + .shouldBeSeamless = true, + .weight = 1.0f, + .focused = layerFocused}); } if (CC_UNLIKELY(mTraceEnabled)) { diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp index 37e67e17fe..a63ccc1df0 100644 --- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp @@ -130,9 +130,9 @@ LayerHistoryV2::Summary LayerHistoryV2::summarize(nsecs_t now) { ALOGV("%s has priority: %d %s focused", strong->getName().c_str(), frameRateSelectionPriority, layerFocused ? "" : "not"); - const auto [type, refreshRate] = info->getRefreshRate(now); + const auto vote = info->getRefreshRateVote(now); // Skip NoVote layer as those don't have any requirements - if (type == LayerHistory::LayerVoteType::NoVote) { + if (vote.type == LayerHistory::LayerVoteType::NoVote) { continue; } @@ -144,10 +144,11 @@ LayerHistoryV2::Summary LayerHistoryV2::summarize(nsecs_t now) { const float layerArea = transformed.getWidth() * transformed.getHeight(); float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; - summary.push_back({strong->getName(), type, refreshRate, weight, layerFocused}); + summary.push_back({strong->getName(), vote.type, vote.fps, vote.shouldBeSeamless, weight, + layerFocused}); if (CC_UNLIKELY(mTraceEnabled)) { - trace(layer, *info, type, static_cast(std::round(refreshRate))); + trace(layer, *info, vote.type, static_cast(std::round(vote.fps))); } } @@ -178,7 +179,7 @@ void LayerHistoryV2::partitionLayers(nsecs_t now) { if (frameRate.rate > 0 || voteType == LayerVoteType::NoVote) { const auto type = layer->isVisible() ? voteType : LayerVoteType::NoVote; - info->setLayerVote(type, frameRate.rate); + info->setLayerVote({type, frameRate.rate, frameRate.shouldBeSeamless}); } else { info->resetLayerVote(); } diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp index 44f20d0063..94e7e20251 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp @@ -198,10 +198,10 @@ std::optional LayerInfoV2::calculateRefreshRateIfPossible(nsecs_t now) { : std::make_optional(mLastRefreshRate.reported); } -std::pair LayerInfoV2::getRefreshRate(nsecs_t now) { +LayerInfoV2::LayerVote LayerInfoV2::getRefreshRateVote(nsecs_t now) { if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { ALOGV("%s voted %d ", mName.c_str(), static_cast(mLayerVote.type)); - return {mLayerVote.type, mLayerVote.fps}; + return mLayerVote; } if (isAnimating(now)) { diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h index 33dc66fd19..2305bc3055 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.h +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h @@ -56,6 +56,13 @@ class LayerInfoV2 { friend class LayerHistoryTestV2; public: + // Holds information about the layer vote + struct LayerVote { + LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; + float fps = 0.0f; + bool shouldBeSeamless = true; + }; + static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; } static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) { @@ -76,7 +83,7 @@ public: // Sets an explicit layer vote. This usually comes directly from the application via // ANativeWindow_setFrameRate API - void setLayerVote(LayerHistory::LayerVoteType type, float fps) { mLayerVote = {type, fps}; } + void setLayerVote(LayerVote vote) { mLayerVote = vote; } // Sets the default layer vote. This will be the layer vote after calling to resetLayerVote(). // This is used for layers that called to setLayerVote() and then removed the vote, so that the @@ -84,9 +91,9 @@ public: void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; } // Resets the layer vote to its default. - void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f}; } + void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f, true}; } - std::pair getRefreshRate(nsecs_t now); + LayerVote getRefreshRateVote(nsecs_t now); // Return the last updated time. If the present time is farther in the future than the // updated time, the updated time is the present time. @@ -130,12 +137,6 @@ private: bool animatingOrInfrequent = false; }; - // Holds information about the layer vote - struct LayerVote { - LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; - float fps = 0.0f; - }; - // Class to store past calculated refresh rate and determine whether // the refresh rate calculated is consistent with past values class RefreshRateHistory { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 150f925fe0..0646c7dfd5 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -31,6 +31,12 @@ namespace android::scheduler { using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; using RefreshRate = RefreshRateConfigs::RefreshRate; +std::string RefreshRate::toString() const { + return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}", + getConfigId().value(), hwcConfig->getId(), getFps(), + hwcConfig->getWidth(), hwcConfig->getHeight(), getConfigGroup()); +} + std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) { switch (vote) { case LayerVoteType::NoVote: @@ -125,7 +131,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( const std::vector& layers, const GlobalSignals& globalSignals, GlobalSignals* outSignalsConsidered) const { ATRACE_CALL(); - ALOGV("getRefreshRateForContent %zu layers", layers.size()); + ALOGV("getBestRefreshRate %zu layers", layers.size()); if (outSignalsConsidered) *outSignalsConsidered = {}; const auto setTouchConsidered = [&] { @@ -148,6 +154,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; float maxExplicitWeight = 0; + int seamedLayers = 0; for (const auto& layer : layers) { if (layer.vote == LayerVoteType::NoVote) { noVoteLayers++; @@ -162,6 +169,10 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( explicitExactOrMultipleVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); } + + if (!layer.shouldBeSeamless) { + seamedLayers++; + } } const bool hasExplicitVoteLayers = @@ -206,6 +217,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( scores.emplace_back(refreshRate, 0.0f); } + const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig); + for (const auto& layer : layers) { ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), layer.weight); @@ -216,6 +229,30 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( auto weight = layer.weight; for (auto i = 0u; i < scores.size(); i++) { + // If there are no layers with shouldBeSeamless=false and the current + // config group is different from the default one, this means a layer with + // shouldBeSeamless=false has just disappeared and we should switch back to + // the default config group. + const bool isSeamlessSwitch = seamedLayers > 0 + ? scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup() + : scores[i].first->getConfigGroup() == defaultConfig->getConfigGroup(); + + if (layer.shouldBeSeamless && !isSeamlessSwitch) { + ALOGV("%s (weight %.2f) ignores %s (group=%d) to avoid non-seamless switch." + "Current config = %s", + layer.name.c_str(), weight, scores[i].first->name.c_str(), + scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str()); + continue; + } + + if (!layer.shouldBeSeamless && !isSeamlessSwitch && !layer.focused) { + ALOGV("%s (weight %.2f) ignores %s (group=%d) because it's not focused" + " and the switch is going to be seamed. Current config = %s", + layer.name.c_str(), weight, scores[i].first->name.c_str(), + scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str()); + continue; + } + bool inPrimaryRange = scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max); if ((primaryRangeIsSingleRate || !inPrimaryRange) && @@ -292,10 +329,13 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( return 1.0f / iter; }(); + // Slightly prefer seamless switches. + constexpr float kSeamedSwitchPenalty = 0.95f; + const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layerScore); - scores[i].second += weight * layerScore; + scores[i].second += weight * layerScore * seamlessness; continue; } } @@ -367,6 +407,15 @@ const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const { } const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const { + for (auto refreshRate : mPrimaryRefreshRates) { + if (mCurrentRefreshRate->getConfigGroup() == refreshRate->getConfigGroup()) { + return *refreshRate; + } + } + ALOGE("Can't find min refresh rate by policy with the same config group" + " as the current config %s", + mCurrentRefreshRate->toString().c_str()); + // Defaulting to the lowest refresh rate return *mPrimaryRefreshRates.front(); } @@ -376,6 +425,16 @@ const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const { } const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const { + for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) { + const auto& refreshRate = (**it); + if (mCurrentRefreshRate->getConfigGroup() == refreshRate.getConfigGroup()) { + return refreshRate; + } + } + ALOGE("Can't find max refresh rate by policy with the same config group" + " as the current config %s", + mCurrentRefreshRate->toString().c_str()); + // Defaulting to the highest refresh rate return *mPrimaryRefreshRates.back(); } @@ -414,7 +473,7 @@ RefreshRateConfigs::RefreshRateConfigs( const float fps = 1e9f / config->getVsyncPeriod(); mRefreshRates.emplace(configId, std::make_unique(configId, config, - base::StringPrintf("%.0ffps", fps), fps, + base::StringPrintf("%.2ffps", fps), fps, RefreshRate::ConstructorTag(0))); if (configId == currentConfigId) { mCurrentRefreshRate = mRefreshRates.at(configId).get(); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 8ff92a095c..41e54a7e7b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -86,6 +86,8 @@ public: bool operator==(const RefreshRate& other) const { return !(*this != other); } + std::string toString() const; + private: friend RefreshRateConfigs; friend class RefreshRateConfigsTest; @@ -216,6 +218,8 @@ public: LayerVoteType vote = LayerVoteType::NoVote; // Layer's desired refresh rate, if applicable. float desiredRefreshRate = 0.0f; + // If a seamless mode switch is required. + bool shouldBeSeamless = true; // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer // would have on choosing the refresh rate. float weight = 0.0f; diff --git a/services/surfaceflinger/Scheduler/StrongTyping.h b/services/surfaceflinger/Scheduler/StrongTyping.h index e8ca0ba836..6a60257c81 100644 --- a/services/surfaceflinger/Scheduler/StrongTyping.h +++ b/services/surfaceflinger/Scheduler/StrongTyping.h @@ -70,6 +70,10 @@ struct StrongTyping : Ability>... { T const& value() const { return mValue; } T& value() { return mValue; } + friend std::ostream& operator<<(std::ostream& os, const StrongTyping& value) { + return os << value.value(); + } + private: T mValue; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 57c4d52653..28a8e7ac12 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3781,7 +3781,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( "SurfaceFlinger::setClientStateLocked") && layer->setFrameRate(Layer::FrameRate(s.frameRate, Layer::FrameRate::convertCompatibility( - s.frameRateCompatibility)))) { + s.frameRateCompatibility), + s.shouldBeSeamless))) { flags |= eTraversalNeeded; } } @@ -6135,7 +6136,7 @@ const std::unordered_map& SurfaceFlinger::getGenericLayer } status_t SurfaceFlinger::setFrameRate(const sp& surface, float frameRate, - int8_t compatibility) { + int8_t compatibility, bool shouldBeSeamless) { if (!ValidateFrameRate(frameRate, compatibility, "SurfaceFlinger::setFrameRate")) { return BAD_VALUE; } @@ -6148,10 +6149,10 @@ status_t SurfaceFlinger::setFrameRate(const sp& surface, ALOGE("Attempt to set frame rate on a layer that no longer exists"); return BAD_VALUE; } - if (layer->setFrameRate( Layer::FrameRate(frameRate, - Layer::FrameRate::convertCompatibility(compatibility)))) { + Layer::FrameRate::convertCompatibility(compatibility), + shouldBeSeamless))) { setTransactionFlags(eTraversalNeeded); } } else { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a821d4473f..9666f145b0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -600,7 +600,7 @@ private: status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) override; status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility) override; + int8_t compatibility, bool shouldBeSeamless) override; status_t acquireFrameRateFlexibilityToken(sp* outToken) override; status_t setFrameTimelineVsync(const sp& surface, diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index da71dad2d4..b87c734e27 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -123,7 +123,7 @@ protected: } virtual void fillBufferQueueLayerColor(const sp& layer, const Color& color, - int32_t bufferWidth, int32_t bufferHeight) { + uint32_t bufferWidth, uint32_t bufferHeight) { ANativeWindow_Buffer buffer; ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); TransactionUtils::fillANativeWindowBufferColor(buffer, @@ -145,7 +145,7 @@ protected: } void fillLayerColor(uint32_t mLayerType, const sp& layer, const Color& color, - int32_t bufferWidth, int32_t bufferHeight) { + uint32_t bufferWidth, uint32_t bufferHeight) { switch (mLayerType) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight); diff --git a/services/surfaceflinger/tests/SetFrameRate_test.cpp b/services/surfaceflinger/tests/SetFrameRate_test.cpp index 02ba9e290d..d1bed0cc83 100644 --- a/services/surfaceflinger/tests/SetFrameRate_test.cpp +++ b/services/surfaceflinger/tests/SetFrameRate_test.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - #include #include @@ -50,8 +46,8 @@ protected: } } - const int mLayerWidth = 32; - const int mLayerHeight = 32; + const uint32_t mLayerWidth = 32; + const uint32_t mLayerHeight = 32; sp mLayer; uint32_t mLayerType; }; @@ -59,26 +55,27 @@ protected: TEST_F(SetFrameRateTest, BufferQueueLayerSetFrameRate) { CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferQueue); native_window_set_frame_rate(mLayer->getSurface().get(), 100.f, - ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT); + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED)); Transaction() - .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) + .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true) .apply(); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED)); native_window_set_frame_rate(mLayer->getSurface().get(), 300.f, - ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT); + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED)); } TEST_F(SetFrameRateTest, BufferStateLayerSetFrameRate) { CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferState); Transaction() - .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) + .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true) .apply(); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::GREEN)); } } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" \ No newline at end of file diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h index 01badf4ad9..a361b1e956 100644 --- a/services/surfaceflinger/tests/TransactionTestHarnesses.h +++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h @@ -98,14 +98,14 @@ public: outTransformHint, format); } - void fillLayerColor(const sp& layer, const Color& color, int32_t bufferWidth, - int32_t bufferHeight) { + void fillLayerColor(const sp& layer, const Color& color, uint32_t bufferWidth, + uint32_t bufferHeight) { ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color, bufferWidth, bufferHeight)); } - void fillLayerQuadrant(const sp& layer, int32_t bufferWidth, - int32_t bufferHeight, const Color& topLeft, const Color& topRight, + void fillLayerQuadrant(const sp& layer, uint32_t bufferWidth, + uint32_t bufferHeight, const Color& topLeft, const Color& topRight, const Color& bottomLeft, const Color& bottomRight) { ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer, bufferWidth, bufferHeight, diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp index cb376cd7bb..3b50321102 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp @@ -78,7 +78,7 @@ protected: for (auto& [weak, info] : history().mLayerInfos) { if (auto strong = weak.promote(); strong && strong.get() == layer) { info->setDefaultLayerVote(vote); - info->setLayerVote(vote, 0); + info->setLayerVote({vote, 0, false}); return; } } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 4762fd4b66..df7611043a 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -57,6 +57,8 @@ protected: static inline const HwcConfigIndexType HWC_CONFIG_ID_72 = HwcConfigIndexType(2); static inline const HwcConfigIndexType HWC_CONFIG_ID_120 = HwcConfigIndexType(3); static inline const HwcConfigIndexType HWC_CONFIG_ID_30 = HwcConfigIndexType(4); + static inline const HwcConfigIndexType HWC_CONFIG_ID_25 = HwcConfigIndexType(5); + static inline const HwcConfigIndexType HWC_CONFIG_ID_50 = HwcConfigIndexType(6); // Test configs std::shared_ptr mConfig60 = @@ -77,8 +79,16 @@ protected: createConfig(HWC_CONFIG_ID_120, 1, static_cast(1e9f / 120)); std::shared_ptr mConfig30 = createConfig(HWC_CONFIG_ID_30, 0, static_cast(1e9f / 30)); + std::shared_ptr mConfig30DifferentGroup = + createConfig(HWC_CONFIG_ID_30, 1, static_cast(1e9f / 30)); + std::shared_ptr mConfig25DifferentGroup = + createConfig(HWC_CONFIG_ID_25, 1, static_cast(1e9f / 25)); + std::shared_ptr mConfig50 = + createConfig(HWC_CONFIG_ID_50, 0, static_cast(1e9f / 50)); // Test device configurations + // The positions of the configs in the arrays below MUST match their IDs. For example, + // the first config should always be 60Hz, the second 90Hz etc. std::vector> m60OnlyConfigDevice = {mConfig60}; std::vector> m60_90Device = {mConfig60, mConfig90}; std::vector> m60_90DeviceWithDifferentGroups = @@ -104,6 +114,14 @@ protected: {mConfig60, mConfig90, mConfig72, mConfig120DifferentGroup, mConfig30}; std::vector> m30_60_90Device = {mConfig60, mConfig90, mConfig72DifferentGroup, mConfig120DifferentGroup, mConfig30}; + std::vector> m25_30_50_60Device = + {mConfig60, + mConfig90, + mConfig72DifferentGroup, + mConfig120DifferentGroup, + mConfig30DifferentGroup, + mConfig25DifferentGroup, + mConfig50}; // Expected RefreshRate objects RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, "60fps", 60, @@ -292,8 +310,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { /*currentConfigId=*/HWC_CONFIG_ID_60); const auto makeLayerRequirements = [](float refreshRate) -> std::vector { - return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*weight*/ 1.0f, - /*focused*/ false}}; + return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*shouldBeSeamless*/ true, + /*weight*/ 1.0f, /*focused*/ false}}; }; EXPECT_EQ(mExpected90Config, @@ -1245,7 +1263,9 @@ TEST_F(RefreshRateConfigsTest, groupSwitching) { auto& layer = layers[0]; layer.vote = LayerVoteType::ExplicitDefault; layer.desiredRefreshRate = 90.0f; + layer.shouldBeSeamless = false; layer.name = "90Hz ExplicitDefault"; + layer.focused = true; ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) @@ -1258,6 +1278,104 @@ TEST_F(RefreshRateConfigsTest, groupSwitching) { ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) .getConfigId()); + + // Verify that we won't change the group if seamless switch is required. + layer.shouldBeSeamless = true; + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + // At this point the default config in the DisplayManager policy with be 60Hz. + // Verify that if the current config is in another group and there are no layers with + // shouldBeSeamless=false we'll go back to the default group. + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + layer.desiredRefreshRate = 60.0f; + layer.name = "60Hz ExplicitDefault"; + layer.shouldBeSeamless = true; + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + // If there's a layer with shouldBeSeamless=false, another layer with shouldBeSeamless=true + // can't change the config group. + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + auto layer2 = LayerRequirement{.weight = 0.5f}; + layer2.vote = LayerVoteType::ExplicitDefault; + layer2.desiredRefreshRate = 90.0f; + layer2.name = "90Hz ExplicitDefault"; + layer2.shouldBeSeamless = false; + layer2.focused = false; + layers.push_back(layer2); + ASSERT_EQ(HWC_CONFIG_ID_90, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); +} + +TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) { + auto refreshRateConfigs = + std::make_unique(m30_60Device, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + // Allow group switching. + RefreshRateConfigs::Policy policy; + policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig; + policy.allowGroupSwitching = true; + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitExactOrMultiple; + layer.desiredRefreshRate = 60.0f; + layer.shouldBeSeamless = false; + layer.name = "60Hz ExplicitExactOrMultiple"; + layer.focused = true; + + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_120); + ASSERT_EQ(HWC_CONFIG_ID_120, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); +} + +TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) { + auto refreshRateConfigs = + std::make_unique(m25_30_50_60Device, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + // Allow group switching. + RefreshRateConfigs::Policy policy; + policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig; + policy.allowGroupSwitching = true; + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); + + auto layers = std::vector< + LayerRequirement>{LayerRequirement{.name = "60Hz ExplicitDefault", + .vote = LayerVoteType::ExplicitDefault, + .desiredRefreshRate = 60.0f, + .shouldBeSeamless = false, + .weight = 0.5f, + .focused = false}, + LayerRequirement{.name = "25Hz ExplicitExactOrMultiple", + .vote = LayerVoteType::ExplicitExactOrMultiple, + .desiredRefreshRate = 25.0f, + .shouldBeSeamless = true, + .weight = 1.0f, + .focused = true}}; + auto& seamedLayer = layers[0]; + + ASSERT_EQ(HWC_CONFIG_ID_50, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + seamedLayer.name = "30Hz ExplicitDefault", seamedLayer.desiredRefreshRate = 30.0f; + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_30); + + ASSERT_EQ(HWC_CONFIG_ID_25, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); } TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index de66f8fb41..d0bb9e291a 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -108,7 +108,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(0u, times.count("90fps")); + EXPECT_EQ(0u, times.count("90.00fps")); mRefreshRateStats->setConfigMode(CONFIG_ID_0); mRefreshRateStats->setPowerMode(PowerMode::ON); @@ -116,15 +116,15 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - ASSERT_EQ(1u, times.count("90fps")); - EXPECT_LT(0, times["90fps"]); + ASSERT_EQ(1u, times.count("90.00fps")); + EXPECT_LT(0, times["90.00fps"]); mRefreshRateStats->setPowerMode(PowerMode::DOZE); - int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + int ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_0); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; @@ -133,7 +133,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { // Because the power mode is not PowerMode::ON, switching the config // does not update refresh rates that come from the config. EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); } TEST_F(RefreshRateStatsTest, twoConfigsTest) { @@ -163,53 +163,53 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - ASSERT_EQ(1u, times.count("90fps")); - EXPECT_LT(0, times["90fps"]); + ASSERT_EQ(1u, times.count("90.00fps")); + EXPECT_LT(0, times["90.00fps"]); // When power mode is normal, time for configs updates. mRefreshRateStats->setConfigMode(CONFIG_ID_1); - int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + int ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - ASSERT_EQ(1u, times.count("60fps")); - EXPECT_LT(0, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + ASSERT_EQ(1u, times.count("60.00fps")); + EXPECT_LT(0, times["60.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_0); - int sixty = mRefreshRateStats->getTotalTimes()["60fps"]; + int sixty = mRefreshRateStats->getTotalTimes()["60.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_LT(ninety, times["90fps"]); - EXPECT_EQ(sixty, times["60fps"]); + EXPECT_LT(ninety, times["90.00fps"]); + EXPECT_EQ(sixty, times["60.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_1); - ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - EXPECT_LT(sixty, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + EXPECT_LT(sixty, times["60.00fps"]); // Because the power mode is not PowerMode::ON, switching the config // does not update refresh rates that come from the config. mRefreshRateStats->setPowerMode(PowerMode::DOZE); mRefreshRateStats->setConfigMode(CONFIG_ID_0); - sixty = mRefreshRateStats->getTotalTimes()["60fps"]; + sixty = mRefreshRateStats->getTotalTimes()["60.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - EXPECT_EQ(sixty, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + EXPECT_EQ(sixty, times["60.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_1); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - EXPECT_EQ(sixty, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + EXPECT_EQ(sixty, times["60.00fps"]); } } // namespace } // namespace scheduler -- cgit v1.2.3-59-g8ed1b From ea0de00dd9dfc03d83b0001b587fbf761493468e Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 17 Nov 2020 17:42:37 -0800 Subject: BlastBufferQueue: Add buffer rejection Second attempt at rejecting buffers that do not match layer size when buffer scaling mode is set to freeze. If we dont reject the buffers, the layer will scale the buffers incorrectly. However we do not want to reject buffers that were rendered before the size change. To prevent this, we gate the size change until we receive the first buffer with the requested size. Bug: 168504870 Test: atest SurfaceViewBufferTests libgui_test Test: go/wm-tests, check logs for no rejected buffers Change-Id: I3cc43b2bbf32b4fe6cd8d540967f217c0593aa57 --- libs/gui/BLASTBufferQueue.cpp | 42 +++++++++++++++++----------- libs/gui/include/gui/BLASTBufferQueue.h | 6 ++-- libs/gui/tests/BLASTBufferQueue_test.cpp | 15 +++++++--- services/surfaceflinger/BufferStateLayer.cpp | 27 +----------------- 4 files changed, 41 insertions(+), 49 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index ac1c7369b6..6db6112762 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -111,8 +111,8 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetName(String8(consumerName.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); mBufferItemConsumer->setBufferFreedListener(this); - mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight); + mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height); mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888); mTransformHint = mSurfaceControl->getTransformHint(); @@ -146,10 +146,10 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, std::unique_lock _lock{mMutex}; mSurfaceControl = surface; - if (mWidth != width || mHeight != height) { - mWidth = width; - mHeight = height; - mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight); + ui::Size newSize(width, height); + if (mRequestedSize != newSize) { + mRequestedSize.set(newSize); + mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height); } } @@ -218,6 +218,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { // number of buffers. if (mNumFrameAvailable == 0 || maxBuffersAcquired()) { BQA_LOGV("processNextBufferLocked waiting for frame available or callback"); + mCallbackCV.notify_all(); return; } @@ -252,10 +253,13 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } if (rejectBuffer(bufferItem)) { - BQA_LOGE("rejecting buffer:configured size=%dx%d, buffer{size=%dx%d transform=%d}", mWidth, - mHeight, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform); - // TODO(b/168917217) temporarily don't reject buffers until we can synchronize buffer size - // changes from ViewRootImpl. + BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d" + "buffer{size=%dx%d transform=%d}", + mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height, + buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform); + mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); + processNextBufferLocked(useNextTransaction); + return; } mNumAcquired++; @@ -278,7 +282,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); t->setFrame(mSurfaceControl, - {0, 0, static_cast(mWidth), static_cast(mHeight)}); + {0, 0, static_cast(mSize.width), static_cast(mSize.height)}); t->setCrop(mSurfaceControl, computeCrop(bufferItem)); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); @@ -291,13 +295,13 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 " applyTransaction=%s mTimestamp=%" PRId64, - mWidth, mHeight, bufferItem.mFrameNumber, toString(applyTransaction), + mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), bufferItem.mTimestamp); } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { if (item.mScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { - return GLConsumer::scaleDownCrop(item.mCrop, mWidth, mHeight); + return GLConsumer::scaleDownCrop(item.mCrop, mSize.width, mSize.height); } return item.mCrop; } @@ -332,8 +336,9 @@ void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) mNextTransaction = t; } -bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) const { +bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { + mSize = mRequestedSize; // Only reject buffers if scaling mode is freeze. return false; } @@ -345,9 +350,14 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) const { if (item.mTransform & ui::Transform::ROT_90) { std::swap(bufWidth, bufHeight); } + ui::Size bufferSize(bufWidth, bufHeight); + if (mRequestedSize != mSize && mRequestedSize == bufferSize) { + mSize = mRequestedSize; + return false; + } // reject buffers if the buffer size doesn't match. - return bufWidth != mWidth || bufHeight != mHeight; + return mSize != bufferSize; } // Check if we have acquired the maximum number of buffers. diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 7741d8c38a..42427c0539 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -100,7 +100,7 @@ private: void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex); Rect computeCrop(const BufferItem& item) REQUIRES(mMutex); // Return true if we need to reject the buffer based on the scaling mode and the buffer size. - bool rejectBuffer(const BufferItem& item) const REQUIRES(mMutex); + bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex); bool maxBuffersAcquired() const REQUIRES(mMutex); std::string mName; @@ -126,8 +126,8 @@ private: // is ready to be presented. PendingReleaseItem mPendingReleaseItem GUARDED_BY(mMutex); - uint32_t mWidth GUARDED_BY(mMutex); - uint32_t mHeight GUARDED_BY(mMutex); + ui::Size mSize GUARDED_BY(mMutex); + ui::Size mRequestedSize GUARDED_BY(mMutex); uint32_t mTransformHint GUARDED_BY(mMutex); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index f3559fa6c1..4282ef9e99 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -55,9 +55,9 @@ public: mBlastBufferQueueAdapter->setNextTransaction(next); } - int getWidth() { return mBlastBufferQueueAdapter->mWidth; } + int getWidth() { return mBlastBufferQueueAdapter->mSize.width; } - int getHeight() { return mBlastBufferQueueAdapter->mHeight; } + int getHeight() { return mBlastBufferQueueAdapter->mSize.height; } Transaction* getNextTransaction() { return mBlastBufferQueueAdapter->mNextTransaction; } @@ -250,8 +250,15 @@ TEST_F(BLASTBufferQueueTest, Update) { PIXEL_FORMAT_RGBA_8888); adapter.update(updateSurface, mDisplayWidth / 2, mDisplayHeight / 2); ASSERT_EQ(updateSurface, adapter.getSurfaceControl()); - ASSERT_EQ(mDisplayWidth / 2, adapter.getWidth()); - ASSERT_EQ(mDisplayHeight / 2, adapter.getHeight()); + sp igbProducer; + setUpProducer(adapter, igbProducer); + + int32_t width; + igbProducer->query(NATIVE_WINDOW_WIDTH, &width); + ASSERT_EQ(mDisplayWidth / 2, width); + int32_t height; + igbProducer->query(NATIVE_WINDOW_HEIGHT, &height); + ASSERT_EQ(mDisplayHeight / 2, height); } TEST_F(BLASTBufferQueueTest, SetNextTransaction) { diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index a64b2434d3..234b6e219b 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -526,37 +526,12 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse return NO_ERROR; } - const int32_t layerId = getSequence(); - - // Reject if the layer is invalid - uint32_t bufferWidth = s.buffer->width; - uint32_t bufferHeight = s.buffer->height; - - if (s.transform & ui::Transform::ROT_90) { - std::swap(bufferWidth, bufferHeight); - } - - if (s.transformToDisplayInverse) { - uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufferWidth, bufferHeight); - } - } - - if (getEffectiveScalingMode() == NATIVE_WINDOW_SCALING_MODE_FREEZE && - (s.active.w != bufferWidth || s.active.h != bufferHeight)) { - ALOGE("[%s] rejecting buffer: " - "bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}", - getDebugName(), bufferWidth, bufferHeight, s.active.w, s.active.h); - mFlinger->mTimeStats->removeTimeRecord(layerId, mDrawingState.frameNumber); - return BAD_VALUE; - } - for (auto& handle : mDrawingState.callbackHandles) { handle->latchTime = latchTime; handle->frameNumber = mDrawingState.frameNumber; } + const int32_t layerId = getSequence(); mFlinger->mTimeStats->setAcquireFence(layerId, mDrawingState.frameNumber, std::make_shared(mDrawingState.acquireFence)); mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime); -- cgit v1.2.3-59-g8ed1b From cf26a0a9c5467ca6ff0ab71dc944ea7341ec62e1 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 13 Nov 2020 12:56:20 -0800 Subject: BlastBufferQueue: Add support for auto refresh When BQ is in shared bufer mode, the client can request the consumer to aquire frames as fast as possible before waiting for a frame to be available. To support this for BLAST, pass the state via a transaction. Fixes: 168506187 Test: atest SurfaceViewBufferTests Change-Id: I25ddd98671a08e56798612b7e5dc72095b2c4b7b --- libs/gui/BLASTBufferQueue.cpp | 5 +++++ libs/gui/LayerState.cpp | 20 +++++++++++++++++++- libs/gui/SurfaceComposerClient.cpp | 13 +++++++++++++ libs/gui/include/gui/BLASTBufferQueue.h | 4 ++++ libs/gui/include/gui/LayerState.h | 6 ++++++ libs/gui/include/gui/SurfaceComposerClient.h | 5 +++++ services/surfaceflinger/BufferLayer.h | 8 ++++++-- services/surfaceflinger/BufferQueueLayer.cpp | 12 +++--------- services/surfaceflinger/BufferQueueLayer.h | 6 ------ services/surfaceflinger/BufferStateLayer.cpp | 11 ++++------- services/surfaceflinger/BufferStateLayer.h | 6 +----- services/surfaceflinger/Layer.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 3 +++ 13 files changed, 70 insertions(+), 30 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 6db6112762..e6aa02a8fe 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -289,6 +289,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setDesiredPresentTime(bufferItem.mTimestamp); t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber); + if (mAutoRefresh != bufferItem.mAutoRefresh) { + t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh); + mAutoRefresh = bufferItem.mAutoRefresh; + } + if (applyTransaction) { t->apply(); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 90999faa78..7d2c7b88df 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -61,7 +61,9 @@ layer_state_t::layer_state_t() frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), shouldBeSeamless(true), fixedTransformHint(ui::Transform::ROT_INVALID), - frameNumber(0) { + frameNumber(0), + frameTimelineVsyncId(ISurfaceComposer::INVALID_VSYNC_ID), + autoRefresh(false) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -149,6 +151,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId); + SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeUint32, blurRegions.size()); for (auto region : blurRegions) { @@ -269,6 +272,7 @@ status_t layer_state_t::read(const Parcel& input) fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId); + SAFE_PARCEL(input.readBool, &autoRefresh); uint32_t numRegions = 0; SAFE_PARCEL(input.readUint32, &numRegions); @@ -534,6 +538,20 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameNumberChanged; frameNumber = other.frameNumber; } + if (other.what & eFrameTimelineVsyncChanged) { + // When merging vsync Ids we take the oldest valid one + if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID && + other.frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) { + frameTimelineVsyncId = std::max(frameTimelineVsyncId, other.frameTimelineVsyncId); + } else if (frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) { + frameTimelineVsyncId = other.frameTimelineVsyncId; + } + what |= eFrameTimelineVsyncChanged; + } + if (other.what & eAutoRefreshChanged) { + what |= eAutoRefreshChanged; + autoRefresh = other.autoRefresh; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIu64 " what=0x%" PRIu64, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index a822598d82..47a08ab500 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1527,6 +1527,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAutoRefresh( + const sp& sc, bool autoRefresh) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eAutoRefreshChanged; + s->autoRefresh = autoRefresh; + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 42427c0539..9fb7d6fd36 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -139,6 +139,10 @@ private: // If set to true, the next queue buffer will wait until the shadow queue has been processed by // the adapter. bool mFlushShadowQueue = false; + // Last requested auto refresh state set by the producer. The state indicates that the consumer + // should acquire the next frame as soon as it can and not wait for a frame to become available. + // This is only relevant for shared buffer mode. + bool mAutoRefresh GUARDED_BY(mMutex) = false; }; } // namespace android diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index d9f280684f..f1c5d6712d 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -130,6 +130,7 @@ struct layer_state_t { eFrameNumberChanged = 0x400'00000000, eFrameTimelineVsyncChanged = 0x800'00000000, eBlurRegionsChanged = 0x1000'00000000, + eAutoRefreshChanged = 0x2000'00000000, }; layer_state_t(); @@ -234,6 +235,11 @@ struct layer_state_t { uint64_t frameNumber; int64_t frameTimelineVsyncId; + + // Indicates that the consumer should acquire the next frame as soon as it + // can and not wait for a frame to become available. This is only relevant + // in shared buffer mode. + bool autoRefresh; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 6289c6a3cd..2eb97f27a1 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -541,6 +541,11 @@ public: Transaction& setFrameTimelineVsync(const sp& sc, int64_t frameTimelineVsyncId); + // Indicates that the consumer should acquire the next frame as soon as it + // can and not wait for a frame to become available. This is only relevant + // in shared buffer mode. + Transaction& setAutoRefresh(const sp& sc, bool autoRefresh); + status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index deaf8461e8..63dfe5f5d9 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -178,13 +178,17 @@ protected: /// the mStateLock. ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0; + bool getAutoRefresh() const { return mAutoRefresh; } + bool getSidebandStreamChanged() const { return mSidebandStreamChanged; } + + std::atomic mAutoRefresh{false}; + std::atomic mSidebandStreamChanged{false}; + private: virtual bool fenceHasSignaled() const = 0; virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0; virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0; - virtual bool getAutoRefresh() const = 0; - virtual bool getSidebandStreamChanged() const = 0; // Latch sideband stream and returns true if the dirty region should be updated. virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 71b05fd2bf..dc99986900 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -196,14 +196,6 @@ uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const { return frameNumber; } -bool BufferQueueLayer::getAutoRefresh() const { - return mAutoRefresh; -} - -bool BufferQueueLayer::getSidebandStreamChanged() const { - return mSidebandStreamChanged; -} - bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) { // We need to update the sideband stream if the layer has both a buffer and a sideband stream. const bool updateSidebandStream = hasFrameUpdate() && mSidebandStream.get(); @@ -265,8 +257,10 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t const uint64_t maxFrameNumberToAcquire = std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber); - status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh, + bool autoRefresh; + status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &autoRefresh, &queuedBuffer, maxFrameNumberToAcquire); + mAutoRefresh = autoRefresh; if (updateResult == BufferQueue::PRESENT_LATER) { // Producer doesn't want buffer to be displayed yet. Signal a // layer update so we check again at the next opportunity. diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index fb8a0c22ee..b45900ef4c 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -90,9 +90,6 @@ protected: private: uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override; - bool getAutoRefresh() const override; - bool getSidebandStreamChanged() const override; - bool latchSidebandStream(bool& recomputeVisibleRegions) override; void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override; @@ -140,11 +137,8 @@ private: std::vector mQueueItems; std::atomic mLastFrameNumberReceived{0}; - bool mAutoRefresh{false}; - // thread-safe std::atomic mQueuedFrames{0}; - std::atomic mSidebandStreamChanged{false}; sp mContentsChangedListener; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 234b6e219b..963e54105d 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -482,13 +482,10 @@ uint64_t BufferStateLayer::getHeadFrameNumber(nsecs_t /* expectedPresentTime */) return mCurrentState.frameNumber; } -bool BufferStateLayer::getAutoRefresh() const { - // TODO(marissaw): support shared buffer mode - return false; -} - -bool BufferStateLayer::getSidebandStreamChanged() const { - return mSidebandStreamChanged.load(); +void BufferStateLayer::setAutoRefresh(bool autoRefresh) { + if (!mAutoRefresh.exchange(autoRefresh)) { + mFlinger->signalLayerUpdate(); + } } bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 104a13be71..42be62a763 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -100,6 +100,7 @@ public: Rect getBufferSize(const State& s) const override; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; Layer::RoundedCornerState getRoundedCornerState() const override; + void setAutoRefresh(bool autoRefresh) override; // ----------------------------------------------------------------------- @@ -123,9 +124,6 @@ private: uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override; - bool getAutoRefresh() const override; - bool getSidebandStreamChanged() const override; - bool latchSidebandStream(bool& recomputeVisibleRegions) override; bool hasFrameUpdate() const override; @@ -149,8 +147,6 @@ private: std::unique_ptr mTextureImage; - std::atomic mSidebandStreamChanged{false}; - mutable uint64_t mFrameNumber{0}; uint64_t mFrameCounter{0}; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 1a784aa778..8d67ce52cd 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -444,6 +444,7 @@ public: virtual bool setColorSpaceAgnostic(const bool agnostic); virtual bool setFrameRateSelectionPriority(int32_t priority); virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint); + virtual void setAutoRefresh(bool /* autoRefresh */) {} // If the variable is not set on the layer, it traverses up the tree to inherit the frame // rate priority from its parent. virtual int32_t getFrameRateSelectionPriority() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 91f050c017..4e398d354b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3796,6 +3796,9 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded | eTransformHintUpdateNeeded; } } + if (what & layer_state_t::eAutoRefreshChanged) { + layer->setAutoRefresh(s.autoRefresh); + } // This has to happen after we reparent children because when we reparent to null we remove // child layers from current state and remove its relative z. If the children are reparented in // the same transaction, then we have to make sure we reparent the children first so we do not -- cgit v1.2.3-59-g8ed1b From a3fe67b0397113b0325fc1824d127c049f96aaf5 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Tue, 1 Dec 2020 00:24:33 +0100 Subject: Fix vsyncId for long frames and double stuffed Since the vsyncId was applied immediately, and since we are doing client-side queing in case we are double stuffed, there was a scenario when setFrameTimelineVsyncId was applied too early meaning that the previous frame was tagged with the id from the next frame. To fix that, we set the pending vsync id and then apply it together with the buffer. Test: Expand quick settings, ensure no missing jank data for shared timeline jank classification Change-Id: Id54133b84e5305d7f1f21dbfd9f0889ef3e464c9 --- libs/gui/BLASTBufferQueue.cpp | 11 +++++++---- libs/gui/include/gui/BLASTBufferQueue.h | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index e6aa02a8fe..3a3a96fc32 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -289,6 +289,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setDesiredPresentTime(bufferItem.mTimestamp); t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber); + if (!mNextFrameTimelineVsyncIdQueue.empty()) { + t->setFrameTimelineVsync(mSurfaceControl, mNextFrameTimelineVsyncIdQueue.front()); + mNextFrameTimelineVsyncIdQueue.pop(); + } + if (mAutoRefresh != bufferItem.mAutoRefresh) { t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh); mAutoRefresh = bufferItem.mAutoRefresh; @@ -417,10 +422,8 @@ status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility, status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { std::unique_lock _lock{mMutex}; - SurfaceComposerClient::Transaction t; - - return t.setFrameTimelineVsync(mSurfaceControl, frameTimelineVsyncId) - .apply(); + mNextFrameTimelineVsyncIdQueue.push(frameTimelineVsyncId); + return OK; } sp BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 9fb7d6fd36..bdf128a538 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -28,6 +28,7 @@ #include #include +#include namespace android { @@ -143,6 +144,8 @@ private: // should acquire the next frame as soon as it can and not wait for a frame to become available. // This is only relevant for shared buffer mode. bool mAutoRefresh GUARDED_BY(mMutex) = false; + + std::queue mNextFrameTimelineVsyncIdQueue GUARDED_BY(mMutex); }; } // namespace android -- cgit v1.2.3-59-g8ed1b From 53c936ca72e18579f446a59765bc99770a49dd20 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 3 Dec 2020 11:46:37 -0800 Subject: BlastBufferQueue: Update layer size immediately if the buffer can scale SurfaceView size changes should be reflected immediately instead of waiting for a new buffer. If the scaling mode is not freeze, the expected behaviour is for the layer size to be update immediately. If a buffer is present, it will be scaled to the new size. If the buffer has scaling mode freeze, then the size changes will continue to be deferred until we recieve the new buffer of the new size. Fixes: 174217687 Test: atest SurfaceViewBufferTests:GeometryTests Change-Id: I19b6378de63be905db3d9c709cce0f4f26acce18 --- libs/gui/BLASTBufferQueue.cpp | 13 ++++++++++++- libs/gui/include/gui/BLASTBufferQueue.h | 5 +++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 3a3a96fc32..b9ab5613c6 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -150,6 +150,16 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, if (mRequestedSize != newSize) { mRequestedSize.set(newSize); mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height); + if (mLastBufferScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { + // If the buffer supports scaling, update the frame immediately since the client may + // want to scale the existing buffer to the new size. + mSize = mRequestedSize; + SurfaceComposerClient::Transaction t; + t.setFrame(mSurfaceControl, + {0, 0, static_cast(mSize.width), + static_cast(mSize.height)}); + t.apply(); + } } } @@ -276,6 +286,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); + mLastBufferScalingMode = bufferItem.mScalingMode; + t->setBuffer(mSurfaceControl, buffer); t->setAcquireFence(mSurfaceControl, bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); @@ -348,7 +360,6 @@ void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { - mSize = mRequestedSize; // Only reject buffers if scaling mode is freeze. return false; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index bdf128a538..11393901c7 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -146,6 +146,11 @@ private: bool mAutoRefresh GUARDED_BY(mMutex) = false; std::queue mNextFrameTimelineVsyncIdQueue GUARDED_BY(mMutex); + + // Last acquired buffer's scaling mode. This is used to check if we should update the blast + // layer size immediately or wait until we get the next buffer. This will support scenarios + // where the layer can change sizes and the buffer will scale to fit the new size. + uint32_t mLastBufferScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; }; } // namespace android -- cgit v1.2.3-59-g8ed1b From 8304f7f005c27dd1302f0080dba533af3252c135 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 2 Dec 2020 15:47:16 -0800 Subject: BLASTBufferQueue: Set consumerIsApp to false This will get us the same behavior as BufferQueueLayer. Bug: 173022064 Test: Existing tests pass Change-Id: I4e6181a1350ba4624e5f067e588b9935148f666e --- libs/gui/BLASTBufferQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index b9ab5613c6..0897e6d6cb 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -123,7 +123,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetMaxDequeuedBufferCount(2); } mBufferItemConsumer = - new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, true); + new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, false); static int32_t id = 0; auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id); id++; -- cgit v1.2.3-59-g8ed1b From 137069ea61afc69515c5412d8abc09d0a4105240 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 10 Dec 2020 22:07:37 -0500 Subject: Add missing BufferItem->BLAST items Add dataspace, hdrmetadata, and surfacedamage to the transaction Test: verified COLOR_MODE_WIDE_GAMUT works again Fixes: 175165025 Change-Id: I7c95ba29e39863aca80341c093a8a4f3952e932c --- libs/gui/BLASTBufferQueue.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index b9ab5613c6..b751e985aa 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -289,6 +289,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { mLastBufferScalingMode = bufferItem.mScalingMode; t->setBuffer(mSurfaceControl, buffer); + t->setDataspace(mSurfaceControl, static_cast(bufferItem.mDataSpace)); + t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); + t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); t->setAcquireFence(mSurfaceControl, bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); -- cgit v1.2.3-59-g8ed1b From c6f89eeb3f422361d1f447028cd8819da9b3c6b9 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 11 Dec 2020 14:27:32 -0800 Subject: BLASTBufferQueue: Pass in an invalid expected present time when acquiring a buffer Passing in 0 will acquire the buffer regardless of the buffer's timestamp. On the client side, we want to acquire the buffer and send it to SF to apply any buffer presentation logic. Bug: 175396534, 168917217 Test: GtsMediaTestCases Change-Id: I7f5007d0ebb15c651741ad4e011c4ad8dabbd912 --- libs/gui/BLASTBufferQueue.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index b9ab5613c6..5773d64704 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -42,6 +42,10 @@ namespace android { // Macros to include adapter info in log messages #define BQA_LOGV(x, ...) \ ALOGV("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) +// enable logs for a single layer +//#define BQA_LOGV(x, ...) \ +// ALOGV_IF((strstr(mName.c_str(), "SurfaceView") != nullptr), "[%s](f:%u,a:%u) " x, \ +// mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) #define BQA_LOGE(x, ...) \ ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) @@ -248,7 +252,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { BufferItem bufferItem; - status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, -1, false); + status_t status = + mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false); if (status != OK) { BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str()); return; -- cgit v1.2.3-59-g8ed1b From 894961252892325aef45e1c3f635e2b927d09536 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 14 Dec 2020 17:14:53 -0800 Subject: BlastBufferQueue: Call ProducerListener callbacks asynchronously When the IGBP is running on the client process, the ProducerListener callbacks will run synchronously and if the callbacks call into the BQ, we can deadlock. This is because If the IGBP was running on the server, the ProducerListener callbacks are via a one way binder calls that do not block. Fix this by wrapping up the listener and running the callbacks in a different thread. Bug: b/168917217 Test: atest android.media.cts.MediaSyncTest#testPlayVideo Test: go/wm-smoke Test: atest BLASTBufferQueueTest Change-Id: Ib8f45a04c457a15c64a4a8c82b0eb053ae652b86 --- libs/gui/BLASTBufferQueue.cpp | 106 ++++++++++++++++++++++++++++++- libs/gui/include/gui/BLASTBufferQueue.h | 2 + libs/gui/tests/BLASTBufferQueue_test.cpp | 40 ++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index b9ab5613c6..757b6cd6d1 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -22,8 +22,13 @@ #include #include +#include +#include +#include #include +#include #include +#include #include @@ -114,7 +119,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetDequeueTimeout(std::numeric_limits::max()); @@ -446,4 +451,103 @@ sp BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) { return new BBQSurface(mProducer, true, scHandle, this); } +// Maintains a single worker thread per process that services a list of runnables. +class AsyncWorker : public Singleton { +private: + std::thread mThread; + bool mDone = false; + std::deque> mRunnables; + std::mutex mMutex; + std::condition_variable mCv; + void run() { + std::unique_lock lock(mMutex); + while (!mDone) { + mCv.wait(lock); + while (!mRunnables.empty()) { + std::function runnable = mRunnables.front(); + mRunnables.pop_front(); + runnable(); + } + } + } + +public: + AsyncWorker() : Singleton() { mThread = std::thread(&AsyncWorker::run, this); } + + ~AsyncWorker() { + mDone = true; + mCv.notify_all(); + if (mThread.joinable()) { + mThread.join(); + } + } + + void post(std::function runnable) { + std::unique_lock lock(mMutex); + mRunnables.emplace_back(std::move(runnable)); + mCv.notify_one(); + } +}; +ANDROID_SINGLETON_STATIC_INSTANCE(AsyncWorker); + +// Asynchronously calls ProducerListener functions so we can emulate one way binder calls. +class AsyncProducerListener : public BnProducerListener { +private: + const sp mListener; + +public: + AsyncProducerListener(const sp& listener) : mListener(listener) {} + + void onBufferReleased() override { + AsyncWorker::getInstance().post([listener = mListener]() { listener->onBufferReleased(); }); + } + + void onBuffersDiscarded(const std::vector& slots) override { + AsyncWorker::getInstance().post( + [listener = mListener, slots = slots]() { listener->onBuffersDiscarded(slots); }); + } +}; + +// Extends the BufferQueueProducer to create a wrapper around the listener so the listener calls +// can be non-blocking when the producer is in the client process. +class BBQBufferQueueProducer : public BufferQueueProducer { +public: + BBQBufferQueueProducer(const sp& core) + : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/) {} + + status_t connect(const sp& listener, int api, bool producerControlledByApp, + QueueBufferOutput* output) override { + if (!listener) { + return BufferQueueProducer::connect(listener, api, producerControlledByApp, output); + } + + return BufferQueueProducer::connect(new AsyncProducerListener(listener), api, + producerControlledByApp, output); + } +}; + +// Similar to BufferQueue::createBufferQueue but creates an adapter specific bufferqueue producer. +// This BQP allows invoking client specified ProducerListeners and invoke them asynchronously, +// emulating one way binder call behavior. Without this, if the listener calls back into the queue, +// we can deadlock. +void BLASTBufferQueue::createBufferQueue(sp* outProducer, + sp* outConsumer) { + LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BLASTBufferQueue: outProducer must not be NULL"); + LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BLASTBufferQueue: outConsumer must not be NULL"); + + sp core(new BufferQueueCore()); + LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore"); + + sp producer(new BBQBufferQueueProducer(core)); + LOG_ALWAYS_FATAL_IF(producer == nullptr, + "BLASTBufferQueue: failed to create BBQBufferQueueProducer"); + + sp consumer(new BufferQueueConsumer(core)); + LOG_ALWAYS_FATAL_IF(consumer == nullptr, + "BLASTBufferQueue: failed to create BufferQueueConsumer"); + + *outProducer = producer; + *outConsumer = consumer; +} + } // namespace android diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 11393901c7..9edea315f6 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -97,6 +97,8 @@ private: // can't be copied BLASTBufferQueue& operator = (const BLASTBufferQueue& rhs); BLASTBufferQueue(const BLASTBufferQueue& rhs); + void createBufferQueue(sp* outProducer, + sp* outConsumer); void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex); Rect computeCrop(const BufferItem& item) REQUIRES(mMutex); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 4282ef9e99..17f8b975a8 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -475,6 +475,46 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { /*border*/ 0, /*outsideRegion*/ true)); } +class TestProducerListener : public BnProducerListener { +public: + sp mIgbp; + TestProducerListener(const sp& igbp) : mIgbp(igbp) {} + void onBufferReleased() override { + sp buffer; + sp fence; + mIgbp->detachNextBuffer(&buffer, &fence); + } +}; + +TEST_F(BLASTBufferQueueTest, CustomProducerListener) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp igbProducer = adapter.getIGraphicBufferProducer(); + ASSERT_NE(nullptr, igbProducer.get()); + ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2)); + IGraphicBufferProducer::QueueBufferOutput qbOutput; + ASSERT_EQ(NO_ERROR, + igbProducer->connect(new TestProducerListener(igbProducer), NATIVE_WINDOW_API_CPU, + false, &qbOutput)); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + for (int i = 0; i < 3; i++) { + int slot; + sp fence; + sp buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + Rect(mDisplayWidth, mDisplayHeight), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + } + adapter.waitForCallbacks(); +} + class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { public: void test(uint32_t tr) { -- cgit v1.2.3-59-g8ed1b From 71c2cc426af966dcafa6ca33fe64c72f5d5179a3 Mon Sep 17 00:00:00 2001 From: chaviw Date: Fri, 23 Oct 2020 16:42:02 -0700 Subject: Add TransactionCompleteCallback Allow users of BlastBufferQueue to register for transaction complete for a particular frame number. This will allow VRI to know when a transaction was applied so it can continue rendering after a relayout. Test: Split screen with blast sync Bug: 167202096 Change-Id: If0bb5b496a462ba486b05b0ddc35bff66eb29e1a --- libs/gui/BLASTBufferQueue.cpp | 100 ++++++++++++++++++++------------ libs/gui/include/gui/BLASTBufferQueue.h | 5 ++ 2 files changed, 68 insertions(+), 37 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 83283224e8..e17f3190aa 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -184,49 +184,64 @@ static void transactionCallbackThunk(void* context, nsecs_t latchTime, void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp& /*presentFence*/, const std::vector& stats) { - std::unique_lock _lock{mMutex}; - ATRACE_CALL(); - BQA_LOGV("transactionCallback"); - mInitialCallbackReceived = true; - - if (!stats.empty()) { - mTransformHint = stats[0].transformHint; - mBufferItemConsumer->setTransformHint(mTransformHint); - mBufferItemConsumer->updateFrameTimestamps(stats[0].frameEventStats.frameNumber, - stats[0].frameEventStats.refreshStartTime, - stats[0].frameEventStats.gpuCompositionDoneFence, - stats[0].presentFence, - stats[0].previousReleaseFence, - stats[0].frameEventStats.compositorTiming, - stats[0].latchTime, - stats[0].frameEventStats.dequeueReadyTime); - } - if (mPendingReleaseItem.item.mGraphicBuffer != nullptr) { + std::function transactionCompleteCallback = nullptr; + uint64_t currFrameNumber = 0; + + { + std::unique_lock _lock{mMutex}; + ATRACE_CALL(); + BQA_LOGV("transactionCallback"); + mInitialCallbackReceived = true; + if (!stats.empty()) { - mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence; - } else { - BQA_LOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback"); + mTransformHint = stats[0].transformHint; + mBufferItemConsumer->setTransformHint(mTransformHint); + mBufferItemConsumer + ->updateFrameTimestamps(stats[0].frameEventStats.frameNumber, + stats[0].frameEventStats.refreshStartTime, + stats[0].frameEventStats.gpuCompositionDoneFence, + stats[0].presentFence, stats[0].previousReleaseFence, + stats[0].frameEventStats.compositorTiming, + stats[0].latchTime, + stats[0].frameEventStats.dequeueReadyTime); + } + if (mPendingReleaseItem.item.mGraphicBuffer != nullptr) { + if (!stats.empty()) { + mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence; + } else { + BQA_LOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback"); + mPendingReleaseItem.releaseFence = nullptr; + } + mBufferItemConsumer->releaseBuffer(mPendingReleaseItem.item, + mPendingReleaseItem.releaseFence + ? mPendingReleaseItem.releaseFence + : Fence::NO_FENCE); + mNumAcquired--; + mPendingReleaseItem.item = BufferItem(); mPendingReleaseItem.releaseFence = nullptr; } - mBufferItemConsumer->releaseBuffer(mPendingReleaseItem.item, - mPendingReleaseItem.releaseFence - ? mPendingReleaseItem.releaseFence - : Fence::NO_FENCE); - mNumAcquired--; - mPendingReleaseItem.item = BufferItem(); - mPendingReleaseItem.releaseFence = nullptr; - } - if (mSubmitted.empty()) { - BQA_LOGE("ERROR: callback with no corresponding submitted buffer item"); - } - mPendingReleaseItem.item = std::move(mSubmitted.front()); - mSubmitted.pop(); + if (mSubmitted.empty()) { + BQA_LOGE("ERROR: callback with no corresponding submitted buffer item"); + } + mPendingReleaseItem.item = std::move(mSubmitted.front()); + mSubmitted.pop(); - processNextBufferLocked(false); + processNextBufferLocked(false); - mCallbackCV.notify_all(); - decStrong((void*)transactionCallbackThunk); + currFrameNumber = mPendingReleaseItem.item.mFrameNumber; + if (mTransactionCompleteCallback && mTransactionCompleteFrameNumber == currFrameNumber) { + transactionCompleteCallback = std::move(mTransactionCompleteCallback); + mTransactionCompleteFrameNumber = 0; + } + + mCallbackCV.notify_all(); + decStrong((void*)transactionCallbackThunk); + } + + if (transactionCompleteCallback) { + transactionCompleteCallback(currFrameNumber); + } } void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { @@ -394,6 +409,17 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { return mSize != bufferSize; } +void BLASTBufferQueue::setTransactionCompleteCallback( + uint64_t frameNumber, std::function&& transactionCompleteCallback) { + std::lock_guard _lock{mMutex}; + if (transactionCompleteCallback == nullptr) { + mTransactionCompleteCallback = nullptr; + } else { + mTransactionCompleteCallback = std::move(transactionCompleteCallback); + mTransactionCompleteFrameNumber = frameNumber; + } +} + // Check if we have acquired the maximum number of buffers. // As a special case, we wait for the first callback before acquiring the second buffer so we // can ensure the first buffer is presented if multiple buffers are queued in succession. diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 9edea315f6..98e0e5abbf 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -82,6 +82,8 @@ public: void transactionCallback(nsecs_t latchTime, const sp& presentFence, const std::vector& stats); void setNextTransaction(SurfaceComposerClient::Transaction *t); + void setTransactionCompleteCallback(uint64_t frameNumber, + std::function&& transactionCompleteCallback); void update(const sp& surface, uint32_t width, uint32_t height); void flushShadowQueue() { mFlushShadowQueue = true; } @@ -153,6 +155,9 @@ private: // layer size immediately or wait until we get the next buffer. This will support scenarios // where the layer can change sizes and the buffer will scale to fit the new size. uint32_t mLastBufferScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; + + std::function mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr; + uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0}; }; } // namespace android -- cgit v1.2.3-59-g8ed1b From f0c5649f2ed8ca5fba07389908b2491007d50b08 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 17 Dec 2020 18:04:15 -0800 Subject: SurfaceFlinger: correctly pass desired present time for BLAST Pass whether a desired present time is automatically populated or not to match BufferStateLayer behavior to the one we have for BufferQueueLayer. Bug: 169901895 Test: expand notification shade and observe systrace Change-Id: Ia02c5633d46dde67d2c3be33b084d63c40c2afb0 --- libs/gui/BLASTBufferQueue.cpp | 4 +- libs/gui/ISurfaceComposer.cpp | 9 ++-- libs/gui/SurfaceComposerClient.cpp | 18 ++++++-- libs/gui/include/gui/ISurfaceComposer.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 6 ++- libs/gui/tests/Surface_test.cpp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 10 ++--- services/surfaceflinger/BufferStateLayer.h | 4 +- services/surfaceflinger/Layer.h | 6 ++- services/surfaceflinger/RefreshRateOverlay.cpp | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 45 +++++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 15 ++++--- .../tests/unittests/TestableSurfaceFlinger.h | 8 ++-- .../tests/unittests/TransactionApplicationTest.cpp | 49 +++++++++++++--------- 14 files changed, 111 insertions(+), 71 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 83283224e8..9fc5495938 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -311,7 +311,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setCrop(mSurfaceControl, computeCrop(bufferItem)); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); - t->setDesiredPresentTime(bufferItem.mTimestamp); + if (!bufferItem.mIsAutoTimestamp) { + t->setDesiredPresentTime(bufferItem.mTimestamp); + } t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber); if (!mNextFrameTimelineVsyncIdQueue.empty()) { diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 405658bf6d..a8d6832275 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -71,7 +71,7 @@ public: virtual status_t setTransactionState( int64_t frameTimelineVsyncId, const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, - const InputWindowCommands& commands, int64_t desiredPresentTime, + const InputWindowCommands& commands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector& listenerCallbacks, uint64_t transactionId) { Parcel data, reply; @@ -92,6 +92,7 @@ public: SAFE_PARCEL(data.writeStrongBinder, applyToken); SAFE_PARCEL(commands.write, data); SAFE_PARCEL(data.writeInt64, desiredPresentTime); + SAFE_PARCEL(data.writeBool, isAutoTimestamp); SAFE_PARCEL(data.writeStrongBinder, uncacheBuffer.token.promote()); SAFE_PARCEL(data.writeUint64, uncacheBuffer.id); SAFE_PARCEL(data.writeBool, hasListenerCallbacks); @@ -1297,7 +1298,9 @@ status_t BnSurfaceComposer::onTransact( SAFE_PARCEL(inputWindowCommands.read, data); int64_t desiredPresentTime = 0; + bool isAutoTimestamp = true; SAFE_PARCEL(data.readInt64, &desiredPresentTime); + SAFE_PARCEL(data.readBool, &isAutoTimestamp); client_cache_t uncachedBuffer; sp tmpBinder; @@ -1323,8 +1326,8 @@ status_t BnSurfaceComposer::onTransact( return setTransactionState(frameTimelineVsyncId, state, displays, stateFlags, applyToken, inputWindowCommands, desiredPresentTime, - uncachedBuffer, hasListenerCallbacks, listenerCallbacks, - transactionId); + isAutoTimestamp, uncachedBuffer, hasListenerCallbacks, + listenerCallbacks, transactionId); } case BOOT_FINISHED: { CHECK_INTERFACE(ISurfaceComposer, data, reply); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 0d370d3aea..5570d99d61 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -395,6 +395,7 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mExplicitEarlyWakeupEnd(other.mExplicitEarlyWakeupEnd), mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime), + mIsAutoTimestamp(other.mIsAutoTimestamp), mFrameTimelineVsyncId(other.mFrameTimelineVsyncId) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; @@ -424,6 +425,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const bool explicitEarlyWakeupEnd = parcel->readBool(); const bool containsBuffer = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); + const bool isAutoTimestamp = parcel->readBool(); const int64_t frameTimelineVsyncId = parcel->readInt64(); size_t count = static_cast(parcel->readUint32()); @@ -497,6 +499,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mExplicitEarlyWakeupEnd = explicitEarlyWakeupEnd; mContainsBuffer = containsBuffer; mDesiredPresentTime = desiredPresentTime; + mIsAutoTimestamp = isAutoTimestamp; mFrameTimelineVsyncId = frameTimelineVsyncId; mDisplayStates = displayStates; mListenerCallbacks = listenerCallbacks; @@ -527,6 +530,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeBool(mExplicitEarlyWakeupEnd); parcel->writeBool(mContainsBuffer); parcel->writeInt64(mDesiredPresentTime); + parcel->writeBool(mIsAutoTimestamp); parcel->writeInt64(mFrameTimelineVsyncId); parcel->writeUint32(static_cast(mDisplayStates.size())); for (auto const& displayState : mDisplayStates) { @@ -628,7 +632,8 @@ void SurfaceComposerClient::Transaction::clear() { mEarlyWakeup = false; mExplicitEarlyWakeupStart = false; mExplicitEarlyWakeupEnd = false; - mDesiredPresentTime = -1; + mDesiredPresentTime = 0; + mIsAutoTimestamp = true; mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; } @@ -640,8 +645,9 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { uncacheBuffer.id = cacheId; sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, {}, {}, 0, applyToken, {}, -1, - uncacheBuffer, false, {}, 0 /* Undefined transactionId */); + sf->setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, {}, {}, 0, applyToken, {}, + systemTime(), true, uncacheBuffer, false, {}, + 0 /* Undefined transactionId */); } void SurfaceComposerClient::Transaction::cacheBuffers() { @@ -759,7 +765,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken, - mInputWindowCommands, mDesiredPresentTime, + mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/, hasListenerCallbacks, listenerCallbacks, mId); mId = generateId(); @@ -1201,6 +1207,9 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe } s->what |= layer_state_t::eBufferChanged; s->buffer = buffer; + if (mIsAutoTimestamp) { + mDesiredPresentTime = systemTime(); + } registerSurfaceControlForCallback(sc); @@ -1295,6 +1304,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSideb SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredPresentTime( nsecs_t desiredPresentTime) { mDesiredPresentTime = desiredPresentTime; + mIsAutoTimestamp = false; return *this; } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 7d25d61431..40316dbeea 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -166,7 +166,7 @@ public: int64_t frameTimelineVsyncId, const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, + bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector& listenerCallbacks, uint64_t transactionId) = 0; /* signal that we're done booting. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 3ee4a39392..0abe72c5b7 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -373,13 +373,17 @@ public: // to be presented. When it is not possible to present at exactly that time, it will be // presented after the time has passed. // + // If the client didn't pass a desired presentation time, mDesiredPresentTime will be + // populated to the time setBuffer was called, and mIsAutoTimestamp will be set to true. + // // Desired present times that are more than 1 second in the future may be ignored. // When a desired present time has already passed, the transaction will be presented as soon // as possible. // // Transactions from the same process are presented in the same order that they are applied. // The desired present time does not affect this ordering. - int64_t mDesiredPresentTime = -1; + int64_t mDesiredPresentTime = 0; + bool mIsAutoTimestamp = true; // The vsync Id provided by Choreographer.getVsyncId int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 7761db8815..fa98cd4c3c 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -700,7 +700,7 @@ public: const Vector& /*displays*/, uint32_t /*flags*/, const sp& /*applyToken*/, const InputWindowCommands& /*inputWindowCommands*/, - int64_t /*desiredPresentTime*/, + int64_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, const client_cache_t& /*cachedBuffer*/, bool /*hasListenerCallbacks*/, const std::vector& /*listenerCallbacks*/, diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 0b9cabae3d..df1472d0d4 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -341,7 +341,7 @@ bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t post } bool BufferStateLayer::setBuffer(const sp& buffer, const sp& acquireFence, - nsecs_t postTime, nsecs_t desiredPresentTime, + nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber) { ATRACE_CALL(); @@ -365,13 +365,13 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const spmTimeStats->setPostTime(layerId, mCurrentState.frameNumber, getName().c_str(), mOwnerUid, postTime); - desiredPresentTime = desiredPresentTime <= 0 ? 0 : desiredPresentTime; mCurrentState.desiredPresentTime = desiredPresentTime; + mCurrentState.isAutoTimestamp = isAutoTimestamp; - mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime, + mFlinger->mScheduler->recordLayerHistory(this, isAutoTimestamp ? 0 : desiredPresentTime, LayerHistory::LayerUpdateType::Buffer); - addFrameEvent(acquireFence, postTime, desiredPresentTime); + addFrameEvent(acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime); return true; } @@ -533,7 +533,7 @@ bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) co return true; } - return mCurrentState.desiredPresentTime <= expectedPresentTime; + return mCurrentState.isAutoTimestamp || mCurrentState.desiredPresentTime <= expectedPresentTime; } bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index ad00c65651..734f647b01 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -70,8 +70,8 @@ public: bool setCrop(const Rect& crop) override; bool setFrame(const Rect& frame) override; bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, - nsecs_t desiredPresentTime, const client_cache_t& clientCacheId, - uint64_t frameNumber) override; + nsecs_t desiredPresentTime, bool isAutoTimestamp, + const client_cache_t& clientCacheId, uint64_t frameNumber) override; bool setAcquireFence(const sp& fence) override; bool setDataspace(ui::Dataspace dataspace) override; bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index c9e97daf8b..d6023b66ac 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -275,7 +275,8 @@ public: // recent callback handle. std::deque> callbackHandles; bool colorSpaceAgnostic; - nsecs_t desiredPresentTime = -1; + nsecs_t desiredPresentTime = 0; + bool isAutoTimestamp = true; // Length of the cast shadow. If the radius is > 0, a shadow of length shadowRadius will // be rendered around the layer. @@ -444,7 +445,8 @@ public: virtual bool setFrame(const Rect& /*frame*/) { return false; }; virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, - const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */) { + bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, + uint64_t /* frameNumber */) { return false; }; virtual bool setAcquireFence(const sp& /*fence*/) { return false; }; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index a959b9a97f..c291b7f2e0 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -235,7 +235,7 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) { mCurrentFps = refreshRate.getFps().getIntValue(); auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame]; - mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}, + mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */)); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); @@ -247,7 +247,7 @@ void RefreshRateOverlay::onInvalidate() { const auto& buffers = getOrCreateBuffers(*mCurrentFps); mFrame = (mFrame + 1) % buffers.size(); auto buffer = buffers[mFrame]; - mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}, + mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */)); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 14536b3143..68d2a68322 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3262,8 +3262,9 @@ bool SurfaceFlinger::flushTransactionQueues() { applyTransactionState(transaction.frameTimelineVsyncId, transaction.states, transaction.displays, transaction.flags, mPendingInputWindowCommands, transaction.desiredPresentTime, - transaction.buffer, transaction.postTime, - transaction.privileged, transaction.hasListenerCallbacks, + transaction.isAutoTimestamp, transaction.buffer, + transaction.postTime, transaction.privileged, + transaction.hasListenerCallbacks, transaction.listenerCallbacks, transaction.originPid, transaction.originUid, transaction.id, /*isMainThread*/ true); transactionQueue.pop(); @@ -3294,7 +3295,7 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, bool ready = true; // 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 (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime && + if (desiredPresentTime > 0 && desiredPresentTime >= expectedPresentTime && desiredPresentTime < expectedPresentTime + s2ns(1)) { ready = false; } @@ -3331,7 +3332,7 @@ status_t SurfaceFlinger::setTransactionState( int64_t frameTimelineVsyncId, const Vector& states, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, + bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector& listenerCallbacks, uint64_t transactionId) { ATRACE_CALL(); @@ -3372,17 +3373,19 @@ status_t SurfaceFlinger::setTransactionState( const int originPid = ipc->getCallingPid(); const int originUid = ipc->getCallingUid(); - if (pendingTransactions || !transactionIsReadyToBeApplied(desiredPresentTime, states, true)) { + if (pendingTransactions || + !transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states, true)) { mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags, - desiredPresentTime, uncacheBuffer, postTime, - privileged, hasListenerCallbacks, listenerCallbacks, - originPid, originUid, transactionId); + desiredPresentTime, isAutoTimestamp, uncacheBuffer, + postTime, privileged, hasListenerCallbacks, + listenerCallbacks, originPid, originUid, + transactionId); setTransactionFlags(eTransactionFlushNeeded); return NO_ERROR; } applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands, - desiredPresentTime, uncacheBuffer, postTime, privileged, + desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, transactionId, /*isMainThread*/ false); return NO_ERROR; @@ -3392,9 +3395,10 @@ void SurfaceFlinger::applyTransactionState( int64_t frameTimelineVsyncId, const Vector& states, const Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged, - bool hasListenerCallbacks, const std::vector& listenerCallbacks, - int originPid, int originUid, uint64_t transactionId, bool isMainThread) { + bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime, + bool privileged, bool hasListenerCallbacks, + const std::vector& listenerCallbacks, int originPid, int originUid, + uint64_t transactionId, bool isMainThread) { uint32_t transactionFlags = 0; if (flags & eAnimation) { @@ -3428,12 +3432,13 @@ void SurfaceFlinger::applyTransactionState( std::unordered_set listenerCallbacksWithSurfaces; uint32_t clientStateFlags = 0; for (const ComposerState& state : states) { - clientStateFlags |= - setClientStateLocked(frameTimelineVsyncId, state, desiredPresentTime, postTime, - privileged, listenerCallbacksWithSurfaces); + clientStateFlags |= setClientStateLocked(frameTimelineVsyncId, state, desiredPresentTime, + isAutoTimestamp, postTime, privileged, + listenerCallbacksWithSurfaces); if ((flags & eAnimation) && state.state.surface) { if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) { - mScheduler->recordLayerHistory(layer.get(), desiredPresentTime, + mScheduler->recordLayerHistory(layer.get(), + isAutoTimestamp ? 0 : desiredPresentTime, LayerHistory::LayerUpdateType::AnimationTX); } } @@ -3608,7 +3613,7 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermis uint32_t SurfaceFlinger::setClientStateLocked( int64_t frameTimelineVsyncId, const ComposerState& composerState, - int64_t desiredPresentTime, int64_t postTime, bool privileged, + int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged, std::unordered_set& listenerCallbacks) { const layer_state_t& s = composerState.state; @@ -3919,8 +3924,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( ? s.frameNumber : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1; - if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, s.cachedBuffer, - frameNumber)) { + if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp, + s.cachedBuffer, frameNumber)) { flags |= eTraversalNeeded; } } @@ -4198,7 +4203,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.height = 0; displays.add(d); setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr, - mPendingInputWindowCommands, -1, {}, false, {}, + mPendingInputWindowCommands, systemTime(), true, {}, false, {}, 0 /* Undefined transactionId */); setPowerModeInternal(display, hal::PowerMode::ON); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e3e9c4f229..db75312cd3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -341,7 +341,7 @@ protected: virtual uint32_t setClientStateLocked( int64_t frameTimelineVsyncId, const ComposerState& composerState, - int64_t desiredPresentTime, int64_t postTime, bool privileged, + int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged, std::unordered_set& listenerCallbacks) REQUIRES(mStateLock); virtual void commitTransactionLocked(); @@ -434,8 +434,9 @@ private: struct TransactionState { TransactionState(int64_t frameTimelineVsyncId, const Vector& composerStates, const Vector& displayStates, uint32_t transactionFlags, - int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, - int64_t postTime, bool privileged, bool hasListenerCallbacks, + int64_t desiredPresentTime, bool isAutoTimestamp, + const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, + bool hasListenerCallbacks, std::vector listenerCallbacks, int originPid, int originUid, uint64_t transactionId) : frameTimelineVsyncId(frameTimelineVsyncId), @@ -443,6 +444,7 @@ private: displays(displayStates), flags(transactionFlags), desiredPresentTime(desiredPresentTime), + isAutoTimestamp(isAutoTimestamp), buffer(uncacheBuffer), postTime(postTime), privileged(privileged), @@ -457,6 +459,7 @@ private: Vector displays; uint32_t flags; const int64_t desiredPresentTime; + const bool isAutoTimestamp; client_cache_t buffer; const int64_t postTime; bool privileged; @@ -520,8 +523,8 @@ private: const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, - bool hasListenerCallbacks, + int64_t desiredPresentTime, bool isAutoTimestamp, + const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector& listenerCallbacks, uint64_t transactionId) override; void bootFinished() override; @@ -723,7 +726,7 @@ private: void applyTransactionState(int64_t frameTimelineVsyncId, const Vector& state, const Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, - const int64_t desiredPresentTime, + const int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged, bool hasListenerCallbacks, const std::vector& listenerCallbacks, diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index c98004a8ab..25aaa14bb1 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -371,14 +371,14 @@ public: const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, - bool hasListenerCallbacks, + int64_t desiredPresentTime, bool isAutoTimestamp, + const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, std::vector& listenerCallbacks, uint64_t transactionId) { return mFlinger->setTransactionState(frameTimelineVsyncId, states, displays, flags, applyToken, inputWindowCommands, desiredPresentTime, - uncacheBuffer, hasListenerCallbacks, listenerCallbacks, - transactionId); + isAutoTimestamp, uncacheBuffer, hasListenerCallbacks, + listenerCallbacks, transactionId); } auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); }; diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index c36d9947b7..fa6ff301af 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -97,7 +97,8 @@ public: uint32_t flags = 0; sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); InputWindowCommands inputWindowCommands; - int64_t desiredPresentTime = -1; + int64_t desiredPresentTime = 0; + bool isAutoTimestamp = true; int64_t frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; client_cache_t uncacheBuffer; int64_t id = -1; @@ -114,11 +115,13 @@ public: } void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows, - int64_t desiredPresentTime, int64_t frameTimelineVsyncId) { + int64_t desiredPresentTime, bool isAutoTimestamp, + int64_t frameTimelineVsyncId) { mTransactionNumber++; transaction.flags |= flags; // ISurfaceComposer::eSynchronous; transaction.inputWindowCommands.syncInputWindows = syncInputWindows; transaction.desiredPresentTime = desiredPresentTime; + transaction.isAutoTimestamp = isAutoTimestamp; transaction.frameTimelineVsyncId = frameTimelineVsyncId; } @@ -129,13 +132,15 @@ public: EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime())); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, - /*desiredPresentTime*/ -1, ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, + ISurfaceComposer::INVALID_VSYNC_ID); nsecs_t applicationTime = systemTime(); mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states, transaction.displays, transaction.flags, transaction.applyToken, transaction.inputWindowCommands, - transaction.desiredPresentTime, transaction.uncacheBuffer, - mHasListenerCallbacks, mCallbacks, transaction.id); + transaction.desiredPresentTime, transaction.isAutoTimestamp, + transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transaction.id); // This transaction should not have been placed on the transaction queue. // If transaction is synchronous or syncs input windows, SF @@ -164,13 +169,15 @@ public: .WillOnce(Return(time + nsecs_t(5 * 1e8))); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, - /*desiredPresentTime*/ time + s2ns(1), ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ time + s2ns(1), false, + ISurfaceComposer::INVALID_VSYNC_ID); nsecs_t applicationSentTime = systemTime(); mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states, transaction.displays, transaction.flags, transaction.applyToken, transaction.inputWindowCommands, - transaction.desiredPresentTime, transaction.uncacheBuffer, - mHasListenerCallbacks, mCallbacks, transaction.id); + transaction.desiredPresentTime, transaction.isAutoTimestamp, + transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transaction.id); nsecs_t returnedTime = systemTime(); EXPECT_LE(returnedTime, applicationSentTime + s2ns(5)); @@ -189,20 +196,23 @@ public: // transaction that should go on the pending thread TransactionInfo transactionA; setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ time + s2ns(1), ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ time + s2ns(1), false, + ISurfaceComposer::INVALID_VSYNC_ID); // transaction that would not have gone on the pending thread if not // blocked TransactionInfo transactionB; setupSingle(transactionB, flags, syncInputWindows, - /*desiredPresentTime*/ -1, ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, + ISurfaceComposer::INVALID_VSYNC_ID); nsecs_t applicationSentTime = systemTime(); mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, - transactionA.desiredPresentTime, transactionA.uncacheBuffer, - mHasListenerCallbacks, mCallbacks, transactionA.id); + transactionA.desiredPresentTime, transactionA.isAutoTimestamp, + transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionA.id); // This thread should not have been blocked by the above transaction // (5s is the timeout period that applyTransactionState waits for SF to @@ -213,8 +223,9 @@ public: mFlinger.setTransactionState(transactionB.frameTimelineVsyncId, transactionB.states, transactionB.displays, transactionB.flags, transactionB.applyToken, transactionB.inputWindowCommands, - transactionB.desiredPresentTime, transactionB.uncacheBuffer, - mHasListenerCallbacks, mCallbacks, transactionB.id); + transactionB.desiredPresentTime, transactionB.isAutoTimestamp, + transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionB.id); // this thread should have been blocked by the above transaction // if this is an animation, this thread should be blocked for 5s @@ -256,12 +267,12 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { .WillOnce(Return(s2ns(2))); TransactionInfo transactionA; // transaction to go on pending queue setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ s2ns(1), ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ s2ns(1), false, ISurfaceComposer::INVALID_VSYNC_ID); mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, - transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, - transactionA.id); + transactionA.isAutoTimestamp, transactionA.uncacheBuffer, + mHasListenerCallbacks, mCallbacks, transactionA.id); auto& transactionQueue = mFlinger.getTransactionQueue(); ASSERT_EQ(1, transactionQueue.size()); @@ -279,8 +290,8 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { empty.applyToken = sp(); mFlinger.setTransactionState(empty.frameTimelineVsyncId, empty.states, empty.displays, empty.flags, empty.applyToken, empty.inputWindowCommands, - empty.desiredPresentTime, empty.uncacheBuffer, - mHasListenerCallbacks, mCallbacks, empty.id); + empty.desiredPresentTime, empty.isAutoTimestamp, + empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks, empty.id); // flush transaction queue should flush as desiredPresentTime has // passed -- cgit v1.2.3-59-g8ed1b From c4a40c1c522bb6607fb436d81c9ff32947a37328 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 23 Dec 2020 09:14:32 -0800 Subject: Added mergeWithNextTransaction to BlastBufferQueue Resurrected abandoned cl Ife2a8c9dbcfac7a5c3b294f64bc8dce40231f652 This is to support SurfaceView synchronizing transactions with ViewRootImpl. Currently, when SurfaceView gets a callback from PositionUpdateListener, it asks ViewRootImpl whether it's waiting on a sync transactions. If so, it will add the SV transactions to the sync transactions. Otherwise, it will apply the transaction on its own. By adding the new function mergeWithNextTransaction, SV can call into BlastBufferQueue and send its own transaction without having to know whether VRI is in a blast sync. As long as blast is enabled, it can always send its transaction to the BlastBufferQueue, which will apply it when the VRI frame comes in. Test: open bubbles with sv blast Test: atest SurfaceViewSyncTest Bug: 175594838 Change-Id: I1d1b6eb3bbcaa844f430dd3a2f7cfbe59e558909 --- libs/gui/BLASTBufferQueue.cpp | 44 +++++++++++++++++++++++++++++++-- libs/gui/include/gui/BLASTBufferQueue.h | 9 ++++++- 2 files changed, 50 insertions(+), 3 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 3415d9db61..ee5552f20e 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -151,6 +151,19 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp(mPendingTransactions.size())); + SurfaceComposerClient::Transaction t; + for (auto& [targetFrameNumber, transaction] : mPendingTransactions) { + t.merge(std::move(transaction)); + } + t.apply(); +} + void BLASTBufferQueue::update(const sp& surface, uint32_t width, uint32_t height) { std::unique_lock _lock{mMutex}; mSurfaceControl = surface; @@ -312,6 +325,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { incStrong((void*)transactionCallbackThunk); mLastBufferScalingMode = bufferItem.mScalingMode; + mLastAcquiredFrameNumber = bufferItem.mFrameNumber; t->setBuffer(mSurfaceControl, buffer); t->setDataspace(mSurfaceControl, static_cast(bufferItem.mDataSpace)); @@ -341,14 +355,29 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { mAutoRefresh = bufferItem.mAutoRefresh; } + auto mergeTransaction = + [&t, currentFrameNumber = bufferItem.mFrameNumber]( + std::tuple pendingTransaction) { + auto& [targetFrameNumber, transaction] = pendingTransaction; + if (currentFrameNumber < targetFrameNumber) { + return false; + } + t->merge(std::move(transaction)); + return true; + }; + + mPendingTransactions.erase(std::remove_if(mPendingTransactions.begin(), + mPendingTransactions.end(), mergeTransaction), + mPendingTransactions.end()); + if (applyTransaction) { t->apply(); } BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 - " applyTransaction=%s mTimestamp=%" PRId64, + " applyTransaction=%s mTimestamp=%" PRId64 " mPendingTransactions.size=%d", mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), - bufferItem.mTimestamp); + bufferItem.mTimestamp, static_cast(mPendingTransactions.size())); } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { @@ -487,6 +516,17 @@ sp BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) { return new BBQSurface(mProducer, true, scHandle, this); } +void BLASTBufferQueue::mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, + uint64_t frameNumber) { + std::lock_guard _lock{mMutex}; + if (mLastAcquiredFrameNumber >= frameNumber) { + // Apply the transaction since we have already acquired the desired frame. + t->apply(); + } else { + mPendingTransactions.emplace_back(frameNumber, std::move(*t)); + } +} + // Maintains a single worker thread per process that services a list of runnables. class AsyncWorker : public Singleton { private: diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 98e0e5abbf..c4cdb65537 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -82,6 +82,7 @@ public: void transactionCallback(nsecs_t latchTime, const sp& presentFence, const std::vector& stats); void setNextTransaction(SurfaceComposerClient::Transaction *t); + void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void setTransactionCompleteCallback(uint64_t frameNumber, std::function&& transactionCompleteCallback); @@ -91,7 +92,7 @@ public: status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); - virtual ~BLASTBufferQueue() = default; + virtual ~BLASTBufferQueue(); private: friend class BLASTBufferQueueHelper; @@ -141,6 +142,9 @@ private: sp mBufferItemConsumer; SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex); + std::vector> + mPendingTransactions GUARDED_BY(mMutex); + // If set to true, the next queue buffer will wait until the shadow queue has been processed by // the adapter. bool mFlushShadowQueue = false; @@ -156,6 +160,9 @@ private: // where the layer can change sizes and the buffer will scale to fit the new size. uint32_t mLastBufferScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; + // Tracks the last acquired frame number + uint64_t mLastAcquiredFrameNumber GUARDED_BY(mMutex) = 0; + std::function mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr; uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0}; }; -- cgit v1.2.3-59-g8ed1b From 17dde6176332eaaa6e609709f9a8f4231ce7c185 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 28 Dec 2020 11:39:59 -0800 Subject: BlastBufferQueue: Handle queue to window composer queries When queuing protected buffers, libstagefright queries ANativeWindow to check if the ANativeWindow sends buffers directly to SurfaceFlinger. This check works by verifying the IGBP matches one of the tracked IGBPs in SurfaceFlinger. This does not apply to blast layers since SurfaceFlinger does not create IGBPs and there may not be any IGBP used to submit buffers. To fix this for the blast adapter, we query the blast buffer queue producer to see if it queues to SurfaceFlinger. Bug: b/175904021, b/168917217 Test: atest BlastBufferQueueTest Test: Play protected content via Google Play on AndroidTV Change-Id: Id1affce09742c6b438c7499b525615b8bd294b9a --- libs/gui/BLASTBufferQueue.cpp | 8 ++++++++ libs/gui/Surface.cpp | 4 ++++ libs/gui/tests/BLASTBufferQueue_test.cpp | 13 +++++++++++++ 3 files changed, 25 insertions(+) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index ee5552f20e..89de629442 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -600,6 +600,14 @@ public: return BufferQueueProducer::connect(new AsyncProducerListener(listener), api, producerControlledByApp, output); } + + int query(int what, int* value) override { + if (what == NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER) { + *value = 1; + return NO_ERROR; + } + return BufferQueueProducer::query(what, value); + } }; // Similar to BufferQueue::createBufferQueue but creates an adapter specific bufferqueue producer. diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 94390aa86c..1bba5e4a7d 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -985,6 +985,10 @@ int Surface::query(int what, int* value) const { } break; case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: { + status_t err = mGraphicBufferProducer->query(what, value); + if (err == NO_ERROR) { + return NO_ERROR; + } if (composerService()->authenticateSurfaceTexture( mGraphicBufferProducer)) { *value = 1; diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 17f8b975a8..170ad87993 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -515,6 +516,18 @@ TEST_F(BLASTBufferQueueTest, CustomProducerListener) { adapter.waitForCallbacks(); } +TEST_F(BLASTBufferQueueTest, QueryNativeWindowQueuesToWindowComposer) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + + sp surface = new Surface(adapter.getIGraphicBufferProducer()); + ANativeWindow* nativeWindow = (ANativeWindow*)(surface.get()); + int queuesToNativeWindow = 0; + int err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, + &queuesToNativeWindow); + ASSERT_EQ(NO_ERROR, err); + ASSERT_EQ(queuesToNativeWindow, 1); +} + class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { public: void test(uint32_t tr) { -- cgit v1.2.3-59-g8ed1b From 277142c594918f828712a2412d3f95164eebffeb Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 5 Jan 2021 18:35:29 -0800 Subject: SurfaceFlinger: Support out of order transactions With BLAST, buffers are submitted via transactions and they are subjected to the same transaction queueing logic - transactions from a client must be applied in the order they came in. This poses a problem when clients use multiple blast adapters. Transactions from one window can get queued up if the buffer is not ready to be presented, preventing transactions from another window to be applied in a timely manner. We fix this by using a different apply token for every bast adapter so their transactions are handled independently. Bug: b/176411039, b/168917217 Test: atest BlastBufferQueueTest Test: YouTube minimize video and scroll, notice scrolling is at 60/90fps Change-Id: I0005dfa3c221a2b33545e39af16ae4b1ef08d269 --- libs/gui/BLASTBufferQueue.cpp | 2 +- libs/gui/SurfaceComposerClient.cpp | 21 ++++++++-- libs/gui/include/gui/BLASTBufferQueue.h | 4 ++ libs/gui/include/gui/SurfaceComposerClient.h | 9 ++++ libs/gui/tests/BLASTBufferQueue_test.cpp | 61 ++++++++++++++++++++++++++++ 5 files changed, 93 insertions(+), 4 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 89de629442..eaa47f9680 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -371,7 +371,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { mPendingTransactions.end()); if (applyTransaction) { - t->apply(); + t->setApplyToken(mApplyToken).apply(); } BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5570d99d61..97c2693f29 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -396,7 +396,8 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), - mFrameTimelineVsyncId(other.mFrameTimelineVsyncId) { + mFrameTimelineVsyncId(other.mFrameTimelineVsyncId), + mApplyToken(other.mApplyToken) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; @@ -427,7 +428,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); const int64_t frameTimelineVsyncId = parcel->readInt64(); - + sp applyToken; + parcel->readNullableStrongBinder(&applyToken); size_t count = static_cast(parcel->readUint32()); if (count > parcel->dataSize()) { return BAD_VALUE; @@ -505,6 +507,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mListenerCallbacks = listenerCallbacks; mComposerStates = composerStates; mInputWindowCommands = inputWindowCommands; + mApplyToken = applyToken; return NO_ERROR; } @@ -532,6 +535,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); parcel->writeInt64(mFrameTimelineVsyncId); + parcel->writeStrongBinder(mApplyToken); parcel->writeUint32(static_cast(mDisplayStates.size())); for (auto const& displayState : mDisplayStates) { displayState.write(*parcel); @@ -607,6 +611,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart; mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd; + mApplyToken = other.mApplyToken; // When merging vsync Ids we take the oldest one if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID && @@ -635,6 +640,7 @@ void SurfaceComposerClient::Transaction::clear() { mDesiredPresentTime = 0; mIsAutoTimestamp = true; mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + mApplyToken = nullptr; } void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { @@ -763,7 +769,10 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd; } - sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); + sp applyToken = mApplyToken + ? mApplyToken + : IInterface::asBinder(TransactionCompletedListener::getIInstance()); + sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/, @@ -1579,6 +1588,12 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAutoR return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken( + const sp& applyToken) { + mApplyToken = applyToken; + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index c4cdb65537..1198135b0c 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -165,6 +165,10 @@ private: std::function mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr; uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0}; + + // Queues up transactions using this token in SurfaceFlinger. This prevents queued up + // transactions from other parts of the client from blocking this transaction. + const sp mApplyToken = new BBinder(); }; } // namespace android diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0abe72c5b7..48bc5d5398 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -388,6 +388,10 @@ public: // The vsync Id provided by Choreographer.getVsyncId int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + // If not null, transactions will be queued up using this token otherwise a common token + // per process will be used. + sp mApplyToken = nullptr; + InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; @@ -555,6 +559,11 @@ public: // in shared buffer mode. Transaction& setAutoRefresh(const sp& sc, bool autoRefresh); + // Queues up transactions using this token in SurfaceFlinger. By default, all transactions + // from a client are placed on the same queue. This can be used to prevent multiple + // transactions from blocking each other. + Transaction& setApplyToken(const sp& token); + status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 170ad87993..d69b7c38a3 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -221,6 +221,32 @@ protected: return captureResults.result; } + void queueBuffer(sp igbp, uint8_t r, uint8_t g, uint8_t b, + nsecs_t presentTimeDelay) { + int slot; + sp fence; + sp buf; + auto ret = igbp->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, + PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, + nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbp->requestBuffer(slot, &buf)); + + uint32_t* bufData; + buf->lock(static_cast(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast(&bufData)); + fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight() / 2), buf->getStride(), r, g, b); + buf->unlock(); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + nsecs_t timestampNanos = systemTime() + presentTimeDelay; + IGraphicBufferProducer::QueueBufferInput input(timestampNanos, false, HAL_DATASPACE_UNKNOWN, + Rect(mDisplayWidth, mDisplayHeight / 2), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, + Fence::NO_FENCE); + igbp->queueBuffer(slot, input, &qbOutput); + } + sp mClient; sp mComposer; @@ -528,6 +554,41 @@ TEST_F(BLASTBufferQueueTest, QueryNativeWindowQueuesToWindowComposer) { ASSERT_EQ(queuesToNativeWindow, 1); } +TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { + sp bgSurface = + mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState); + ASSERT_NE(nullptr, bgSurface.get()); + Transaction t; + t.setLayerStack(bgSurface, 0) + .show(bgSurface) + .setDataspace(bgSurface, ui::Dataspace::V0_SRGB) + .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight)) + .setLayer(bgSurface, std::numeric_limits::max() - 1) + .apply(); + + BLASTBufferQueueHelper slowAdapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp slowIgbProducer; + setUpProducer(slowAdapter, slowIgbProducer); + nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); + queueBuffer(slowIgbProducer, 0 /* r */, 0 /* g */, 0 /* b */, presentTimeDelay); + + BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight); + sp fastIgbProducer; + setUpProducer(fastAdapter, fastIgbProducer); + uint8_t r = 255; + uint8_t g = 0; + uint8_t b = 0; + queueBuffer(fastIgbProducer, r, g, b, 0 /* presentTimeDelay */); + fastAdapter.waitForCallbacks(); + + // capture screen and verify that it is red + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); +} + class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { public: void test(uint32_t tr) { -- cgit v1.2.3-59-g8ed1b From adf632ba3a3298b4e66edfc468cf3888d5f2eac4 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 7 Jan 2021 14:05:08 -0800 Subject: BlastBufferQueue: Pass client dequeue times to SurfaceFlinger SF keeps track of client dequeue, queue, acquire etc. timestamps to construct frame rendering timelines for developers. With BBQ, SF no longer has access to this data, so pass the dequeue time along with the buffers. Ideally this data should flow to the perfetto trace directly from the client but this is a temp solution while some perf issues with client logging is sorted out. Bug: 176931912 Test: manual tests Change-Id: Ic88170c1fb20850662cb99325ac42b7232a02817 --- aidl/gui/android/view/LayerMetadataKey.aidl | 1 + libs/gui/BLASTBufferQueue.cpp | 20 ++++++++++++++++++++ libs/gui/LayerMetadata.cpp | 12 ++++++++++++ libs/gui/include/gui/BLASTBufferQueue.h | 12 +++++++++++- libs/gui/include/gui/LayerMetadata.h | 3 +++ services/surfaceflinger/BufferStateLayer.cpp | 3 ++- services/surfaceflinger/BufferStateLayer.h | 3 ++- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/RefreshRateOverlay.cpp | 6 ++++-- services/surfaceflinger/SurfaceFlinger.cpp | 4 +++- 10 files changed, 59 insertions(+), 7 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/aidl/gui/android/view/LayerMetadataKey.aidl b/aidl/gui/android/view/LayerMetadataKey.aidl index 491c629278..a1d8ce5962 100644 --- a/aidl/gui/android/view/LayerMetadataKey.aidl +++ b/aidl/gui/android/view/LayerMetadataKey.aidl @@ -25,4 +25,5 @@ enum LayerMetadataKey { METADATA_MOUSE_CURSOR = 4, METADATA_ACCESSIBILITY_ID = 5, METADATA_OWNER_PID = 6, + METADATA_DEQUEUE_TIME = 7, } diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index eaa47f9680..f4b5a26033 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -354,6 +354,16 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh); mAutoRefresh = bufferItem.mAutoRefresh; } + { + std::unique_lock _lock{mTimestampMutex}; + auto dequeueTime = mDequeueTimestamps.find(buffer->getId()); + if (dequeueTime != mDequeueTimestamps.end()) { + Parcel p; + p.writeInt64(dequeueTime->second); + t->setMetadata(mSurfaceControl, METADATA_DEQUEUE_TIME, p); + mDequeueTimestamps.erase(dequeueTime); + } + } auto mergeTransaction = [&t, currentFrameNumber = bufferItem.mFrameNumber]( @@ -412,6 +422,16 @@ void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) { // Do nothing since we are not storing unacquired buffer items locally. } +void BLASTBufferQueue::onFrameDequeued(const uint64_t bufferId) { + std::unique_lock _lock{mTimestampMutex}; + mDequeueTimestamps[bufferId] = systemTime(); +}; + +void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) { + std::unique_lock _lock{mTimestampMutex}; + mDequeueTimestamps.erase(bufferId); +}; + void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) { std::lock_guard _lock{mMutex}; mNextTransaction = t; diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp index 30c9b373ef..634d8b7df0 100644 --- a/libs/gui/LayerMetadata.cpp +++ b/libs/gui/LayerMetadata.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "android/view/LayerMetadataKey.h" @@ -113,6 +114,15 @@ void LayerMetadata::setInt32(uint32_t key, int32_t value) { memcpy(data.data(), p.data(), p.dataSize()); } +std::optional LayerMetadata::getInt64(uint32_t key) const { + if (!has(key)) return std::nullopt; + const std::vector& data = mMap.at(key); + if (data.size() < sizeof(int64_t)) return std::nullopt; + Parcel p; + p.setData(data.data(), data.size()); + return p.readInt64(); +} + std::string LayerMetadata::itemToString(uint32_t key, const char* separator) const { if (!has(key)) return std::string(); switch (static_cast(key)) { @@ -124,6 +134,8 @@ std::string LayerMetadata::itemToString(uint32_t key, const char* separator) con return StringPrintf("taskId%s%d", separator, getInt32(key, 0)); case view::LayerMetadataKey::METADATA_OWNER_PID: return StringPrintf("ownerPID%s%d", separator, getInt32(key, 0)); + case view::LayerMetadataKey::METADATA_DEQUEUE_TIME: + return StringPrintf("dequeueTime%s%" PRId64, separator, *getInt64(key)); default: return StringPrintf("%d%s%dbytes", key, separator, static_cast(mMap.at(key).size())); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 1198135b0c..0fbcbdc50f 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -78,6 +78,8 @@ public: void onBufferFreed(const wp&/* graphicBuffer*/) override { /* TODO */ } void onFrameReplaced(const BufferItem& item) override; void onFrameAvailable(const BufferItem& item) override; + void onFrameDequeued(const uint64_t) override; + void onFrameCancelled(const uint64_t) override; void transactionCallback(nsecs_t latchTime, const sp& presentFence, const std::vector& stats); @@ -168,7 +170,15 @@ private: // Queues up transactions using this token in SurfaceFlinger. This prevents queued up // transactions from other parts of the client from blocking this transaction. - const sp mApplyToken = new BBinder(); + const sp mApplyToken GUARDED_BY(mMutex) = new BBinder(); + + // Guards access to mDequeueTimestamps since we cannot hold to mMutex in onFrameDequeued or + // we will deadlock. + std::mutex mTimestampMutex; + // Tracks buffer dequeue times by the client. This info is sent to SurfaceFlinger which uses + // it for debugging purposes. + std::unordered_map mDequeueTimestamps + GUARDED_BY(mTimestampMutex); }; } // namespace android diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h index ac48aefae6..41982c28a2 100644 --- a/libs/gui/include/gui/LayerMetadata.h +++ b/libs/gui/include/gui/LayerMetadata.h @@ -29,6 +29,7 @@ enum { METADATA_MOUSE_CURSOR = 4, METADATA_ACCESSIBILITY_ID = 5, METADATA_OWNER_PID = 6, + METADATA_DEQUEUE_TIME = 7 }; struct LayerMetadata : public Parcelable { @@ -51,6 +52,8 @@ struct LayerMetadata : public Parcelable { bool has(uint32_t key) const; int32_t getInt32(uint32_t key, int32_t fallback) const; void setInt32(uint32_t key, int32_t value); + std::optional getInt64(uint32_t key) const; + void setInt64(uint32_t key, int64_t value); std::string itemToString(uint32_t key, const char* separator) const; }; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index bca1c69c0f..a431028bde 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -343,7 +343,8 @@ bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t post bool BufferStateLayer::setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& clientCacheId, uint64_t frameNumber) { + const client_cache_t& clientCacheId, uint64_t frameNumber, + std::optional /* dequeueTime */) { ATRACE_CALL(); if (mCurrentState.buffer) { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 6414e6be60..1098606cbb 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -71,7 +71,8 @@ public: bool setFrame(const Rect& frame) override; bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& clientCacheId, uint64_t frameNumber) override; + const client_cache_t& clientCacheId, uint64_t frameNumber, + std::optional dequeueTime) override; bool setAcquireFence(const sp& fence) override; bool setDataspace(ui::Dataspace dataspace) override; bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index d6023b66ac..f78b5f31e9 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -446,7 +446,7 @@ public: virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, - uint64_t /* frameNumber */) { + uint64_t /* frameNumber */, std::optional /* dequeueTime */) { return false; }; virtual bool setAcquireFence(const sp& /*fence*/) { return false; }; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 6a511a85a0..32110e9547 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -237,7 +237,8 @@ void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) { mCurrentFps = refreshRate.getFps().getIntValue(); auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, - mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */)); + mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), + std::nullopt /* dequeueTime */); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } @@ -249,7 +250,8 @@ void RefreshRateOverlay::onInvalidate() { mFrame = (mFrame + 1) % buffers.size(); auto buffer = buffers[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, - mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */)); + mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), + std::nullopt /* dequeueTime */); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6967f69876..6938d5de57 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3840,7 +3840,9 @@ uint32_t SurfaceFlinger::setClientStateLocked( ALOGE("Attempt to update InputWindowInfo without permission ACCESS_SURFACE_FLINGER"); } } + std::optional dequeueBufferTimestamp; if (what & layer_state_t::eMetadataChanged) { + dequeueBufferTimestamp = s.metadata.getInt64(METADATA_DEQUEUE_TIME); if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded; } if (what & layer_state_t::eColorSpaceAgnosticChanged) { @@ -3928,7 +3930,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1; if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp, - s.cachedBuffer, frameNumber)) { + s.cachedBuffer, frameNumber, dequeueBufferTimestamp)) { flags |= eTraversalNeeded; } } -- cgit v1.2.3-59-g8ed1b From 565ee5462ec2e47036261dbe948fcd2eda5b0b1e Mon Sep 17 00:00:00 2001 From: chaviw Date: Thu, 14 Jan 2021 10:21:23 -0800 Subject: Pass in format when creating and updating BBQ. Pixel format should be passed in when creating or updating BBQ since the format is set on the consumer. Test: go/wm-smoke Bug: 177557720 Change-Id: Ib9137eb83d4014d98e9022527d21ad67765caad0 --- libs/gui/BLASTBufferQueue.cpp | 14 +++++++++++--- libs/gui/include/gui/BLASTBufferQueue.h | 5 +++-- libs/gui/tests/BLASTBufferQueue_test.cpp | 5 +++-- 3 files changed, 17 insertions(+), 7 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index f4b5a26033..0a3d44d336 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -117,11 +117,13 @@ void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* ne } BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp& surface, - int width, int height, bool enableTripleBuffering) + int width, int height, int32_t format, + bool enableTripleBuffering) : mName(name), mSurfaceControl(surface), mSize(width, height), mRequestedSize(mSize), + mFormat(format), mNextTransaction(nullptr) { createBufferQueue(&mProducer, &mConsumer); // since the adapter is in the client process, set dequeue timeout @@ -140,7 +142,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetFrameAvailableListener(this); mBufferItemConsumer->setBufferFreedListener(this); mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height); - mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888); + mBufferItemConsumer->setDefaultBufferFormat(format); mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); @@ -164,10 +166,16 @@ BLASTBufferQueue::~BLASTBufferQueue() { t.apply(); } -void BLASTBufferQueue::update(const sp& surface, uint32_t width, uint32_t height) { +void BLASTBufferQueue::update(const sp& surface, uint32_t width, uint32_t height, + int32_t format) { std::unique_lock _lock{mMutex}; mSurfaceControl = surface; + if (mFormat != format) { + mFormat = format; + mBufferItemConsumer->setDefaultBufferFormat(format); + } + ui::Size newSize(width, height); if (mRequestedSize != newSize) { mRequestedSize.set(newSize); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 0fbcbdc50f..411526eeb3 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -68,7 +68,7 @@ class BLASTBufferQueue { public: BLASTBufferQueue(const std::string& name, const sp& surface, int width, - int height, bool enableTripleBuffering = true); + int height, int32_t format, bool enableTripleBuffering = true); sp getIGraphicBufferProducer() const { return mProducer; @@ -88,7 +88,7 @@ public: void setTransactionCompleteCallback(uint64_t frameNumber, std::function&& transactionCompleteCallback); - void update(const sp& surface, uint32_t width, uint32_t height); + void update(const sp& surface, uint32_t width, uint32_t height, int32_t format); void flushShadowQueue() { mFlushShadowQueue = true; } status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); @@ -136,6 +136,7 @@ private: ui::Size mSize GUARDED_BY(mMutex); ui::Size mRequestedSize GUARDED_BY(mMutex); + int32_t mFormat GUARDED_BY(mMutex); uint32_t mTransformHint GUARDED_BY(mMutex); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index d69b7c38a3..70e656da9b 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -45,11 +45,12 @@ using android::hardware::graphics::common::V1_2::BufferUsage; class BLASTBufferQueueHelper { public: BLASTBufferQueueHelper(const sp& sc, int width, int height) { - mBlastBufferQueueAdapter = new BLASTBufferQueue("TestBLASTBufferQueue", sc, width, height); + mBlastBufferQueueAdapter = new BLASTBufferQueue("TestBLASTBufferQueue", sc, width, height, + PIXEL_FORMAT_RGBA_8888); } void update(const sp& sc, int width, int height) { - mBlastBufferQueueAdapter->update(sc, width, height); + mBlastBufferQueueAdapter->update(sc, width, height, PIXEL_FORMAT_RGBA_8888); } void setNextTransaction(Transaction* next) { -- cgit v1.2.3-59-g8ed1b From 8b30dd1104d26c92acd14df3a100a1ede0b1f47f Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 25 Jan 2021 14:16:54 -0800 Subject: Allow BlastBufferQueue to acquire an additional buffer We want to be able to send buffers from BlastBufferQueue to the server as soon as possible. This allows us among other things, dropping the oldest buffer when multiple buffers with timestamps are queued up. To support this behavior with BlastBufferQueue, we need to acquire an additional buffer and send it to SurfaceFlinger. This requires changing the consumer owned by BlastBufferQueue to acquire an additional buffer. This change is safe because we will only acquire the buffer if its not droppable, maintaining the contract with the producer. If the buffer is not droppable, i.e. the producer is in sync mode, once the buffer has been queued, the buffer is owned by the queue until it is released or acquired by the consumer. By acquiring an additional buffer, we transfer the ownership to the consumer earlier. The server has more info to make decisions faster. The producer still has access the same number of buffers and is unaffected. If the producer is in async mode, then this buffer may be released by the producer when trying to queue a buffer. So we check if the buffer is droppable, and we do not acquire the extra buffer in this scenario. Test: atest BlastBufferQueueTests android.media.cts.PresentationSyncTest Bug: b/176507654, b/176967609 Change-Id: I494a9edcbea0b1c297ee75df2b840d8328e59eca --- libs/gui/BLASTBufferQueue.cpp | 30 +++++++++++++++++++----------- libs/gui/BufferQueueConsumer.cpp | 13 ++++++++++++- libs/gui/include/gui/BLASTBufferQueue.h | 2 +- libs/gui/include/gui/BufferQueueConsumer.h | 4 ++++ libs/gui/include/gui/BufferQueueCore.h | 3 +++ 5 files changed, 39 insertions(+), 13 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 0a3d44d336..f9b152cce5 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -248,7 +248,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const spacquireBuffer(&bufferItem, 0 /* expectedPresent */, false); - if (status != OK) { + if (status == BufferQueue::NO_BUFFER_AVAILABLE) { + BQA_LOGV("Failed to acquire a buffer, err=NO_BUFFER_AVAILABLE"); + return; + } else if (status != OK) { BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str()); return; } @@ -414,7 +418,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { item.mFrameNumber, toString(nextTransactionSet), toString(mFlushShadowQueue)); if (nextTransactionSet || mFlushShadowQueue) { - while (mNumFrameAvailable > 0 || maxBuffersAcquired()) { + while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) { BQA_LOGV("waiting in onFrameAvailable..."); mCallbackCV.wait(_lock); } @@ -422,7 +426,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { mFlushShadowQueue = false; // add to shadow queue mNumFrameAvailable++; - processNextBufferLocked(true); + processNextBufferLocked(nextTransactionSet /* useNextTransaction */); } void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) { @@ -482,9 +486,12 @@ void BLASTBufferQueue::setTransactionCompleteCallback( // Check if we have acquired the maximum number of buffers. // As a special case, we wait for the first callback before acquiring the second buffer so we // can ensure the first buffer is presented if multiple buffers are queued in succession. -bool BLASTBufferQueue::maxBuffersAcquired() const { - return mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 || - (!mInitialCallbackReceived && mNumAcquired == 1); +// Consumer can acquire an additional buffer if that buffer is not droppable. Set +// includeExtraAcquire is true to include this buffer to the count. Since this depends on the state +// of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE. +bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const { + int maxAcquiredBuffers = MAX_ACQUIRED_BUFFERS + (includeExtraAcquire ? 2 : 1); + return mNumAcquired == maxAcquiredBuffers || (!mInitialCallbackReceived && mNumAcquired == 1); } class BBQSurface : public Surface { @@ -654,7 +661,8 @@ void BLASTBufferQueue::createBufferQueue(sp* outProducer LOG_ALWAYS_FATAL_IF(producer == nullptr, "BLASTBufferQueue: failed to create BBQBufferQueueProducer"); - sp consumer(new BufferQueueConsumer(core)); + sp consumer(new BufferQueueConsumer(core)); + consumer->setAllowExtraAcquire(true); LOG_ALWAYS_FATAL_IF(consumer == nullptr, "BLASTBufferQueue: failed to create BufferQueueConsumer"); diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index da6143c59f..7f7a0437f1 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -94,7 +94,10 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, ++numAcquiredBuffers; } } - if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { + const bool acquireNonDroppableBuffer = mCore->mAllowExtraAcquire && + numAcquiredBuffers == mCore->mMaxAcquiredBufferCount + 1; + if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1 && + !acquireNonDroppableBuffer) { BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); return INVALID_OPERATION; @@ -254,6 +257,9 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, outBuffer->mIsStale = false; outBuffer->mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh; + } else if (acquireNonDroppableBuffer && front->mIsDroppable) { + BQ_LOGV("acquireBuffer: front buffer is not droppable"); + return NO_BUFFER_AVAILABLE; } else { slot = front->mSlot; *outBuffer = *front; @@ -824,4 +830,9 @@ status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResul return NO_ERROR; } +void BufferQueueConsumer::setAllowExtraAcquire(bool allow) { + std::lock_guard lock(mCore->mMutex); + mCore->mAllowExtraAcquire = allow; +} + } // namespace android diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 411526eeb3..7f69bc4244 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -109,7 +109,7 @@ private: Rect computeCrop(const BufferItem& item) REQUIRES(mMutex); // Return true if we need to reject the buffer based on the scaling mode and the buffer size. bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex); - bool maxBuffersAcquired() const REQUIRES(mMutex); + bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex); std::string mName; sp mSurfaceControl; diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h index 7db69eca9d..6aa801ab86 100644 --- a/libs/gui/include/gui/BufferQueueConsumer.h +++ b/libs/gui/include/gui/BufferQueueConsumer.h @@ -174,6 +174,10 @@ public: // Value used to determine if present time is valid. constexpr static int MAX_REASONABLE_NSEC = 1'000'000'000ULL; // 1 second + // This allows the consumer to acquire an additional buffer if that buffer is not droppable and + // will eventually be released or acquired by the consumer. + void setAllowExtraAcquire(bool /* allow */); + private: sp mCore; diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 557c28b1b7..8d0828d88e 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -354,6 +354,9 @@ private: // mTransformHintInUse is to cache the mTransformHint used by the producer. uint32_t mTransformHintInUse; + // This allows the consumer to acquire an additional buffer if that buffer is not droppable and + // will eventually be released or acquired by the consumer. + bool mAllowExtraAcquire = false; }; // class BufferQueueCore } // namespace android -- cgit v1.2.3-59-g8ed1b From f6eddb6b42a9548f1298e899ea06a7a042182783 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 27 Jan 2021 22:02:11 -0800 Subject: Enable backpressure for BufferStateLayer The default behaviour of buffer state layer is to drop older buffers if there are newer buffers that are ready to be presented. When emulating BufferQueue behavior via the adapter, we want to queue up buffers without any present timestamps. To solve this, we introduce a layer state flag to keep the buffer in the transaction queue if there is already a buffer that is ready to be applied. Test: atest SurfaceViewBufferTests:BufferPresentationTests Bug: 176967609 Change-Id: I33f6347bd1c7a2d80dc4214e596bb864abe8c6bf --- libs/gui/BLASTBufferQueue.cpp | 21 +++++++++++++++++---- libs/gui/LayerState.cpp | 8 +++----- libs/gui/SurfaceComposerClient.cpp | 3 ++- libs/gui/include/gui/LayerState.h | 8 ++++++-- services/surfaceflinger/Layer.cpp | 2 +- services/surfaceflinger/Layer.h | 7 +++++-- services/surfaceflinger/SurfaceFlinger.cpp | 29 ++++++++++++++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 2 +- 8 files changed, 55 insertions(+), 25 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 0a3d44d336..490495596b 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -146,6 +146,10 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spgetTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); + SurfaceComposerClient::Transaction() + .setFlags(surface, layer_state_t::eEnableBackpressure, + layer_state_t::eEnableBackpressure) + .apply(); mNumAcquired = 0; mNumFrameAvailable = 0; @@ -169,13 +173,20 @@ BLASTBufferQueue::~BLASTBufferQueue() { void BLASTBufferQueue::update(const sp& surface, uint32_t width, uint32_t height, int32_t format) { std::unique_lock _lock{mMutex}; - mSurfaceControl = surface; - if (mFormat != format) { mFormat = format; mBufferItemConsumer->setDefaultBufferFormat(format); } + SurfaceComposerClient::Transaction t; + bool applyTransaction = false; + if (!SurfaceControl::isSameSurface(mSurfaceControl, surface)) { + mSurfaceControl = surface; + t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, + layer_state_t::eEnableBackpressure); + applyTransaction = true; + } + ui::Size newSize(width, height); if (mRequestedSize != newSize) { mRequestedSize.set(newSize); @@ -184,13 +195,15 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, // If the buffer supports scaling, update the frame immediately since the client may // want to scale the existing buffer to the new size. mSize = mRequestedSize; - SurfaceComposerClient::Transaction t; t.setFrame(mSurfaceControl, {0, 0, static_cast(mSize.width), static_cast(mSize.height)}); - t.apply(); + applyTransaction = true; } } + if (applyTransaction) { + t.apply(); + } } static void transactionCallbackThunk(void* context, nsecs_t latchTime, diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index e5e10a0014..2946aaed37 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -183,12 +183,9 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &layerStack); SAFE_PARCEL(input.readFloat, &alpha); - uint32_t tmpUint32 = 0; - SAFE_PARCEL(input.readUint32, &tmpUint32); - flags = static_cast(tmpUint32); + SAFE_PARCEL(input.readUint32, &flags); - SAFE_PARCEL(input.readUint32, &tmpUint32); - mask = static_cast(tmpUint32); + SAFE_PARCEL(input.readUint32, &mask); SAFE_PARCEL(matrix.read, input); SAFE_PARCEL(input.read, crop_legacy); @@ -229,6 +226,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.read, *acquireFence); } + uint32_t tmpUint32 = 0; SAFE_PARCEL(input.readUint32, &tmpUint32); dataspace = static_cast(tmpUint32); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 78f655a71b..96c099be23 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -934,7 +934,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags return *this; } if ((mask & layer_state_t::eLayerOpaque) || (mask & layer_state_t::eLayerHidden) || - (mask & layer_state_t::eLayerSecure) || (mask & layer_state_t::eLayerSkipScreenshot)) { + (mask & layer_state_t::eLayerSecure) || (mask & layer_state_t::eLayerSkipScreenshot) || + (mask & layer_state_t::eEnableBackpressure)) { s->what |= layer_state_t::eFlagsChanged; } s->flags &= ~mask; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 83a9d3356e..b1305c6607 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -82,6 +82,10 @@ struct layer_state_t { eLayerOpaque = 0x02, // SURFACE_OPAQUE eLayerSkipScreenshot = 0x40, // SKIP_SCREENSHOT eLayerSecure = 0x80, // SECURE + // Queue up BufferStateLayer buffers instead of dropping the oldest buffer when this flag is + // set. This blocks the client until all the buffers have been presented. If the buffers + // have presentation timestamps, then we may drop buffers. + eEnableBackpressure = 0x100, // ENABLE_BACKPRESSURE }; enum { @@ -157,8 +161,8 @@ struct layer_state_t { uint32_t h; uint32_t layerStack; float alpha; - uint8_t flags; - uint8_t mask; + uint32_t flags; + uint32_t mask; uint8_t reserved; matrix22_t matrix; Rect crop_legacy; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 66ce3f1a44..177a81a7bc 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1312,7 +1312,7 @@ bool Layer::setBlurRegions(const std::vector& blurRegions) { return true; } -bool Layer::setFlags(uint8_t flags, uint8_t mask) { +bool Layer::setFlags(uint32_t flags, uint32_t mask) { const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask); if (mCurrentState.flags == newFlags) return false; mCurrentState.sequence++; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 359340eb64..357c4a4dee 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -207,7 +207,7 @@ public: // to achieve mirroring. uint32_t layerStack; - uint8_t flags; + uint32_t flags; uint8_t reserved[2]; int32_t sequence; // changes when visible regions can change bool modified; @@ -425,7 +425,7 @@ public: virtual bool setBackgroundBlurRadius(int backgroundBlurRadius); virtual bool setBlurRegions(const std::vector& effectRegions); virtual bool setTransparentRegionHint(const Region& transparent); - virtual bool setFlags(uint8_t flags, uint8_t mask); + virtual bool setFlags(uint32_t flags, uint32_t mask); virtual bool setLayerStack(uint32_t layerStack); virtual uint32_t getLayerStack() const; virtual void deferTransactionUntil_legacy(const sp& barrierHandle, @@ -906,6 +906,9 @@ public: bool mPendingHWCDestroy{false}; + bool backpressureEnabled() { return mDrawingState.flags & layer_state_t::eEnableBackpressure; } + bool hasPendingBuffer() { return mCurrentState.buffer != mDrawingState.buffer; }; + protected: class SyncPoint { public: diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c1fabf8322..bf0c2d69f5 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3258,7 +3258,8 @@ bool SurfaceFlinger::flushTransactionQueues() { while (!transactionQueue.empty()) { const auto& transaction = transactionQueue.front(); - if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime, + if (!transactionIsReadyToBeApplied(transaction.isAutoTimestamp, + transaction.desiredPresentTime, transaction.states)) { setTransactionFlags(eTransactionFlushNeeded); break; @@ -3291,16 +3292,14 @@ bool SurfaceFlinger::transactionFlushNeeded() { return !mTransactionQueues.empty(); } - -bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, +bool SurfaceFlinger::transactionIsReadyToBeApplied(bool isAutoTimestamp, int64_t desiredPresentTime, const Vector& states, bool updateTransactionCounters) { - const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); bool ready = true; // 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 (desiredPresentTime > 0 && desiredPresentTime >= expectedPresentTime && + if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime && desiredPresentTime < expectedPresentTime + s2ns(1)) { ready = false; } @@ -3320,14 +3319,26 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, ALOGW("Transaction with buffer, but no Layer?"); continue; } - if (layer && !mScheduler->isVsyncValid(expectedPresentTime, layer->getOwnerUid())) { + if (!layer) { + continue; + } + + if (!mScheduler->isVsyncValid(expectedPresentTime, layer->getOwnerUid())) { ATRACE_NAME("!isVsyncValidForUid"); ready = false; } if (updateTransactionCounters) { - // See BufferStateLayer::mPendingBufferTransactions - if (layer) layer->incrementPendingBufferCount(); + // See BufferStateLayer::mPendingBufferTransactions + layer->incrementPendingBufferCount(); + } + // If backpressure is enabled and we already have a buffer to commit, keep the transaction + // in the queue. + bool hasBuffer = s.what & layer_state_t::eBufferChanged || + s.what & layer_state_t::eCachedBufferChanged; + if (hasBuffer && layer->backpressureEnabled() && layer->hasPendingBuffer() && + isAutoTimestamp) { + ready = false; } } return ready; @@ -3385,7 +3396,7 @@ status_t SurfaceFlinger::setTransactionState( // Call transactionIsReadyToBeApplied first in case we need to incrementPendingBufferCount // if the transaction contains a buffer. - if (!transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states, true) || + if (!transactionIsReadyToBeApplied(isAutoTimestamp, desiredPresentTime, states, true) || pendingTransactions) { mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags, desiredPresentTime, isAutoTimestamp, uncacheBuffer, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c90fb4aca3..194131db32 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -751,7 +751,7 @@ private: uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule); void commitTransaction() REQUIRES(mStateLock); void commitOffscreenLayers(); - bool transactionIsReadyToBeApplied(int64_t desiredPresentTime, + bool transactionIsReadyToBeApplied(bool isAutoTimestamp, int64_t desiredPresentTime, const Vector& states, bool updateTransactionCounters = false) REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); -- cgit v1.2.3-59-g8ed1b From fc434acf530cbde198c8936bf1bc09fad5861031 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 13 Jan 2021 10:28:00 -1000 Subject: Add inputEventId to SurfaceFrame SurfaceFrame will now be aware of the id of the input event that caused the current frame. The flow of input event id is inputflinger -> app -> surfaceflinger. Here, we are adding the 'inputEventId' parameter to the 'setFrameTimelineVsync' call. This call will now be responsible for setting two pieces of information: the vsync id, and the input event id. Since it will no longer be limited to the vsync id, we rename this call to "setFrameTimelineInfo". Once the inputEventId is stored in SurfaceFrame, we will add a binder call to send the frame timing information to inputflinger (separate, future CL). This will allow input to reconstruct the entire sequence of events (at what time was input event getting processed in system_server, app, and surfaceflinger) and will provide the ability to measure end-to-end touch latency. In a separate change, we will also add ATRACE calls to allow manual / script-based latency analysis for local debugging. We will now know which input event is being processed in surfaceflinger. Bug: 169866723 Bug: 129481165 Design doc: https://docs.google.com/document/d/1G3bLaZYSmbe6AKcL-6ZChvrw_B_LXEz29Z6Ed9QoYXY/edit# Test: atest WMShellUnitTests SurfaceParcelable_test libgui_test IPC_test SurfaceFlinger_test Change-Id: If7e0eee82603b38b396b53ad7ced660973efcb50 Merged-In: If7e0eee82603b38b396b53ad7ced660973efcb50 --- libs/gui/Android.bp | 3 + libs/gui/BLASTBufferQueue.cpp | 14 +- libs/gui/FrameTimelineInfo.cpp | 62 +++++ libs/gui/ISurfaceComposer.cpp | 251 ++++++++++----------- libs/gui/ITransactionCompletedListener.cpp | 6 +- libs/gui/LayerState.cpp | 18 +- libs/gui/Surface.cpp | 16 +- libs/gui/SurfaceComposerClient.cpp | 41 ++-- libs/gui/include/gui/BLASTBufferQueue.h | 4 +- libs/gui/include/gui/DisplayEventDispatcher.h | 2 +- libs/gui/include/gui/FrameTimelineInfo.h | 43 ++++ libs/gui/include/gui/ISurfaceComposer.h | 14 +- libs/gui/include/gui/LayerState.h | 4 +- libs/gui/include/gui/Surface.h | 5 +- libs/gui/include/gui/SurfaceComposerClient.h | 13 +- libs/gui/tests/Surface_test.cpp | 6 +- libs/input/android/os/IInputConstants.aidl | 9 + libs/nativewindow/include/system/window.h | 11 +- services/surfaceflinger/BufferQueueLayer.cpp | 14 +- services/surfaceflinger/BufferQueueLayer.h | 6 +- .../surfaceflinger/FrameTimeline/FrameTimeline.cpp | 97 ++++---- .../surfaceflinger/FrameTimeline/FrameTimeline.h | 28 +-- services/surfaceflinger/Layer.cpp | 16 +- services/surfaceflinger/Layer.h | 9 +- services/surfaceflinger/SurfaceFlinger.cpp | 40 ++-- services/surfaceflinger/SurfaceFlinger.h | 18 +- services/surfaceflinger/tests/LayerState_test.cpp | 29 +++ .../tests/unittests/FrameTimelineTest.cpp | 187 +++++++-------- .../tests/unittests/TestableSurfaceFlinger.h | 18 +- .../tests/unittests/TransactionApplicationTest.cpp | 72 +++--- 30 files changed, 589 insertions(+), 467 deletions(-) create mode 100644 libs/gui/FrameTimelineInfo.cpp create mode 100644 libs/gui/include/gui/FrameTimelineInfo.h (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 38ae353a68..fa5044cc16 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -49,6 +49,7 @@ cc_library_shared { srcs: [ ":framework_native_aidl", + ":inputconstants_aidl", ":libgui_aidl", ":libgui_bufferqueue_sources", @@ -62,6 +63,7 @@ cc_library_shared { "DebugEGLImageTracker.cpp", "DisplayEventDispatcher.cpp", "DisplayEventReceiver.cpp", + "FrameTimelineInfo.cpp", "GLConsumer.cpp", "IConsumerListener.cpp", "IDisplayEventConnection.cpp", @@ -154,6 +156,7 @@ cc_library_static { defaults: ["libgui_bufferqueue-defaults"], srcs: [ + ":inputconstants_aidl", ":libgui_aidl", ":libgui_bufferqueue_sources", ], diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 42d2895950..c62d9ad440 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -370,9 +370,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber); - if (!mNextFrameTimelineVsyncIdQueue.empty()) { - t->setFrameTimelineVsync(mSurfaceControl, mNextFrameTimelineVsyncIdQueue.front()); - mNextFrameTimelineVsyncIdQueue.pop(); + if (!mNextFrameTimelineInfoQueue.empty()) { + t->setFrameTimelineInfo(mSurfaceControl, mNextFrameTimelineInfoQueue.front()); + mNextFrameTimelineInfoQueue.pop(); } if (mAutoRefresh != bufferItem.mAutoRefresh) { @@ -534,8 +534,8 @@ public: return mBbq->setFrameRate(frameRate, compatibility, shouldBeSeamless); } - status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override { - return mBbq->setFrameTimelineVsync(frameTimelineVsyncId); + status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override { + return mBbq->setFrameTimelineInfo(frameTimelineInfo); } }; @@ -549,9 +549,9 @@ status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility, return t.setFrameRate(mSurfaceControl, frameRate, compatibility, shouldBeSeamless).apply(); } -status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { +status_t BLASTBufferQueue::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { std::unique_lock _lock{mMutex}; - mNextFrameTimelineVsyncIdQueue.push(frameTimelineVsyncId); + mNextFrameTimelineInfoQueue.push(frameTimelineInfo); return OK; } diff --git a/libs/gui/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp new file mode 100644 index 0000000000..f40077403a --- /dev/null +++ b/libs/gui/FrameTimelineInfo.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 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. + */ + +#define LOG_TAG "FrameTimelineInfo" + +#include + +#include +#include +#include +#include + +#include + +using android::os::IInputConstants; + +namespace android { + +status_t FrameTimelineInfo::write(Parcel& output) const { + SAFE_PARCEL(output.writeInt64, vsyncId); + SAFE_PARCEL(output.writeInt32, inputEventId); + return NO_ERROR; +} + +status_t FrameTimelineInfo::read(const Parcel& input) { + SAFE_PARCEL(input.readInt64, &vsyncId); + SAFE_PARCEL(input.readInt32, &inputEventId); + return NO_ERROR; +} + +void FrameTimelineInfo::merge(const FrameTimelineInfo& other) { + // When merging vsync Ids we take the oldest valid one + if (vsyncId != INVALID_VSYNC_ID && other.vsyncId != INVALID_VSYNC_ID) { + if (other.vsyncId > vsyncId) { + vsyncId = other.vsyncId; + inputEventId = other.inputEventId; + } + } else if (vsyncId == INVALID_VSYNC_ID) { + vsyncId = other.vsyncId; + inputEventId = other.inputEventId; + } +} + +void FrameTimelineInfo::clear() { + vsyncId = INVALID_VSYNC_ID; + inputEventId = IInputConstants::INVALID_INPUT_EVENT_ID; +} + +}; // namespace android diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index a8d6832275..f68f3e134e 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -68,16 +68,19 @@ public: return interface_cast(reply.readStrongBinder()); } - virtual status_t setTransactionState( - int64_t frameTimelineVsyncId, const Vector& state, - const Vector& displays, uint32_t flags, const sp& applyToken, - const InputWindowCommands& commands, int64_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, - const std::vector& listenerCallbacks, uint64_t transactionId) { + status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, + const Vector& state, + const Vector& displays, uint32_t flags, + const sp& applyToken, const InputWindowCommands& commands, + int64_t desiredPresentTime, bool isAutoTimestamp, + const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, + const std::vector& listenerCallbacks, + uint64_t transactionId) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeInt64, frameTimelineVsyncId); + SAFE_PARCEL(frameTimelineInfo.write, data); + SAFE_PARCEL(data.writeUint32, static_cast(state.size())); for (const auto& s : state) { SAFE_PARCEL(s.write, data); @@ -108,15 +111,14 @@ public: return remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } - virtual void bootFinished() - { + void bootFinished() override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } - virtual status_t captureDisplay(const DisplayCaptureArgs& args, - const sp& captureListener) { + status_t captureDisplay(const DisplayCaptureArgs& args, + const sp& captureListener) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(args.write, data); @@ -125,8 +127,8 @@ public: return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply); } - virtual status_t captureDisplay(uint64_t displayOrLayerStack, - const sp& captureListener) { + status_t captureDisplay(uint64_t displayOrLayerStack, + const sp& captureListener) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(data.writeUint64, displayOrLayerStack); @@ -135,8 +137,8 @@ public: return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply); } - virtual status_t captureLayers(const LayerCaptureArgs& args, - const sp& captureListener) { + status_t captureLayers(const LayerCaptureArgs& args, + const sp& captureListener) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(args.write, data); @@ -145,9 +147,8 @@ public: return remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); } - virtual bool authenticateSurfaceTexture( - const sp& bufferProducer) const - { + bool authenticateSurfaceTexture( + const sp& bufferProducer) const override { Parcel data, reply; int err = NO_ERROR; err = data.writeInterfaceToken( @@ -180,8 +181,7 @@ public: return result != 0; } - virtual status_t getSupportedFrameTimestamps( - std::vector* outSupported) const { + status_t getSupportedFrameTimestamps(std::vector* outSupported) const override { if (!outSupported) { return UNEXPECTED_NULL; } @@ -224,8 +224,8 @@ public: return NO_ERROR; } - virtual sp createDisplayEventConnection( - VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) { + sp createDisplayEventConnection( + VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) override { Parcel data, reply; sp result; int err = data.writeInterfaceToken( @@ -247,8 +247,7 @@ public: return result; } - virtual sp createDisplay(const String8& displayName, bool secure) - { + sp createDisplay(const String8& displayName, bool secure) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t status = data.writeString8(displayName); @@ -272,15 +271,14 @@ public: return display; } - virtual void destroyDisplay(const sp& display) - { + void destroyDisplay(const sp& display) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply); } - virtual std::vector getPhysicalDisplayIds() const { + std::vector getPhysicalDisplayIds() const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) == @@ -297,7 +295,7 @@ public: return {}; } - virtual sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const { + sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeUint64(displayId.value); @@ -305,8 +303,7 @@ public: return reply.readStrongBinder(); } - virtual void setPowerMode(const sp& display, int mode) - { + void setPowerMode(const sp& display, int mode) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -314,7 +311,7 @@ public: remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply); } - virtual status_t getDisplayState(const sp& display, ui::DisplayState* state) { + status_t getDisplayState(const sp& display, ui::DisplayState* state) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -326,7 +323,7 @@ public: return result; } - virtual status_t getDisplayInfo(const sp& display, DisplayInfo* info) { + status_t getDisplayInfo(const sp& display, DisplayInfo* info) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -336,7 +333,8 @@ public: return reply.read(*info); } - virtual status_t getDisplayConfigs(const sp& display, Vector* configs) { + status_t getDisplayConfigs(const sp& display, + Vector* configs) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -354,9 +352,7 @@ public: return result; } - virtual status_t getDisplayStats(const sp& display, - DisplayStatInfo* stats) - { + status_t getDisplayStats(const sp& display, DisplayStatInfo* stats) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -370,8 +366,7 @@ public: return result; } - virtual int getActiveConfig(const sp& display) - { + int getActiveConfig(const sp& display) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -379,8 +374,8 @@ public: return reply.readInt32(); } - virtual status_t getDisplayColorModes(const sp& display, - Vector* outColorModes) { + status_t getDisplayColorModes(const sp& display, + Vector* outColorModes) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -409,8 +404,8 @@ public: return result; } - virtual status_t getDisplayNativePrimaries(const sp& display, - ui::DisplayPrimaries& primaries) { + status_t getDisplayNativePrimaries(const sp& display, + ui::DisplayPrimaries& primaries) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -435,7 +430,7 @@ public: return result; } - virtual ColorMode getActiveColorMode(const sp& display) { + ColorMode getActiveColorMode(const sp& display) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -455,8 +450,7 @@ public: return static_cast(reply.readInt32()); } - virtual status_t setActiveColorMode(const sp& display, - ColorMode colorMode) { + status_t setActiveColorMode(const sp& display, ColorMode colorMode) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -481,8 +475,8 @@ public: return static_cast(reply.readInt32()); } - virtual status_t getAutoLowLatencyModeSupport(const sp& display, - bool* outSupport) const { + status_t getAutoLowLatencyModeSupport(const sp& display, + bool* outSupport) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t result = data.writeStrongBinder(display); @@ -499,7 +493,7 @@ public: return reply.readBool(outSupport); } - virtual void setAutoLowLatencyMode(const sp& display, bool on) { + void setAutoLowLatencyMode(const sp& display, bool on) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -524,7 +518,8 @@ public: } } - virtual status_t getGameContentTypeSupport(const sp& display, bool* outSupport) const { + status_t getGameContentTypeSupport(const sp& display, + bool* outSupport) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t result = data.writeStrongBinder(display); @@ -540,7 +535,7 @@ public: return reply.readBool(outSupport); } - virtual void setGameContentType(const sp& display, bool on) { + void setGameContentType(const sp& display, bool on) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -563,7 +558,7 @@ public: } } - virtual status_t clearAnimationFrameStats() { + status_t clearAnimationFrameStats() override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -578,7 +573,7 @@ public: return reply.readInt32(); } - virtual status_t getAnimationFrameStats(FrameStats* outStats) const { + status_t getAnimationFrameStats(FrameStats* outStats) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply); @@ -586,8 +581,8 @@ public: return reply.readInt32(); } - virtual status_t getHdrCapabilities(const sp& display, - HdrCapabilities* outCapabilities) const { + status_t getHdrCapabilities(const sp& display, + HdrCapabilities* outCapabilities) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t result = data.writeStrongBinder(display); @@ -608,7 +603,7 @@ public: return result; } - virtual status_t enableVSyncInjections(bool enable) { + status_t enableVSyncInjections(bool enable) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -629,7 +624,7 @@ public: return result; } - virtual status_t injectVSync(nsecs_t when) { + status_t injectVSync(nsecs_t when) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -650,7 +645,7 @@ public: return result; } - virtual status_t getLayerDebugInfo(std::vector* outLayers) { + status_t getLayerDebugInfo(std::vector* outLayers) override { if (!outLayers) { return UNEXPECTED_NULL; } @@ -680,10 +675,10 @@ public: return reply.readParcelableVector(outLayers); } - virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace, - ui::PixelFormat* defaultPixelFormat, - ui::Dataspace* wideColorGamutDataspace, - ui::PixelFormat* wideColorGamutPixelFormat) const { + status_t getCompositionPreference(ui::Dataspace* defaultDataspace, + ui::PixelFormat* defaultPixelFormat, + ui::Dataspace* wideColorGamutDataspace, + ui::PixelFormat* wideColorGamutPixelFormat) const override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -703,7 +698,7 @@ public: return error; } - virtual status_t getColorManagement(bool* outGetColorManagement) const { + status_t getColorManagement(bool* outGetColorManagement) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply); @@ -715,10 +710,10 @@ public: return err; } - virtual status_t getDisplayedContentSamplingAttributes(const sp& display, - ui::PixelFormat* outFormat, - ui::Dataspace* outDataspace, - uint8_t* outComponentMask) const { + status_t getDisplayedContentSamplingAttributes(const sp& display, + ui::PixelFormat* outFormat, + ui::Dataspace* outDataspace, + uint8_t* outComponentMask) const override { if (!outFormat || !outDataspace || !outComponentMask) return BAD_VALUE; Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -752,8 +747,8 @@ public: return error; } - virtual status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, - uint8_t componentMask, uint64_t maxFrames) { + status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, + uint8_t componentMask, uint64_t maxFrames) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -766,9 +761,9 @@ public: return result; } - virtual status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, - uint64_t timestamp, - DisplayedFrameStats* outStats) const { + status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, + uint64_t timestamp, + DisplayedFrameStats* outStats) const override { if (!outStats) return BAD_VALUE; Parcel data, reply; @@ -805,7 +800,7 @@ public: return result; } - virtual status_t getProtectedContentSupport(bool* outSupported) const { + status_t getProtectedContentSupport(bool* outSupported) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t error = @@ -817,8 +812,8 @@ public: return error; } - virtual status_t isWideColorDisplay(const sp& token, - bool* outIsWideColorDisplay) const { + status_t isWideColorDisplay(const sp& token, + bool* outIsWideColorDisplay) const override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -837,9 +832,8 @@ public: return error; } - virtual status_t addRegionSamplingListener(const Rect& samplingArea, - const sp& stopLayerHandle, - const sp& listener) { + status_t addRegionSamplingListener(const Rect& samplingArea, const sp& stopLayerHandle, + const sp& listener) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -868,7 +862,7 @@ public: return error; } - virtual status_t removeRegionSamplingListener(const sp& listener) { + status_t removeRegionSamplingListener(const sp& listener) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -888,12 +882,11 @@ public: return error; } - virtual status_t setDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t defaultConfig, bool allowGroupSwitching, - float primaryRefreshRateMin, - float primaryRefreshRateMax, - float appRequestRefreshRateMin, - float appRequestRefreshRateMax) { + status_t setDesiredDisplayConfigSpecs(const sp& displayToken, int32_t defaultConfig, + bool allowGroupSwitching, float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -947,13 +940,12 @@ public: return reply.readInt32(); } - virtual status_t getDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t* outDefaultConfig, - bool* outAllowGroupSwitching, - float* outPrimaryRefreshRateMin, - float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, - float* outAppRequestRefreshRateMax) { + status_t getDesiredDisplayConfigSpecs(const sp& displayToken, + int32_t* outDefaultConfig, bool* outAllowGroupSwitching, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) override { if (!outDefaultConfig || !outAllowGroupSwitching || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) { @@ -1011,8 +1003,8 @@ public: return reply.readInt32(); } - virtual status_t getDisplayBrightnessSupport(const sp& displayToken, - bool* outSupport) const { + status_t getDisplayBrightnessSupport(const sp& displayToken, + bool* outSupport) const override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1039,7 +1031,7 @@ public: return NO_ERROR; } - virtual status_t setDisplayBrightness(const sp& displayToken, float brightness) { + status_t setDisplayBrightness(const sp& displayToken, float brightness) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1064,7 +1056,7 @@ public: return NO_ERROR; } - virtual status_t notifyPowerBoost(int32_t boostId) { + status_t notifyPowerBoost(int32_t boostId) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1085,8 +1077,8 @@ public: return NO_ERROR; } - virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, - float lightPosY, float lightPosZ, float lightRadius) { + status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, + float lightPosY, float lightPosZ, float lightRadius) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1114,8 +1106,8 @@ public: return NO_ERROR; } - virtual status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) { + status_t setFrameRate(const sp& surface, float frameRate, + int8_t compatibility, bool shouldBeSeamless) override { Parcel data, reply; status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { @@ -1156,7 +1148,7 @@ public: return reply.readInt32(); } - virtual status_t acquireFrameRateFlexibilityToken(sp* outToken) { + status_t acquireFrameRateFlexibilityToken(sp* outToken) override { if (!outToken) return BAD_VALUE; Parcel data, reply; @@ -1191,40 +1183,34 @@ public: return NO_ERROR; } - virtual status_t setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) { + status_t setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) override { Parcel data, reply; status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed writing interface token: %s (%d)", strerror(-err), - -err); + ALOGE("%s: failed writing interface token: %s (%d)", __func__, strerror(-err), -err); return err; } err = data.writeStrongBinder(IInterface::asBinder(surface)); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed writing strong binder: %s (%d)", strerror(-err), - -err); + ALOGE("%s: failed writing strong binder: %s (%d)", __func__, strerror(-err), -err); return err; } - err = data.writeInt64(frameTimelineVsyncId); - if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed writing int64_t: %s (%d)", strerror(-err), -err); - return err; - } + SAFE_PARCEL(frameTimelineInfo.write, data); - err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_VSYNC, data, &reply); + err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_INFO, data, &reply); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed to transact: %s (%d)", strerror(-err), err); + ALOGE("%s: failed to transact: %s (%d)", __func__, strerror(-err), err); return err; } return reply.readInt32(); } - virtual status_t addTransactionTraceListener( - const sp& listener) { + status_t addTransactionTraceListener( + const sp& listener) override { Parcel data, reply; SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); @@ -1235,7 +1221,7 @@ public: /** * Get priority of the RenderEngine in surface flinger. */ - virtual int getGPUContextPriority() { + int getGPUContextPriority() override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t err = @@ -1269,8 +1255,9 @@ status_t BnSurfaceComposer::onTransact( case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - int64_t frameTimelineVsyncId; - SAFE_PARCEL(data.readInt64, &frameTimelineVsyncId); + FrameTimelineInfo frameTimelineInfo; + SAFE_PARCEL(frameTimelineInfo.read, data); + uint32_t count = 0; SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize()); Vector state; @@ -1324,10 +1311,10 @@ status_t BnSurfaceComposer::onTransact( uint64_t transactionId = -1; SAFE_PARCEL(data.readUint64, &transactionId); - return setTransactionState(frameTimelineVsyncId, state, displays, stateFlags, - applyToken, inputWindowCommands, desiredPresentTime, - isAutoTimestamp, uncachedBuffer, hasListenerCallbacks, - listenerCallbacks, transactionId); + return setTransactionState(frameTimelineInfo, state, displays, stateFlags, applyToken, + inputWindowCommands, desiredPresentTime, isAutoTimestamp, + uncachedBuffer, hasListenerCallbacks, listenerCallbacks, + transactionId); } case BOOT_FINISHED: { CHECK_INTERFACE(ISurfaceComposer, data, reply); @@ -2078,30 +2065,26 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } - case SET_FRAME_TIMELINE_VSYNC: { + case SET_FRAME_TIMELINE_INFO: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp binder; status_t err = data.readStrongBinder(&binder); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed to read strong binder: %s (%d)", - strerror(-err), -err); + ALOGE("setFrameTimelineInfo: failed to read strong binder: %s (%d)", strerror(-err), + -err); return err; } sp surface = interface_cast(binder); if (!surface) { - ALOGE("setFrameTimelineVsync: failed to cast to IGraphicBufferProducer: %s (%d)", + ALOGE("setFrameTimelineInfo: failed to cast to IGraphicBufferProducer: %s (%d)", strerror(-err), -err); return err; } - int64_t frameTimelineVsyncId; - err = data.readInt64(&frameTimelineVsyncId); - if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed to read int64_t: %s (%d)", strerror(-err), - -err); - return err; - } - status_t result = setFrameTimelineVsync(surface, frameTimelineVsyncId); + FrameTimelineInfo frameTimelineInfo; + SAFE_PARCEL(frameTimelineInfo.read, data); + + status_t result = setFrameTimelineInfo(surface, frameTimelineInfo); reply->writeInt32(result); return NO_ERROR; } diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 180857185c..0ded9361bf 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -92,10 +92,8 @@ status_t FrameEventHistoryStats::readFromParcel(const Parcel* input) { return err; } -JankData::JankData() : - frameVsyncId(ISurfaceComposer::INVALID_VSYNC_ID), - jankType(JankType::None) { -} +JankData::JankData() + : frameVsyncId(FrameTimelineInfo::INVALID_VSYNC_ID), jankType(JankType::None) {} status_t JankData::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeInt64, frameVsyncId); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 2946aaed37..a4b054a5ff 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -63,7 +63,7 @@ layer_state_t::layer_state_t() shouldBeSeamless(true), fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0), - frameTimelineVsyncId(ISurfaceComposer::INVALID_VSYNC_ID), + frameTimelineInfo(), autoRefresh(false) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; @@ -151,7 +151,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeBool, shouldBeSeamless); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); - SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId); + SAFE_PARCEL(frameTimelineInfo.write, output); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeUint32, blurRegions.size()); @@ -270,7 +270,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); - SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId); + SAFE_PARCEL(frameTimelineInfo.read, input); SAFE_PARCEL(input.readBool, &autoRefresh); uint32_t numRegions = 0; @@ -537,15 +537,9 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameNumberChanged; frameNumber = other.frameNumber; } - if (other.what & eFrameTimelineVsyncChanged) { - // When merging vsync Ids we take the oldest valid one - if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID && - other.frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) { - frameTimelineVsyncId = std::max(frameTimelineVsyncId, other.frameTimelineVsyncId); - } else if (frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) { - frameTimelineVsyncId = other.frameTimelineVsyncId; - } - what |= eFrameTimelineVsyncChanged; + if (other.what & eFrameTimelineInfoChanged) { + what |= eFrameTimelineInfoChanged; + frameTimelineInfo.merge(other.frameTimelineInfo); } if (other.what & eAutoRefreshChanged) { what |= eAutoRefreshChanged; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e82f0cc9e9..59ad8d28bd 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1496,8 +1496,8 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER: res = dispatchGetLastQueuedBuffer(args); break; - case NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC: - res = dispatchSetFrameTimelineVsync(args); + case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO: + res = dispatchSetFrameTimelineInfo(args); break; default: res = NAME_NOT_FOUND; @@ -1806,12 +1806,13 @@ int Surface::dispatchGetLastQueuedBuffer(va_list args) { return result; } -int Surface::dispatchSetFrameTimelineVsync(va_list args) { +int Surface::dispatchSetFrameTimelineInfo(va_list args) { ATRACE_CALL(); auto frameTimelineVsyncId = static_cast(va_arg(args, int64_t)); + auto inputEventId = static_cast(va_arg(args, int32_t)); - ALOGV("Surface::dispatchSetFrameTimelineVsync"); - return setFrameTimelineVsync(frameTimelineVsyncId); + ALOGV("Surface::%s", __func__); + return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId}); } bool Surface::transformToDisplayInverse() { @@ -2579,9 +2580,8 @@ status_t Surface::setFrameRate(float frameRate, int8_t compatibility, bool shoul shouldBeSeamless); } -status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { - return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, - frameTimelineVsyncId); +status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { + return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo); } }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 96c099be23..a1bdc033b0 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -396,7 +396,7 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), - mFrameTimelineVsyncId(other.mFrameTimelineVsyncId), + mFrameTimelineInfo(other.mFrameTimelineInfo), mApplyToken(other.mApplyToken) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; @@ -427,7 +427,9 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const bool containsBuffer = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); - const int64_t frameTimelineVsyncId = parcel->readInt64(); + FrameTimelineInfo frameTimelineInfo; + SAFE_PARCEL(frameTimelineInfo.read, *parcel); + sp applyToken; parcel->readNullableStrongBinder(&applyToken); size_t count = static_cast(parcel->readUint32()); @@ -502,7 +504,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mContainsBuffer = containsBuffer; mDesiredPresentTime = desiredPresentTime; mIsAutoTimestamp = isAutoTimestamp; - mFrameTimelineVsyncId = frameTimelineVsyncId; + mFrameTimelineInfo = frameTimelineInfo; mDisplayStates = displayStates; mListenerCallbacks = listenerCallbacks; mComposerStates = composerStates; @@ -534,7 +536,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeBool(mContainsBuffer); parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); - parcel->writeInt64(mFrameTimelineVsyncId); + SAFE_PARCEL(mFrameTimelineInfo.write, *parcel); parcel->writeStrongBinder(mApplyToken); parcel->writeUint32(static_cast(mDisplayStates.size())); for (auto const& displayState : mDisplayStates) { @@ -613,13 +615,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd; mApplyToken = other.mApplyToken; - // When merging vsync Ids we take the oldest one - if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID && - other.mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) { - mFrameTimelineVsyncId = std::max(mFrameTimelineVsyncId, other.mFrameTimelineVsyncId); - } else if (mFrameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) { - mFrameTimelineVsyncId = other.mFrameTimelineVsyncId; - } + mFrameTimelineInfo.merge(other.mFrameTimelineInfo); other.clear(); return *this; @@ -639,7 +635,7 @@ void SurfaceComposerClient::Transaction::clear() { mExplicitEarlyWakeupEnd = false; mDesiredPresentTime = 0; mIsAutoTimestamp = true; - mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + mFrameTimelineInfo.clear(); mApplyToken = nullptr; } @@ -651,9 +647,8 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { uncacheBuffer.id = cacheId; sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, {}, {}, 0, applyToken, {}, - systemTime(), true, uncacheBuffer, false, {}, - 0 /* Undefined transactionId */); + sf->setTransactionState(FrameTimelineInfo{}, {}, {}, 0, applyToken, {}, systemTime(), true, + uncacheBuffer, false, {}, 0 /* Undefined transactionId */); } void SurfaceComposerClient::Transaction::cacheBuffers() { @@ -773,7 +768,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { ? mApplyToken : IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken, + sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/, hasListenerCallbacks, listenerCallbacks, mId); @@ -1549,22 +1544,22 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync( - int64_t frameTimelineVsyncId) { - mFrameTimelineVsyncId = frameTimelineVsyncId; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( + const FrameTimelineInfo& frameTimelineInfo) { + mFrameTimelineInfo = frameTimelineInfo; return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync( - const sp& sc, int64_t frameTimelineVsyncId) { +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( + const sp& sc, const FrameTimelineInfo& frameTimelineInfo) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } - s->what |= layer_state_t::eFrameTimelineVsyncChanged; - s->frameTimelineVsyncId = frameTimelineVsyncId; + s->what |= layer_state_t::eFrameTimelineInfoChanged; + s->frameTimelineInfo = frameTimelineInfo; return *this; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 7f69bc4244..fa3efe15db 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -92,7 +92,7 @@ public: void flushShadowQueue() { mFlushShadowQueue = true; } status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); - status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); + status_t setFrameTimelineInfo(const FrameTimelineInfo& info); virtual ~BLASTBufferQueue(); @@ -156,7 +156,7 @@ private: // This is only relevant for shared buffer mode. bool mAutoRefresh GUARDED_BY(mMutex) = false; - std::queue mNextFrameTimelineVsyncIdQueue GUARDED_BY(mMutex); + std::queue mNextFrameTimelineInfoQueue GUARDED_BY(mMutex); // Last acquired buffer's scaling mode. This is used to check if we should update the blast // layer size immediately or wait until we get the next buffer. This will support scenarios diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index 5587acf08f..f446dd88ed 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -25,7 +25,7 @@ struct VsyncEventData { // The Vsync Id corresponsing to this vsync event. This will be used to // populate ISurfaceComposer::setFrameTimelineVsync and // SurfaceComposerClient::setFrameTimelineVsync - int64_t id = ISurfaceComposer::INVALID_VSYNC_ID; + int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; // The deadline in CLOCK_MONOTONIC that the app needs to complete its // frame by (both on the CPU and the GPU) diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/include/gui/FrameTimelineInfo.h new file mode 100644 index 0000000000..3b4c009609 --- /dev/null +++ b/libs/gui/include/gui/FrameTimelineInfo.h @@ -0,0 +1,43 @@ +/* + * Copyright 2021 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 + +#include +#include + +namespace android { + +struct FrameTimelineInfo { + // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java + static constexpr int64_t INVALID_VSYNC_ID = -1; + + // The vsync id that was used to start the transaction + int64_t vsyncId = INVALID_VSYNC_ID; + + // The id of the input event that caused this buffer + int32_t inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; + + status_t write(Parcel& output) const; + status_t read(const Parcel& input); + + void merge(const FrameTimelineInfo& other); + void clear(); +}; + +} // namespace android diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 86f3c605ab..81ff6b0d8d 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -117,9 +118,6 @@ public: using EventRegistrationFlags = Flags; - // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java - static constexpr int64_t INVALID_VSYNC_ID = -1; - /* * Create a connection with SurfaceFlinger. */ @@ -164,7 +162,7 @@ public: /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual status_t setTransactionState( - int64_t frameTimelineVsyncId, const Vector& state, + const FrameTimelineInfo& frameTimelineInfo, const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, @@ -494,11 +492,11 @@ public: virtual status_t acquireFrameRateFlexibilityToken(sp* outToken) = 0; /* - * Sets the frame timeline vsync id received from choreographer that corresponds to next + * Sets the frame timeline vsync info received from choreographer that corresponds to next * buffer submitted on that surface. */ - virtual status_t setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) = 0; + virtual status_t setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) = 0; /* * Adds a TransactionTraceListener to listen for transaction tracing state updates. @@ -569,7 +567,7 @@ public: SET_GAME_CONTENT_TYPE, SET_FRAME_RATE, ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, - SET_FRAME_TIMELINE_VSYNC, + SET_FRAME_TIMELINE_INFO, ADD_TRANSACTION_TRACE_LISTENER, GET_GPU_CONTEXT_PRIORITY, // Always append new enum to the end. diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index b1305c6607..b3b074ad2f 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -132,7 +132,7 @@ struct layer_state_t { eProducerDisconnect = 0x100'00000000, eFixedTransformHintChanged = 0x200'00000000, eFrameNumberChanged = 0x400'00000000, - eFrameTimelineVsyncChanged = 0x800'00000000, + eFrameTimelineInfoChanged = 0x800'00000000, eBlurRegionsChanged = 0x1000'00000000, eAutoRefreshChanged = 0x2000'00000000, }; @@ -238,7 +238,7 @@ struct layer_state_t { // graphics producer. uint64_t frameNumber; - int64_t frameTimelineVsyncId; + FrameTimelineInfo frameTimelineInfo; // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 43b5dcd60d..b6b5c7ca5e 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -18,6 +18,7 @@ #define ANDROID_GUI_SURFACE_H #include +#include #include #include #include @@ -187,7 +188,7 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const; virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); - virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); + virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info); protected: virtual ~Surface(); @@ -273,7 +274,7 @@ private: int dispatchAddQueueInterceptor(va_list args); int dispatchAddQueryInterceptor(va_list args); int dispatchGetLastQueuedBuffer(va_list args); - int dispatchSetFrameTimelineVsync(va_list args); + int dispatchSetFrameTimelineInfo(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 11db658de2..bed5c44110 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -385,8 +385,8 @@ public: int64_t mDesiredPresentTime = 0; bool mIsAutoTimestamp = true; - // The vsync Id provided by Choreographer.getVsyncId - int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + // The vsync id provided by Choreographer.getVsyncId and the input event id + FrameTimelineInfo mFrameTimelineInfo; // If not null, transactions will be queued up using this token otherwise a common token // per process will be used. @@ -546,11 +546,12 @@ public: Transaction& setFixedTransformHint(const sp& sc, int32_t transformHint); // Sets the frame timeline vsync id received from choreographer that corresponds - // to the transaction. - Transaction& setFrameTimelineVsync(int64_t frameTimelineVsyncId); + // to the transaction, and the input event id that identifies the input event that caused + // the current frame. + Transaction& setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo); // Variant that only applies to a specific SurfaceControl. - Transaction& setFrameTimelineVsync(const sp& sc, - int64_t frameTimelineVsyncId); + Transaction& setFrameTimelineInfo(const sp& sc, + const FrameTimelineInfo& frameTimelineInfo); // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 63db9a7b96..3f7a5b1785 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -695,7 +695,7 @@ public: void destroyDisplay(const sp& /*display */) override {} std::vector getPhysicalDisplayIds() const override { return {}; } sp getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; } - status_t setTransactionState(int64_t /*frameTimelineVsyncId*/, + status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/, const Vector& /*state*/, const Vector& /*displays*/, uint32_t /*flags*/, const sp& /*applyToken*/, @@ -877,8 +877,8 @@ public: return NO_ERROR; } - status_t setFrameTimelineVsync(const sp& /*surface*/, - int64_t /*frameTimelineVsyncId*/) override { + status_t setFrameTimelineInfo(const sp& /*surface*/, + const FrameTimelineInfo& /*frameTimelineInfo*/) override { return NO_ERROR; } diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl index 6316b59a57..bce0ec8367 100644 --- a/libs/input/android/os/IInputConstants.aidl +++ b/libs/input/android/os/IInputConstants.aidl @@ -28,4 +28,13 @@ interface IInputConstants * to identify apps that are using this flag. */ const long BLOCK_FLAG_SLIPPERY = 157929241; + + // Indicate invalid battery capacity + const int INVALID_BATTERY_CAPACITY = -1; + + /** + * Every input event has an id. This constant value is used when a valid input event id is not + * available. + */ + const int INVALID_INPUT_EVENT_ID = 0; } diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 82d2e661b4..ffe4412b72 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -255,7 +255,7 @@ enum { NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */ NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */ NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */ - NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC = 48, /* private */ + NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO = 48, /* private */ // clang-format on }; @@ -1023,10 +1023,11 @@ static inline int native_window_set_frame_rate(struct ANativeWindow* window, flo (int)compatibility, (int)shouldBeSeamless); } -static inline int native_window_set_frame_timeline_vsync(struct ANativeWindow* window, - int64_t frameTimelineVsyncId) { - return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC, - frameTimelineVsyncId); +static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window, + int64_t frameTimelineVsyncId, + int32_t inputEventId) { + return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, + frameTimelineVsyncId, inputEventId); } // ------------------------------------------------------------------------------------------------ diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 32e6b1098f..52197873c5 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -384,8 +384,8 @@ status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) { return NO_ERROR; } -void BufferQueueLayer::setFrameTimelineVsyncForBuffer(int64_t frameTimelineVsyncId) { - mFrameTimelineVsyncId = frameTimelineVsyncId; +void BufferQueueLayer::setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) { + mFrameTimelineInfo = frameTimelineInfo; } // ----------------------------------------------------------------------- @@ -445,9 +445,8 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { } auto surfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineVsyncId, - mOwnerPid, mOwnerUid, mName, - mName); + mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid, + mOwnerUid, mName, mName); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems.push_back({item, surfaceFrame}); @@ -485,9 +484,8 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { } auto surfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineVsyncId, - mOwnerPid, mOwnerUid, mName, - mName); + mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid, + mOwnerUid, mName, mName); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems[mQueueItems.size() - 1].item = item; mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame); diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 0e8fdbe092..41ff01262e 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -101,7 +101,7 @@ private: status_t updateActiveBuffer() override; status_t updateFrameNumber(nsecs_t latchTime) override; - void setFrameTimelineVsyncForBuffer(int64_t frameTimelineVsyncId) override; + void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) override; sp createClone() override; @@ -145,10 +145,10 @@ private: sp mContentsChangedListener; - // The last vsync id received on this layer. This will be used when we get + // The last vsync info received on this layer. This will be used when we get // a buffer to correlate the buffer with the vsync id. Can only be accessed // with the SF state lock held. - std::optional mFrameTimelineVsyncId; + FrameTimelineInfo mFrameTimelineInfo; // Keeps track of the time SF latched the last buffer from this layer. // Used in buffer stuffing analysis in FrameTimeline. diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 17d1f3bff7..3743716876 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -275,13 +275,15 @@ int64_t TraceCookieCounter::getCookieForTracing() { return ++mTraceCookie; } -SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName, - std::string debugName, PredictionState predictionState, +SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, + uid_t ownerUid, std::string layerName, std::string debugName, + PredictionState predictionState, frametimeline::TimelineItem&& predictions, std::shared_ptr timeStats, JankClassificationThresholds thresholds, TraceCookieCounter* traceCookieCounter) - : mToken(token), + : mToken(frameTimelineInfo.vsyncId), + mInputEventId(frameTimelineInfo.inputEventId), mOwnerPid(ownerPid), mOwnerUid(ownerUid), mLayerName(std::move(layerName)), @@ -295,27 +297,27 @@ SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::s mTraceCookieCounter(*traceCookieCounter) {} void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mActuals.startTime = actualStartTime; } void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mActualQueueTime = actualQueueTime; } void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime); } void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mPresentState = presentState; mLastLatchTime = lastLatchTime; } std::optional SurfaceFrame::getJankType() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); if (mActuals.presentTime == 0) { return std::nullopt; } @@ -323,32 +325,32 @@ std::optional SurfaceFrame::getJankType() const { } nsecs_t SurfaceFrame::getBaseTime() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return getMinTime(mPredictionState, mPredictions, mActuals); } TimelineItem SurfaceFrame::getActuals() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mActuals; } SurfaceFrame::PresentState SurfaceFrame::getPresentState() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mPresentState; } FramePresentMetadata SurfaceFrame::getFramePresentMetadata() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mFramePresentMetadata; } FrameReadyMetadata SurfaceFrame::getFrameReadyMetadata() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mFrameReadyMetadata; } void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); StringAppendF(&result, "%s", indent.c_str()); StringAppendF(&result, "Layer - %s", mDebugName.c_str()); if (mJankType != JankType::None) { @@ -387,7 +389,7 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, nsecs_t vsyncPeriod) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); if (mPresentState != PresentState::Presented) { // No need to update dropped buffers return; @@ -479,6 +481,9 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType); } +/** + * TODO(b/178637512): add inputEventId to the perfetto trace. + */ void SurfaceFrame::trace(int64_t displayFrameToken) { using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource; @@ -486,12 +491,12 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { bool missingToken = false; // Expected timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); - if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) { + std::scoped_lock lock(mMutex); + if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) { ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str()); missingToken = true; return; - } else if (displayFrameToken == ISurfaceComposer::INVALID_VSYNC_ID) { + } else if (displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) { ALOGD("Cannot trace SurfaceFrame - %s with invalid displayFrameToken", mLayerName.c_str()); missingToken = true; @@ -521,7 +526,7 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { // Expected timeline end FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(static_cast(mPredictions.endTime)); @@ -535,7 +540,7 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing(); // Actual timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); // Actual start time is not yet available, so use expected start instead @@ -566,7 +571,7 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { }); // Actual timeline end FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(static_cast(mActuals.endTime)); @@ -582,7 +587,7 @@ namespace impl { int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); const int64_t assignedToken = mCurrentToken++; mPredictions[assignedToken] = {systemTime(), predictions}; flushTokens(systemTime()); @@ -590,7 +595,7 @@ int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { } std::optional TokenManager::getPredictionsForToken(int64_t token) const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto predictionsIterator = mPredictions.find(token); if (predictionsIterator != mPredictions.end()) { return predictionsIterator->second.predictions; @@ -634,26 +639,28 @@ void FrameTimeline::registerDataSource() { } std::shared_ptr FrameTimeline::createSurfaceFrameForToken( - std::optional token, pid_t ownerPid, uid_t ownerUid, std::string layerName, - std::string debugName) { + const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName) { ATRACE_CALL(); - if (!token) { - return std::make_shared(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid, - ownerUid, std::move(layerName), std::move(debugName), + if (frameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { + return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, + std::move(layerName), std::move(debugName), PredictionState::None, TimelineItem(), mTimeStats, mJankClassificationThresholds, &mTraceCookieCounter); } - std::optional predictions = mTokenManager.getPredictionsForToken(*token); + std::optional predictions = + mTokenManager.getPredictionsForToken(frameTimelineInfo.vsyncId); if (predictions) { - return std::make_shared(*token, ownerPid, ownerUid, std::move(layerName), - std::move(debugName), PredictionState::Valid, - std::move(*predictions), mTimeStats, - mJankClassificationThresholds, &mTraceCookieCounter); - } - return std::make_shared(*token, ownerPid, ownerUid, std::move(layerName), - std::move(debugName), PredictionState::Expired, - TimelineItem(), mTimeStats, mJankClassificationThresholds, - &mTraceCookieCounter); + return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, + std::move(layerName), std::move(debugName), + PredictionState::Valid, std::move(*predictions), + mTimeStats, mJankClassificationThresholds, + &mTraceCookieCounter); + } + return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, + std::move(layerName), std::move(debugName), + PredictionState::Expired, TimelineItem(), mTimeStats, + mJankClassificationThresholds, &mTraceCookieCounter); } FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr timeStats, @@ -669,13 +676,13 @@ FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr timeStats, void FrameTimeline::addSurfaceFrame(std::shared_ptr surfaceFrame) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame); } void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod, mTokenManager.getPredictionsForToken(token), wakeUpTime); } @@ -683,7 +690,7 @@ void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsync void FrameTimeline::setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr& presentFence) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mCurrentDisplayFrame->setActualEndTime(sfPresentTime); mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame)); flushPendingPresentFences(); @@ -826,7 +833,7 @@ void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const { // Expected timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { auto packet = ctx.NewTracePacket(); - if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) { + if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) { ALOGD("Cannot trace DisplayFrame with invalid token"); missingToken = true; return; @@ -999,7 +1006,7 @@ void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) co } void FrameTimeline::dumpAll(std::string& result) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size()); nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime(); for (size_t i = 0; i < mDisplayFrames.size(); i++) { @@ -1009,7 +1016,7 @@ void FrameTimeline::dumpAll(std::string& result) { } void FrameTimeline::dumpJank(std::string& result) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime(); for (size_t i = 0; i < mDisplayFrames.size(); i++) { mDisplayFrames[i]->dumpJank(result, baseTime, static_cast(i)); @@ -1031,7 +1038,7 @@ void FrameTimeline::parseArgs(const Vector& args, std::string& result) } void FrameTimeline::setMaxDisplayFrames(uint32_t size) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); // The size can either increase or decrease, clear everything, to be consistent mDisplayFrames.clear(); diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index ed38cc6375..54e8efbc92 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -154,10 +154,10 @@ public: // Only FrameTimeline can construct a SurfaceFrame as it provides Predictions(through // TokenManager), Thresholds and TimeStats pointer. - SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName, - std::string debugName, PredictionState predictionState, TimelineItem&& predictions, - std::shared_ptr timeStats, JankClassificationThresholds thresholds, - TraceCookieCounter* traceCookieCounter); + SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName, PredictionState predictionState, + TimelineItem&& predictions, std::shared_ptr timeStats, + JankClassificationThresholds thresholds, TraceCookieCounter* traceCookieCounter); ~SurfaceFrame() = default; // Returns std::nullopt if the frame hasn't been classified yet. @@ -166,6 +166,7 @@ public: // Functions called by SF int64_t getToken() const { return mToken; }; + int32_t getInputEventId() const { return mInputEventId; }; TimelineItem getPredictions() const { return mPredictions; }; // Actual timestamps of the app are set individually at different functions. // Start time (if the app provides) and Queue time are accessible after queueing the frame, @@ -198,6 +199,7 @@ public: private: const int64_t mToken; + const int32_t mInputEventId; const pid_t mOwnerPid; const uid_t mOwnerUid; const std::string mLayerName; @@ -243,10 +245,9 @@ public: // Create a new surface frame, set the predictions based on a token and return it to the caller. // Debug name is the human-readable debugging string for dumpsys. - virtual std::shared_ptr createSurfaceFrameForToken(std::optional token, - pid_t ownerPid, uid_t ownerUid, - std::string layerName, - std::string debugName) = 0; + virtual std::shared_ptr createSurfaceFrameForToken( + const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName) = 0; // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be // composited into one display frame. @@ -279,7 +280,7 @@ namespace impl { class TokenManager : public android::frametimeline::TokenManager { public: - TokenManager() : mCurrentToken(ISurfaceComposer::INVALID_VSYNC_ID + 1) {} + TokenManager() : mCurrentToken(FrameTimelineInfo::INVALID_VSYNC_ID + 1) {} ~TokenManager() = default; int64_t generateTokenForPredictions(TimelineItem&& predictions) override; @@ -353,7 +354,7 @@ public: private: void dump(std::string& result, nsecs_t baseTime) const; - int64_t mToken = ISurfaceComposer::INVALID_VSYNC_ID; + int64_t mToken = FrameTimelineInfo::INVALID_VSYNC_ID; /* Usage of TimelineItem w.r.t SurfaceFlinger * startTime Time when SurfaceFlinger wakes up to handle transactions and buffer updates @@ -393,10 +394,9 @@ public: ~FrameTimeline() = default; frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } - std::shared_ptr createSurfaceFrameForToken(std::optional token, - pid_t ownerPid, uid_t ownerUid, - std::string layerName, - std::string debugName) override; + std::shared_ptr createSurfaceFrameForToken( + const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName) override; void addSurfaceFrame(std::shared_ptr surfaceFrame) override; void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) override; void setSfPresent(nsecs_t sfPresentTime, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 177a81a7bc..f6440d3843 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -129,7 +129,7 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.shadowRadius = 0.f; mCurrentState.treeHasFrameRateVote = false; mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID; - mCurrentState.frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + mCurrentState.frameTimelineInfo = {}; mCurrentState.postTime = -1; if (args.flags & ISurfaceComposerClient::eNoColorFill) { @@ -907,14 +907,10 @@ bool Layer::applyPendingStates(State* stateToCommit) { } if (stateUpdateAvailable) { - const auto vsyncId = - stateToCommit->frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID - ? std::nullopt - : std::make_optional(stateToCommit->frameTimelineVsyncId); - mSurfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(vsyncId, mOwnerPid, mOwnerUid, - mName, mTransactionName); + mFlinger->mFrameTimeline + ->createSurfaceFrameForToken(stateToCommit->frameTimelineInfo, mOwnerPid, + mOwnerUid, mName, mTransactionName); mSurfaceFrame->setActualQueueTime(stateToCommit->postTime); // For transactions we set the acquire fence time to the post time as we // don't have a buffer. For BufferStateLayer it is overridden in @@ -1491,8 +1487,8 @@ bool Layer::setFrameRate(FrameRate frameRate) { return true; } -void Layer::setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime) { - mCurrentState.frameTimelineVsyncId = frameTimelineVsyncId; +void Layer::setFrameTimelineInfoForTransaction(const FrameTimelineInfo& info, nsecs_t postTime) { + mCurrentState.frameTimelineInfo = info; mCurrentState.postTime = postTime; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 357c4a4dee..0660a4a998 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -304,8 +304,8 @@ public: // a fixed transform hint is not set. ui::Transform::RotationFlags fixedTransformHint; - // The vsync id that was used to start the transaction - int64_t frameTimelineVsyncId; + // The vsync info that was used to start the transaction + FrameTimelineInfo frameTimelineInfo; // When the transaction was posted nsecs_t postTime; @@ -869,8 +869,9 @@ public: bool setFrameRate(FrameRate); - virtual void setFrameTimelineVsyncForBuffer(int64_t /*frameTimelineVsyncId*/) {} - void setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime); + virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {} + void setFrameTimelineInfoForTransaction(const FrameTimelineInfo& frameTimelineInfo, + nsecs_t postTime); // Creates a new handle each time, so we only expect // this to be called once. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 27df232472..8d448e0910 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3287,7 +3287,7 @@ bool SurfaceFlinger::flushTransactionQueues() { break; } transactions.push_back(transaction); - applyTransactionState(transaction.frameTimelineVsyncId, transaction.states, + applyTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, mPendingInputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, transaction.buffer, @@ -3367,7 +3367,7 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(bool isAutoTimestamp, int64_t } status_t SurfaceFlinger::setTransactionState( - int64_t frameTimelineVsyncId, const Vector& states, + const FrameTimelineInfo& frameTimelineInfo, const Vector& states, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, @@ -3420,7 +3420,7 @@ status_t SurfaceFlinger::setTransactionState( // if the transaction contains a buffer. if (!transactionIsReadyToBeApplied(isAutoTimestamp, desiredPresentTime, states, true) || pendingTransactions) { - mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags, + mTransactionQueues[applyToken].emplace(frameTimelineInfo, states, displays, flags, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, @@ -3429,7 +3429,7 @@ status_t SurfaceFlinger::setTransactionState( return NO_ERROR; } - applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands, + applyTransactionState(frameTimelineInfo, states, displays, flags, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, transactionId, /*isMainThread*/ false); @@ -3437,7 +3437,7 @@ status_t SurfaceFlinger::setTransactionState( } void SurfaceFlinger::applyTransactionState( - int64_t frameTimelineVsyncId, const Vector& states, + const FrameTimelineInfo& frameTimelineInfo, const Vector& states, const Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime, @@ -3478,9 +3478,9 @@ void SurfaceFlinger::applyTransactionState( uint32_t clientStateFlags = 0; for (const ComposerState& state : states) { clientStateFlags |= - setClientStateLocked(frameTimelineVsyncId, state, desiredPresentTime, - isAutoTimestamp, postTime, privileged, - listenerCallbacksWithSurfaces, originPid, originUid); + setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp, + postTime, privileged, listenerCallbacksWithSurfaces, originPid, + originUid); if ((flags & eAnimation) && state.state.surface) { if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) { mScheduler->recordLayerHistory(layer.get(), @@ -3658,7 +3658,7 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermis } uint32_t SurfaceFlinger::setClientStateLocked( - int64_t frameTimelineVsyncId, const ComposerState& composerState, + const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged, std::unordered_set& listenerCallbacks, int originPid, int originUid) { @@ -3916,10 +3916,10 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } - if (what & layer_state_t::eFrameTimelineVsyncChanged) { - layer->setFrameTimelineVsyncForTransaction(s.frameTimelineVsyncId, postTime); - } else if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) { - layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime); + if (what & layer_state_t::eFrameTimelineInfoChanged) { + layer->setFrameTimelineInfoForTransaction(s.frameTimelineInfo, postTime); + } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { + layer->setFrameTimelineInfoForTransaction(frameTimelineInfo, postTime); } if (what & layer_state_t::eFixedTransformHintChanged) { if (layer->setFixedTransformHint(s.fixedTransformHint)) { @@ -4255,7 +4255,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); - setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr, + setTransactionState(FrameTimelineInfo{}, state, displays, 0, nullptr, mPendingInputWindowCommands, systemTime(), true, {}, false, {}, 0 /* Undefined transactionId */); @@ -5006,7 +5006,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case CAPTURE_LAYERS: case CAPTURE_DISPLAY: case SET_DISPLAY_BRIGHTNESS: - case SET_FRAME_TIMELINE_VSYNC: + case SET_FRAME_TIMELINE_INFO: // This is not sensitive information, so should not require permission control. case GET_GPU_CONTEXT_PRIORITY: { return OK; @@ -6374,21 +6374,21 @@ void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() { })); } -status_t SurfaceFlinger::setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) { +status_t SurfaceFlinger::setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) { Mutex::Autolock lock(mStateLock); if (!authenticateSurfaceTextureLocked(surface)) { - ALOGE("Attempt to set frame timeline vsync on an unrecognized IGraphicBufferProducer"); + ALOGE("Attempt to set frame timeline info on an unrecognized IGraphicBufferProducer"); return BAD_VALUE; } sp layer = (static_cast(surface.get()))->getLayer(); if (layer == nullptr) { - ALOGE("Attempt to set frame timeline vsync on a layer that no longer exists"); + ALOGE("Attempt to set frame timeline info on a layer that no longer exists"); return BAD_VALUE; } - layer->setFrameTimelineVsyncForBuffer(frameTimelineVsyncId); + layer->setFrameTimelineInfoForBuffer(frameTimelineInfo); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 50d6099698..323ed40e36 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -343,7 +343,7 @@ protected: virtual ~SurfaceFlinger(); virtual uint32_t setClientStateLocked( - int64_t frameTimelineVsyncId, const ComposerState& composerState, + const FrameTimelineInfo& info, const ComposerState& composerState, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged, std::unordered_set& listenerCallbacks, int originPid, int originUid) REQUIRES(mStateLock); @@ -435,14 +435,15 @@ private: }; struct TransactionState { - TransactionState(int64_t frameTimelineVsyncId, const Vector& composerStates, + TransactionState(const FrameTimelineInfo& frameTimelineInfo, + const Vector& composerStates, const Vector& displayStates, uint32_t transactionFlags, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, std::vector listenerCallbacks, int originPid, int originUid, uint64_t transactionId) - : frameTimelineVsyncId(frameTimelineVsyncId), + : frameTimelineInfo(frameTimelineInfo), states(composerStates), displays(displayStates), flags(transactionFlags), @@ -457,7 +458,7 @@ private: originUid(originUid), id(transactionId) {} - int64_t frameTimelineVsyncId; + FrameTimelineInfo frameTimelineInfo; Vector states; Vector displays; uint32_t flags; @@ -522,7 +523,8 @@ private: void destroyDisplay(const sp& displayToken) override; std::vector getPhysicalDisplayIds() const override; sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const override; - status_t setTransactionState(int64_t frameTimelineVsyncId, const Vector& state, + status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, + const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, @@ -608,8 +610,8 @@ private: int8_t compatibility, bool shouldBeSeamless) override; status_t acquireFrameRateFlexibilityToken(sp* outToken) override; - status_t setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) override; + status_t setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) override; status_t addTransactionTraceListener( const sp& listener) override; @@ -727,7 +729,7 @@ private: /* * Transactions */ - void applyTransactionState(int64_t frameTimelineVsyncId, const Vector& state, + void applyTransactionState(const FrameTimelineInfo& info, const Vector& state, const Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp index 93d5f2f8ec..80dbd1b889 100644 --- a/services/surfaceflinger/tests/LayerState_test.cpp +++ b/services/surfaceflinger/tests/LayerState_test.cpp @@ -106,5 +106,34 @@ TEST(LayerStateTest, ParcellingScreenCaptureResults) { ASSERT_EQ(results.result, results2.result); } +/** + * Parcel a layer_state_t struct, and then unparcel. Ensure that the object that was parceled + * matches the object that's unparceled. + */ +TEST(LayerStateTest, ParcelUnparcelLayerStateT) { + layer_state_t input; + input.frameTimelineInfo.vsyncId = 1; + input.frameTimelineInfo.inputEventId = 2; + Parcel p; + input.write(p); + layer_state_t output; + p.setDataPosition(0); + output.read(p); + ASSERT_EQ(input.frameTimelineInfo.vsyncId, output.frameTimelineInfo.vsyncId); + ASSERT_EQ(input.frameTimelineInfo.inputEventId, output.frameTimelineInfo.inputEventId); +} + +TEST(LayerStateTest, LayerStateMerge_SelectsValidInputEvent) { + layer_state_t layer1; + layer1.frameTimelineInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; + layer_state_t layer2; + layer2.frameTimelineInfo.inputEventId = 1; + layer2.what |= layer_state_t::eFrameTimelineInfoChanged; + + layer1.merge(layer2); + + ASSERT_EQ(1, layer1.frameTimelineInfo.inputEventId); +} + } // namespace test } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index e2584e266d..6e9f09bdaa 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -14,9 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra" #include "gmock/gmock-spec-builders.h" #include "mock/MockTimeStats.h" @@ -177,16 +174,17 @@ static const std::string sLayerNameTwo = "layer2"; static constexpr const uid_t sUidOne = 0; static constexpr pid_t sPidOne = 10; static constexpr pid_t sPidTwo = 20; +static constexpr int32_t sInputEventId = 5; TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); - EXPECT_EQ(getPredictions().size(), 1); + EXPECT_EQ(getPredictions().size(), 1u); flushTokens(systemTime() + maxTokenRetentionTime); int64_t token2 = mTokenManager->generateTokenForPredictions({10, 20, 30}); std::optional predictions = mTokenManager->getPredictionsForToken(token1); // token1 should have expired - EXPECT_EQ(getPredictions().size(), 1); + EXPECT_EQ(getPredictions().size(), 1u); EXPECT_EQ(predictions.has_value(), false); predictions = mTokenManager->getPredictionsForToken(token2); @@ -194,16 +192,16 @@ TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { } TEST_F(FrameTimelineTest, createSurfaceFrameForToken_getOwnerPidReturnsCorrectPid) { - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, + auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); - auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidTwo, sUidOne, + auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({}, sPidTwo, sUidOne, sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame1->getOwnerPid(), sPidOne); EXPECT_EQ(surfaceFrame2->getOwnerPid(), sPidTwo); } TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, + auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::None); } @@ -211,21 +209,33 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); flushTokens(systemTime() + maxTokenRetentionTime); - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired); } TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid); EXPECT_EQ(compareTimelineItems(surfaceFrame->getPredictions(), TimelineItem(10, 20, 30)), true); } +TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) { + int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + constexpr int32_t inputEventId = 1; + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({token1, inputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); + + EXPECT_EQ(inputEventId, surfaceFrame->getInputEventId()); +} + TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { // Global increment EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); @@ -234,8 +244,9 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, 11); @@ -264,11 +275,11 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 60}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameTwo, sLayerNameTwo); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameTwo, sLayerNameTwo); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -288,8 +299,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame3 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame3); @@ -320,8 +331,9 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { int64_t sfToken = mTokenManager->generateTokenForPredictions( {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor}); auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, + sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -341,8 +353,8 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { int64_t sfToken = mTokenManager->generateTokenForPredictions( {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor}); auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -356,18 +368,18 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { } TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceAfterQueue) { - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, 0, - "acquireFenceAfterQueue", - "acquireFenceAfterQueue"); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, "acquireFenceAfterQueue", + "acquireFenceAfterQueue"); surfaceFrame->setActualQueueTime(123); surfaceFrame->setAcquireFenceTime(456); EXPECT_EQ(surfaceFrame->getActuals().endTime, 456); } TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) { - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, 0, - "acquireFenceAfterQueue", - "acquireFenceAfterQueue"); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, "acquireFenceAfterQueue", + "acquireFenceAfterQueue"); surfaceFrame->setActualQueueTime(456); surfaceFrame->setAcquireFenceTime(123); EXPECT_EQ(surfaceFrame->getActuals().endTime, 456); @@ -383,8 +395,8 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Size shouldn't exceed maxDisplayFrames - 64 for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -395,15 +407,15 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Increase the size to 256 mFrameTimeline->setMaxDisplayFrames(256); - EXPECT_EQ(*maxDisplayFrames, 256); + EXPECT_EQ(*maxDisplayFrames, 256u); // Global increment EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)) .Times(static_cast(*maxDisplayFrames + 10)); for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -414,15 +426,15 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Shrink the size to 128 mFrameTimeline->setMaxDisplayFrames(128); - EXPECT_EQ(*maxDisplayFrames, 128); + EXPECT_EQ(*maxDisplayFrames, 128u); // Global increment EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)) .Times(static_cast(*maxDisplayFrames + 10)); for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -449,8 +461,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { std::chrono::duration_cast(56ms).count(), std::chrono::duration_cast(60ms).count()}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast(52ms).count(), 11); @@ -478,8 +490,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { std::chrono::duration_cast(56ms).count(), std::chrono::duration_cast(60ms).count()}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast(52ms).count(), 30); @@ -507,8 +519,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { std::chrono::duration_cast(86ms).count(), std::chrono::duration_cast(90ms).count()}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, @@ -542,8 +554,9 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, 11); @@ -558,7 +571,7 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { mFrameTimeline->setSfPresent(55, presentFence2); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 0); + EXPECT_EQ(packets.size(), 0u); } TEST_F(FrameTimelineTest, tracing_sanityTest) { @@ -573,8 +586,9 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { tracingSession->StartBlocking(); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); // Set up the display frame mFrameTimeline->setSfWakeUp(token2, 20, 11); @@ -594,7 +608,7 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); // Display Frame 1 has 8 packets - 4 from DisplayFrame and 4 from SurfaceFrame. - EXPECT_EQ(packets.size(), 8); + EXPECT_EQ(packets.size(), 8u); } TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) { @@ -622,7 +636,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) tracingSession->StopBlocking(); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 0); + EXPECT_EQ(packets.size(), 0u); } TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) { @@ -635,7 +649,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) tracingSession->StartBlocking(); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, + auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); // Set up the display frame @@ -657,7 +671,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); // Display Frame 1 has 4 packets (SurfaceFrame shouldn't be traced since it has an invalid // token). - EXPECT_EQ(packets.size(), 4); + EXPECT_EQ(packets.size(), 4u); } void validateTraceEvent(const ProtoExpectedDisplayFrameStart& received, @@ -791,12 +805,12 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { tracingSession->StopBlocking(); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 4); + EXPECT_EQ(packets.size(), 4u); // Packet - 0 : ExpectedDisplayFrameStart const auto& packet0 = packets[0]; ASSERT_TRUE(packet0.has_timestamp()); - EXPECT_EQ(packet0.timestamp(), 10); + EXPECT_EQ(packet0.timestamp(), 10u); ASSERT_TRUE(packet0.has_frame_timeline_event()); const auto& event0 = packet0.frame_timeline_event(); @@ -807,7 +821,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { // Packet - 1 : FrameEnd (ExpectedDisplayFrame) const auto& packet1 = packets[1]; ASSERT_TRUE(packet1.has_timestamp()); - EXPECT_EQ(packet1.timestamp(), 25); + EXPECT_EQ(packet1.timestamp(), 25u); ASSERT_TRUE(packet1.has_frame_timeline_event()); const auto& event1 = packet1.frame_timeline_event(); @@ -818,7 +832,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { // Packet - 2 : ActualDisplayFrameStart const auto& packet2 = packets[2]; ASSERT_TRUE(packet2.has_timestamp()); - EXPECT_EQ(packet2.timestamp(), 20); + EXPECT_EQ(packet2.timestamp(), 20u); ASSERT_TRUE(packet2.has_frame_timeline_event()); const auto& event2 = packet2.frame_timeline_event(); @@ -829,7 +843,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { // Packet - 3 : FrameEnd (ActualDisplayFrame) const auto& packet3 = packets[3]; ASSERT_TRUE(packet3.has_timestamp()); - EXPECT_EQ(packet3.timestamp(), 26); + EXPECT_EQ(packet3.timestamp(), 26u); ASSERT_TRUE(packet3.has_frame_timeline_event()); const auto& event3 = packet3.frame_timeline_event(); @@ -853,8 +867,8 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setActualStartTime(0); surfaceFrame1->setActualQueueTime(15); surfaceFrame1->setAcquireFenceTime(20); @@ -904,12 +918,12 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { tracingSession->StopBlocking(); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 8); + EXPECT_EQ(packets.size(), 8u); // Packet - 4 : ExpectedSurfaceFrameStart const auto& packet4 = packets[4]; ASSERT_TRUE(packet4.has_timestamp()); - EXPECT_EQ(packet4.timestamp(), 10); + EXPECT_EQ(packet4.timestamp(), 10u); ASSERT_TRUE(packet4.has_frame_timeline_event()); const auto& event4 = packet4.frame_timeline_event(); @@ -920,7 +934,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Packet - 5 : FrameEnd (ExpectedSurfaceFrame) const auto& packet5 = packets[5]; ASSERT_TRUE(packet5.has_timestamp()); - EXPECT_EQ(packet5.timestamp(), 25); + EXPECT_EQ(packet5.timestamp(), 25u); ASSERT_TRUE(packet5.has_frame_timeline_event()); const auto& event5 = packet5.frame_timeline_event(); @@ -931,7 +945,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Packet - 6 : ActualSurfaceFrameStart const auto& packet6 = packets[6]; ASSERT_TRUE(packet6.has_timestamp()); - EXPECT_EQ(packet6.timestamp(), 10); + EXPECT_EQ(packet6.timestamp(), 10u); ASSERT_TRUE(packet6.has_frame_timeline_event()); const auto& event6 = packet6.frame_timeline_event(); @@ -942,7 +956,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Packet - 7 : FrameEnd (ActualSurfaceFrame) const auto& packet7 = packets[7]; ASSERT_TRUE(packet7.has_timestamp()); - EXPECT_EQ(packet7.timestamp(), 20); + EXPECT_EQ(packet7.timestamp(), 20u); ASSERT_TRUE(packet7.has_frame_timeline_event()); const auto& event7 = packet7.frame_timeline_event(); @@ -961,8 +975,8 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30}); auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -1126,8 +1140,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1145,8 +1159,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1199,8 +1213,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1218,8 +1232,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1270,8 +1284,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 42, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1316,8 +1330,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 30}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 50}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(26); mFrameTimeline->setSfWakeUp(sfToken1, 32, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1335,8 +1349,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken2, 43, 11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1390,8 +1404,8 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 56, 60}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 116, 120}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, 30); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1409,8 +1423,8 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(84); mFrameTimeline->setSfWakeUp(sfToken2, 112, 30); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54); @@ -1456,6 +1470,3 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli JankType::AppDeadlineMissed | JankType::BufferStuffing); } } // namespace android::frametimeline - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 2701f472aa..8ca052f710 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -368,16 +368,14 @@ public: auto& getTransactionQueue() { return mFlinger->mTransactionQueues; } - auto setTransactionState(int64_t frameTimelineVsyncId, const Vector& states, - const Vector& displays, uint32_t flags, - const sp& applyToken, - const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, - std::vector& listenerCallbacks, - uint64_t transactionId) { - return mFlinger->setTransactionState(frameTimelineVsyncId, states, displays, flags, - applyToken, inputWindowCommands, desiredPresentTime, + auto setTransactionState( + const FrameTimelineInfo& frameTimelineInfo, const Vector& states, + const Vector& displays, uint32_t flags, const sp& applyToken, + const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, + bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, + std::vector& listenerCallbacks, uint64_t transactionId) { + return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken, + inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, hasListenerCallbacks, listenerCallbacks, transactionId); } diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 06275c6b5b..6d2f672bce 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "CompositionTest" @@ -100,43 +96,44 @@ public: InputWindowCommands inputWindowCommands; int64_t desiredPresentTime = 0; bool isAutoTimestamp = true; - int64_t frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + FrameTimelineInfo frameTimelineInfo; client_cache_t uncacheBuffer; - int64_t id = -1; + uint64_t id = static_cast(-1); + static_assert(0xffffffffffffffff == static_cast(-1)); }; void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) { - EXPECT_EQ(0, info.states.size()); - EXPECT_EQ(0, state.states.size()); + EXPECT_EQ(0u, info.states.size()); + EXPECT_EQ(0u, state.states.size()); - EXPECT_EQ(0, info.displays.size()); - EXPECT_EQ(0, state.displays.size()); + EXPECT_EQ(0u, info.displays.size()); + EXPECT_EQ(0u, state.displays.size()); EXPECT_EQ(info.flags, state.flags); EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime); } void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows, int64_t desiredPresentTime, bool isAutoTimestamp, - int64_t frameTimelineVsyncId) { + const FrameTimelineInfo& frameTimelineInfo) { mTransactionNumber++; transaction.flags |= flags; // ISurfaceComposer::eSynchronous; transaction.inputWindowCommands.syncInputWindows = syncInputWindows; transaction.desiredPresentTime = desiredPresentTime; transaction.isAutoTimestamp = isAutoTimestamp; - transaction.frameTimelineVsyncId = frameTimelineVsyncId; + transaction.frameTimelineInfo = frameTimelineInfo; } void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime())); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - ISurfaceComposer::INVALID_VSYNC_ID); + FrameTimelineInfo{}); nsecs_t applicationTime = systemTime(); - mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states, + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, transaction.applyToken, transaction.inputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, @@ -155,11 +152,11 @@ public: EXPECT_LE(returnedTime, applicationTime + s2ns(5)); } auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(0, transactionQueue.size()); + EXPECT_EQ(0u, transactionQueue.size()); } void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); @@ -170,10 +167,9 @@ public: .WillOnce(Return(time + nsecs_t(5 * 1e8))); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, - /*desiredPresentTime*/ time + s2ns(1), false, - ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); - mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states, + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, transaction.applyToken, transaction.inputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, @@ -184,11 +180,11 @@ public: EXPECT_LE(returnedTime, applicationSentTime + s2ns(5)); // This transaction should have been placed on the transaction queue auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(1, transactionQueue.size()); + EXPECT_EQ(1u, transactionQueue.size()); } void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction nsecs_t time = systemTime(); EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); @@ -197,18 +193,17 @@ public: // transaction that should go on the pending thread TransactionInfo transactionA; setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ time + s2ns(1), false, - ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); // transaction that would not have gone on the pending thread if not // blocked TransactionInfo transactionB; setupSingle(transactionB, flags, syncInputWindows, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - ISurfaceComposer::INVALID_VSYNC_ID); + FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); - mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states, + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, transactionA.isAutoTimestamp, @@ -221,7 +216,7 @@ public: EXPECT_LE(systemTime(), applicationSentTime + s2ns(5)); applicationSentTime = systemTime(); - mFlinger.setTransactionState(transactionB.frameTimelineVsyncId, transactionB.states, + mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, transactionB.displays, transactionB.flags, transactionB.applyToken, transactionB.inputWindowCommands, transactionB.desiredPresentTime, transactionB.isAutoTimestamp, @@ -240,10 +235,10 @@ public: // check that there is one binder on the pending queue. auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(1, transactionQueue.size()); + EXPECT_EQ(1u, transactionQueue.size()); auto& [applyToken, transactionStates] = *(transactionQueue.begin()); - EXPECT_EQ(2, transactionStates.size()); + EXPECT_EQ(2u, transactionStates.size()); auto& transactionStateA = transactionStates.front(); transactionStates.pop(); @@ -258,7 +253,7 @@ public: }; TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); @@ -268,18 +263,18 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { .WillOnce(Return(s2ns(2))); TransactionInfo transactionA; // transaction to go on pending queue setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ s2ns(1), false, ISurfaceComposer::INVALID_VSYNC_ID); - mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states, + /*desiredPresentTime*/ s2ns(1), false, FrameTimelineInfo{}); + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, transactionA.isAutoTimestamp, transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, transactionA.id); auto& transactionQueue = mFlinger.getTransactionQueue(); - ASSERT_EQ(1, transactionQueue.size()); + ASSERT_EQ(1u, transactionQueue.size()); auto& [applyToken, transactionStates] = *(transactionQueue.begin()); - ASSERT_EQ(1, transactionStates.size()); + ASSERT_EQ(1u, transactionStates.size()); auto& transactionState = transactionStates.front(); checkEqual(transactionA, transactionState); @@ -289,8 +284,8 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { // different process) to re-query and reset the cached expected present time TransactionInfo empty; empty.applyToken = sp(); - mFlinger.setTransactionState(empty.frameTimelineVsyncId, empty.states, empty.displays, - empty.flags, empty.applyToken, empty.inputWindowCommands, + mFlinger.setTransactionState(empty.frameTimelineInfo, empty.states, empty.displays, empty.flags, + empty.applyToken, empty.inputWindowCommands, empty.desiredPresentTime, empty.isAutoTimestamp, empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks, empty.id); @@ -298,7 +293,7 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { // passed mFlinger.flushTransactionQueues(); - EXPECT_EQ(0, transactionQueue.size()); + EXPECT_EQ(0u, transactionQueue.size()); } TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) { @@ -343,6 +338,3 @@ TEST_F(TransactionApplicationTest, FromHandle) { EXPECT_EQ(nullptr, ret.promote().get()); } } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" -- cgit v1.2.3-59-g8ed1b From 497e81c9fb9d955391678bbf0776b75d397e9ad9 Mon Sep 17 00:00:00 2001 From: chaviw Date: Thu, 4 Feb 2021 17:09:47 -0800 Subject: Convert certain format types to another buffer format. Parity the code from BufferQueueLayer where it converted certain user passed formats into supported formats Test: Builds Fixes: 179066417 Change-Id: I3d9e04491ec4adbd27d5efd53e84075c762ee386 --- libs/gui/BLASTBufferQueue.cpp | 18 ++++++++++++++++-- libs/gui/include/gui/BLASTBufferQueue.h | 1 + 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index c62d9ad440..c2ec0fe078 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -142,7 +142,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetFrameAvailableListener(this); mBufferItemConsumer->setBufferFreedListener(this); mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height); - mBufferItemConsumer->setDefaultBufferFormat(format); + mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format)); mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); @@ -175,7 +175,7 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, std::unique_lock _lock{mMutex}; if (mFormat != format) { mFormat = format; - mBufferItemConsumer->setDefaultBufferFormat(format); + mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format)); } SurfaceComposerClient::Transaction t; @@ -683,4 +683,18 @@ void BLASTBufferQueue::createBufferQueue(sp* outProducer *outConsumer = consumer; } +PixelFormat BLASTBufferQueue::convertBufferFormat(PixelFormat& format) { + PixelFormat convertedFormat = format; + switch (format) { + case PIXEL_FORMAT_TRANSPARENT: + case PIXEL_FORMAT_TRANSLUCENT: + convertedFormat = PIXEL_FORMAT_RGBA_8888; + break; + case PIXEL_FORMAT_OPAQUE: + convertedFormat = PIXEL_FORMAT_RGBX_8888; + break; + } + return convertedFormat; +} + } // namespace android diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index fa3efe15db..bccb71b362 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -110,6 +110,7 @@ private: // Return true if we need to reject the buffer based on the scaling mode and the buffer size. bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex); bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex); + static PixelFormat convertBufferFormat(PixelFormat& format); std::string mName; sp mSurfaceControl; -- cgit v1.2.3-59-g8ed1b From 1618c67c4dc8c0b0d386126e582c8154dbdda403 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 5 Feb 2021 13:08:26 -0800 Subject: Fix default consumer usage bits on BBQ consumer This change aligns with surfaceflinger BQ consumer defaults. Test: atest android.hardware.camera2.cts.NativeCameraDeviceTest#testCameraDeviceSharedOutputUpdate on cuttlefish Bug: 179265466 Change-Id: I5a0081f3c56dfe1deb7e9f851e3df3f9366bb1d7 --- libs/gui/BLASTBufferQueue.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index c62d9ad440..785aaffc9b 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -133,8 +133,10 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetMaxDequeuedBufferCount(2); } - mBufferItemConsumer = - new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, false); + mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer, + GraphicBuffer::USAGE_HW_COMPOSER | + GraphicBuffer::USAGE_HW_TEXTURE, + 1, false); static int32_t id = 0; auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id); id++; -- cgit v1.2.3-59-g8ed1b From 621ec58b54f95a26d7a0b9bf29c5ac9c97d21368 Mon Sep 17 00:00:00 2001 From: Hongguang Chen Date: Tue, 16 Feb 2021 15:42:35 -0800 Subject: Notify BLAST layer when sideband stream is changed. Bug: 180121385 Test: dumpsys SurfaceFlinger, manual test Live TV sideband HDMI input. Change-Id: I821a9fdc6e5c1a446604b1a46dc2e5f720c7155b --- libs/gui/BLASTBufferQueue.cpp | 30 ++++++++++++++++++++++++++---- libs/gui/include/gui/BLASTBufferQueue.h | 26 +++++++++++++++++--------- 2 files changed, 43 insertions(+), 13 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 1e6fc2b217..82c9268feb 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -55,7 +55,7 @@ namespace android { ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__) void BLASTBufferItemConsumer::onDisconnect() { - Mutex::Autolock lock(mFrameEventHistoryMutex); + Mutex::Autolock lock(mMutex); mPreviouslyConnected = mCurrentlyConnected; mCurrentlyConnected = false; if (mPreviouslyConnected) { @@ -66,7 +66,7 @@ void BLASTBufferItemConsumer::onDisconnect() { void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta* outDelta) { - Mutex::Autolock lock(mFrameEventHistoryMutex); + Mutex::Autolock lock(mMutex); if (newTimestamps) { // BufferQueueProducer only adds a new timestamp on // queueBuffer @@ -90,7 +90,7 @@ void BLASTBufferItemConsumer::updateFrameTimestamps(uint64_t frameNumber, nsecs_ const sp& prevReleaseFence, CompositorTiming compositorTiming, nsecs_t latchTime, nsecs_t dequeueReadyTime) { - Mutex::Autolock lock(mFrameEventHistoryMutex); + Mutex::Autolock lock(mMutex); // if the producer is not connected, don't bother updating, // the next producer that connects won't access this frame event @@ -108,7 +108,7 @@ void BLASTBufferItemConsumer::updateFrameTimestamps(uint64_t frameNumber, nsecs_ void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect) { bool disconnect = false; - Mutex::Autolock lock(mFrameEventHistoryMutex); + Mutex::Autolock lock(mMutex); while (!mDisconnectEvents.empty() && mDisconnectEvents.front() <= frameNumber) { disconnect = true; mDisconnectEvents.pop(); @@ -116,6 +116,19 @@ void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* ne if (needsDisconnect != nullptr) *needsDisconnect = disconnect; } +void BLASTBufferItemConsumer::setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) { + Mutex::Autolock lock(mMutex); + mBLASTBufferQueue = blastbufferqueue; +} + +void BLASTBufferItemConsumer::onSidebandStreamChanged() { + Mutex::Autolock lock(mMutex); + if (mBLASTBufferQueue != nullptr) { + sp stream = getSidebandStream(); + mBLASTBufferQueue->setSidebandStream(stream); + } +} + BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp& surface, int width, int height, int32_t format, bool enableTripleBuffering) @@ -145,6 +158,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetBufferFreedListener(this); mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height); mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format)); + mBufferItemConsumer->setBlastBufferQueue(this); mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); @@ -160,6 +174,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetBlastBufferQueue(nullptr); if (mPendingTransactions.empty()) { return; } @@ -557,6 +572,13 @@ status_t BLASTBufferQueue::setFrameTimelineInfo(const FrameTimelineInfo& frameTi return OK; } +void BLASTBufferQueue::setSidebandStream(const sp& stream) { + std::unique_lock _lock{mMutex}; + SurfaceComposerClient::Transaction t; + + t.setSidebandStream(mSurfaceControl, stream).apply(); +} + sp BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) { std::unique_lock _lock{mMutex}; sp scHandle = nullptr; diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index bccb71b362..dd8e714e23 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -32,6 +32,7 @@ namespace android { +class BLASTBufferQueue; class BufferItemConsumer; class BLASTBufferItemConsumer : public BufferItemConsumer { @@ -40,27 +41,32 @@ public: int bufferCount, bool controlledByApp) : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp), mCurrentlyConnected(false), - mPreviouslyConnected(false) {} + mPreviouslyConnected(false), + mBLASTBufferQueue(nullptr) {} void onDisconnect() override; void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, - FrameEventHistoryDelta* outDelta) override - REQUIRES(mFrameEventHistoryMutex); + FrameEventHistoryDelta* outDelta) override REQUIRES(mMutex); void updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime, const sp& gpuCompositionDoneFence, const sp& presentFence, const sp& prevReleaseFence, CompositorTiming compositorTiming, nsecs_t latchTime, - nsecs_t dequeueReadyTime) REQUIRES(mFrameEventHistoryMutex); + nsecs_t dequeueReadyTime) REQUIRES(mMutex); void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect); + void setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) REQUIRES(mMutex); + +protected: + void onSidebandStreamChanged() override REQUIRES(mMutex); private: uint64_t mCurrentFrameNumber = 0; - Mutex mFrameEventHistoryMutex; - ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mFrameEventHistoryMutex); - std::queue mDisconnectEvents GUARDED_BY(mFrameEventHistoryMutex); - bool mCurrentlyConnected GUARDED_BY(mFrameEventHistoryMutex); - bool mPreviouslyConnected GUARDED_BY(mFrameEventHistoryMutex); + Mutex mMutex; + ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mMutex); + std::queue mDisconnectEvents GUARDED_BY(mMutex); + bool mCurrentlyConnected GUARDED_BY(mMutex); + bool mPreviouslyConnected GUARDED_BY(mMutex); + BLASTBufferQueue* mBLASTBufferQueue GUARDED_BY(mMutex); }; class BLASTBufferQueue @@ -94,6 +100,8 @@ public: status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); status_t setFrameTimelineInfo(const FrameTimelineInfo& info); + void setSidebandStream(const sp& stream); + virtual ~BLASTBufferQueue(); private: -- cgit v1.2.3-59-g8ed1b From 1506b181085e1f2156283d0e7b62fe94a918427f Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 22 Feb 2021 14:35:15 -0800 Subject: Introduce release buffer callback for BufferStateLayer Currently BLAST clients use the TransactionCompleted callbacks to determine when to release buffers. The TransactionCompleted callback is overloaded. For transactions without buffers, the callback is called when the transaction is applied on the server. If the Transaction contains one or more buffers, the callback is called when all the buffers are latched and ready to be presented. If we have multiple buffers on multiple transactions, where one or more buffers maybe dropped, the pending callbacks are called together. This may delay signaling the client when a buffer can be released. To fix this, we introduce a new buffer release callback that is called as soon as a buffer is dropped by the server or when a new buffer has been latched and the buffer will no longer be presented. This new callback provides a graphic bufferid to identify the buffer that can be released and a release fence to wait on. BlastBufferQueue has been switched to use this new callback. Other BLAST users continue to use the existing callback. Test: go/wm-smoke Test: atest ReleaseBufferCallbackTest Bug: 178385281 Change-Id: Idd88e4994e543443198a5a8cfa0e3f5f67d5d482 --- libs/gui/BLASTBufferQueue.cpp | 107 +++---- libs/gui/ITransactionCompletedListener.cpp | 13 +- libs/gui/LayerState.cpp | 17 +- libs/gui/SurfaceComposerClient.cpp | 84 +++++- libs/gui/include/gui/BLASTBufferQueue.h | 18 +- .../include/gui/ITransactionCompletedListener.h | 8 +- libs/gui/include/gui/LayerState.h | 7 +- libs/gui/include/gui/SurfaceComposerClient.h | 19 +- libs/gui/tests/BLASTBufferQueue_test.cpp | 53 +++- services/surfaceflinger/BufferStateLayer.cpp | 54 +++- services/surfaceflinger/BufferStateLayer.h | 8 +- services/surfaceflinger/Layer.cpp | 3 + services/surfaceflinger/Layer.h | 10 +- services/surfaceflinger/RefreshRateOverlay.cpp | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 3 +- .../surfaceflinger/TransactionCallbackInvoker.cpp | 3 +- .../surfaceflinger/TransactionCallbackInvoker.h | 1 + services/surfaceflinger/tests/Android.bp | 1 + .../surfaceflinger/tests/LayerCallback_test.cpp | 21 +- .../tests/ReleaseBufferCallback_test.cpp | 312 +++++++++++++++++++++ .../tests/unittests/TransactionFrameTracerTest.cpp | 3 +- .../unittests/TransactionSurfaceFrameTest.cpp | 26 +- 22 files changed, 652 insertions(+), 125 deletions(-) create mode 100644 services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 82c9268feb..f778232803 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -169,8 +169,6 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp= mTransactionCompleteFrameNumber) { + if (currFrameNumber > mTransactionCompleteFrameNumber) { + BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64 + " than expected=%" PRIu64, + currFrameNumber, mTransactionCompleteFrameNumber); + } + transactionCompleteCallback = std::move(mTransactionCompleteCallback); + mTransactionCompleteFrameNumber = 0; } - mBufferItemConsumer->releaseBuffer(mPendingReleaseItem.item, - mPendingReleaseItem.releaseFence - ? mPendingReleaseItem.releaseFence - : Fence::NO_FENCE); - mNumAcquired--; - mPendingReleaseItem.item = BufferItem(); - mPendingReleaseItem.releaseFence = nullptr; - } - - if (mSubmitted.empty()) { - BQA_LOGE("ERROR: callback with no corresponding submitted buffer item"); } - mPendingReleaseItem.item = std::move(mSubmitted.front()); - mSubmitted.pop(); - - processNextBufferLocked(false /* useNextTransaction */); - currFrameNumber = mPendingReleaseItem.item.mFrameNumber; - if (mTransactionCompleteCallback && mTransactionCompleteFrameNumber == currFrameNumber) { - transactionCompleteCallback = std::move(mTransactionCompleteCallback); - mTransactionCompleteFrameNumber = 0; - } - - mCallbackCV.notify_all(); decStrong((void*)transactionCallbackThunk); } @@ -295,15 +274,46 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp context, uint64_t graphicBufferId, + const sp& releaseFence) { + sp blastBufferQueue = context.promote(); + ALOGV("releaseBufferCallbackThunk graphicBufferId=%" PRIu64 " blastBufferQueue=%s", + graphicBufferId, blastBufferQueue ? "alive" : "dead"); + if (blastBufferQueue) { + blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence); + } +} + +void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, + const sp& releaseFence) { ATRACE_CALL(); - BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction)); + std::unique_lock _lock{mMutex}; + BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId); + + auto it = mSubmitted.find(graphicBufferId); + if (it == mSubmitted.end()) { + BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64, + graphicBufferId); + return; + } + mBufferItemConsumer->releaseBuffer(it->second, releaseFence); + mSubmitted.erase(it); + mNumAcquired--; + processNextBufferLocked(false /* useNextTransaction */); + mCallbackCV.notify_all(); +} + +void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { + ATRACE_CALL(); // If the next transaction is set, we want to guarantee the our acquire will not fail, so don't // include the extra buffer when checking if we can acquire the next buffer. const bool includeExtraAcquire = !useNextTransaction; if (mNumFrameAvailable == 0 || maxBuffersAcquired(includeExtraAcquire)) { - BQA_LOGV("processNextBufferLocked waiting for frame available or callback"); mCallbackCV.notify_all(); return; } @@ -353,7 +363,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } mNumAcquired++; - mSubmitted.push(bufferItem); + mSubmitted[buffer->getId()] = bufferItem; bool needsDisconnect = false; mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect); @@ -369,7 +379,10 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { mLastBufferScalingMode = bufferItem.mScalingMode; mLastAcquiredFrameNumber = bufferItem.mFrameNumber; - t->setBuffer(mSurfaceControl, buffer); + auto releaseBufferCallback = + std::bind(releaseBufferCallbackThunk, wp(this) /* callbackContext */, + std::placeholders::_1, std::placeholders::_2); + t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback); t->setDataspace(mSurfaceControl, static_cast(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); @@ -427,9 +440,12 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 - " applyTransaction=%s mTimestamp=%" PRId64 " mPendingTransactions.size=%d", + " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d" + " graphicBufferId=%" PRIu64, mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), - bufferItem.mTimestamp, static_cast(mPendingTransactions.size())); + bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", + static_cast(mPendingTransactions.size()), + bufferItem.mGraphicBuffer->getId()); } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { @@ -444,18 +460,17 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { std::unique_lock _lock{mMutex}; const bool nextTransactionSet = mNextTransaction != nullptr; - BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s mFlushShadowQueue=%s", - item.mFrameNumber, toString(nextTransactionSet), toString(mFlushShadowQueue)); - - if (nextTransactionSet || mFlushShadowQueue) { + if (nextTransactionSet) { while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) { BQA_LOGV("waiting in onFrameAvailable..."); mCallbackCV.wait(_lock); } } - mFlushShadowQueue = false; // add to shadow queue mNumFrameAvailable++; + + BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, + toString(nextTransactionSet)); processNextBufferLocked(nextTransactionSet /* useNextTransaction */); } @@ -514,14 +529,12 @@ void BLASTBufferQueue::setTransactionCompleteCallback( } // Check if we have acquired the maximum number of buffers. -// As a special case, we wait for the first callback before acquiring the second buffer so we -// can ensure the first buffer is presented if multiple buffers are queued in succession. // Consumer can acquire an additional buffer if that buffer is not droppable. Set // includeExtraAcquire is true to include this buffer to the count. Since this depends on the state // of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE. bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const { int maxAcquiredBuffers = MAX_ACQUIRED_BUFFERS + (includeExtraAcquire ? 2 : 1); - return mNumAcquired == maxAcquiredBuffers || (!mInitialCallbackReceived && mNumAcquired == 1); + return mNumAcquired == maxAcquiredBuffers; } class BBQSurface : public Surface { diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 0ded9361bf..9b5be1f15a 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -27,7 +27,8 @@ namespace { // Anonymous enum class Tag : uint32_t { ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION, - LAST = ON_TRANSACTION_COMPLETED, + ON_RELEASE_BUFFER, + LAST = ON_RELEASE_BUFFER, }; } // Anonymous namespace @@ -122,6 +123,7 @@ status_t SurfaceStats::writeToParcel(Parcel* output) const { for (const auto& data : jankData) { SAFE_PARCEL(output->writeParcelable, data); } + SAFE_PARCEL(output->writeUint64, previousBufferId); return NO_ERROR; } @@ -144,6 +146,7 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) { SAFE_PARCEL(input->readParcelable, &data); jankData.push_back(data); } + SAFE_PARCEL(input->readUint64, &previousBufferId); return NO_ERROR; } @@ -245,6 +248,12 @@ public: onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED, stats); } + + void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence) override { + callRemoteAsync(Tag::ON_RELEASE_BUFFER, + graphicBufferId, releaseFence); + } }; // Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see @@ -263,6 +272,8 @@ status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& case Tag::ON_TRANSACTION_COMPLETED: return callLocalAsync(data, reply, &ITransactionCompletedListener::onTransactionCompleted); + case Tag::ON_RELEASE_BUFFER: + return callLocalAsync(data, reply, &ITransactionCompletedListener::onReleaseBuffer); } } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 6bb8bf2d5b..7a18ca61fe 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -63,7 +63,8 @@ layer_state_t::layer_state_t() fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0), frameTimelineInfo(), - autoRefresh(false) { + autoRefresh(false), + releaseBufferListener(nullptr) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -152,6 +153,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeUint64, frameNumber); SAFE_PARCEL(frameTimelineInfo.write, output); SAFE_PARCEL(output.writeBool, autoRefresh); + SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(releaseBufferListener)); SAFE_PARCEL(output.writeUint32, blurRegions.size()); for (auto region : blurRegions) { @@ -275,6 +277,12 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(frameTimelineInfo.read, input); SAFE_PARCEL(input.readBool, &autoRefresh); + tmpBinder = nullptr; + SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder); + if (tmpBinder) { + releaseBufferListener = checked_interface_cast(tmpBinder); + } + uint32_t numRegions = 0; SAFE_PARCEL(input.readUint32, &numRegions); blurRegions.clear(); @@ -543,6 +551,13 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eAutoRefreshChanged; autoRefresh = other.autoRefresh; } + if (other.what & eReleaseBufferListenerChanged) { + if (releaseBufferListener) { + ALOGW("Overriding releaseBufferListener"); + } + what |= eReleaseBufferListenerChanged; + releaseBufferListener = other.releaseBufferListener; + } if (other.what & eStretchChanged) { what |= eStretchChanged; stretchEffect = other.stretchEffect; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c16a98f42f..11fe49039d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -195,6 +195,17 @@ void TransactionCompletedListener::removeJankListener(const sp } } +void TransactionCompletedListener::setReleaseBufferCallback(uint64_t graphicBufferId, + ReleaseBufferCallback listener) { + std::scoped_lock lock(mMutex); + mReleaseBufferCallbacks[graphicBufferId] = listener; +} + +void TransactionCompletedListener::removeReleaseBufferCallback(uint64_t graphicBufferId) { + std::scoped_lock lock(mMutex); + mReleaseBufferCallbacks.erase(graphicBufferId); +} + void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, sp surfaceControl, SurfaceStatsCallback listener) { std::lock_guard lock(mMutex); @@ -275,6 +286,20 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener .surfaceControls[surfaceStats.surfaceControl] ->setTransformHint(surfaceStats.transformHint); } + // If there is buffer id set, we look up any pending client release buffer callbacks + // and call them. This is a performance optimization when we have a transaction + // callback and a release buffer callback happening at the same time to avoid an + // additional ipc call from the server. + if (surfaceStats.previousBufferId) { + ReleaseBufferCallback callback = + popReleaseBufferCallbackLocked(surfaceStats.previousBufferId); + if (callback) { + callback(surfaceStats.previousBufferId, + surfaceStats.previousReleaseFence + ? surfaceStats.previousReleaseFence + : Fence::NO_FENCE); + } + } } callbackFunction(transactionStats.latchTime, transactionStats.presentFence, @@ -297,6 +322,32 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } } +void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, + sp releaseFence) { + ReleaseBufferCallback callback; + { + std::scoped_lock lock(mMutex); + callback = popReleaseBufferCallbackLocked(graphicBufferId); + } + if (!callback) { + ALOGE("Could not call release buffer callback, buffer not found %" PRIu64, graphicBufferId); + return; + } + callback(graphicBufferId, releaseFence); +} + +ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( + uint64_t graphicBufferId) { + ReleaseBufferCallback callback; + auto itr = mReleaseBufferCallbacks.find(graphicBufferId); + if (itr == mReleaseBufferCallbacks.end()) { + return nullptr; + } + callback = itr->second; + mReleaseBufferCallbacks.erase(itr); + return callback; +} + // --------------------------------------------------------------------------- void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId); @@ -1219,17 +1270,20 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( - const sp& sc, const sp& buffer) { + const sp& sc, const sp& buffer, + ReleaseBufferCallback callback) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } + removeReleaseBufferCallback(s); s->what |= layer_state_t::eBufferChanged; s->buffer = buffer; if (mIsAutoTimestamp) { mDesiredPresentTime = systemTime(); } + setReleaseBufferCallback(s, callback); registerSurfaceControlForCallback(sc); @@ -1237,6 +1291,34 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe return *this; } +void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state_t* s) { + if (!s->releaseBufferListener) { + return; + } + + s->what &= ~static_cast(layer_state_t::eReleaseBufferListenerChanged); + s->releaseBufferListener = nullptr; + TransactionCompletedListener::getInstance()->removeReleaseBufferCallback(s->buffer->getId()); +} + +void SurfaceComposerClient::Transaction::setReleaseBufferCallback(layer_state_t* s, + ReleaseBufferCallback callback) { + if (!callback) { + return; + } + + if (!s->buffer) { + ALOGW("Transaction::setReleaseBufferCallback" + "ignored trying to set a callback on a null buffer."); + return; + } + + s->what |= layer_state_t::eReleaseBufferListenerChanged; + s->releaseBufferListener = TransactionCompletedListener::getIInstance(); + auto listener = TransactionCompletedListener::getInstance(); + listener->setReleaseBufferCallback(s->buffer->getId(), callback); +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence( const sp& sc, const sp& fence) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index dd8e714e23..0173ffd68e 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -89,13 +89,14 @@ public: void transactionCallback(nsecs_t latchTime, const sp& presentFence, const std::vector& stats); + void releaseBufferCallback(uint64_t graphicBufferId, const sp& releaseFence); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void setTransactionCompleteCallback(uint64_t frameNumber, std::function&& transactionCompleteCallback); void update(const sp& surface, uint32_t width, uint32_t height, int32_t format); - void flushShadowQueue() { mFlushShadowQueue = true; } + void flushShadowQueue() {} status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); status_t setFrameTimelineInfo(const FrameTimelineInfo& info); @@ -132,16 +133,10 @@ private: int32_t mNumFrameAvailable GUARDED_BY(mMutex); int32_t mNumAcquired GUARDED_BY(mMutex); - bool mInitialCallbackReceived GUARDED_BY(mMutex) = false; - struct PendingReleaseItem { - BufferItem item; - sp releaseFence; - }; - std::queue mSubmitted GUARDED_BY(mMutex); - // Keep a reference to the currently presented buffer so we can release it when the next buffer - // is ready to be presented. - PendingReleaseItem mPendingReleaseItem GUARDED_BY(mMutex); + // Keep a reference to the submitted buffers so we can release when surfaceflinger drops the + // buffer or the buffer has been presented and a new buffer is ready to be presented. + std::unordered_map mSubmitted GUARDED_BY(mMutex); ui::Size mSize GUARDED_BY(mMutex); ui::Size mRequestedSize GUARDED_BY(mMutex); @@ -157,9 +152,6 @@ private: std::vector> mPendingTransactions GUARDED_BY(mMutex); - // If set to true, the next queue buffer will wait until the shadow queue has been processed by - // the adapter. - bool mFlushShadowQueue = false; // Last requested auto refresh state set by the producer. The state indicates that the consumer // should acquire the next frame as soon as it can and not wait for a frame to become available. // This is only relevant for shared buffer mode. diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index cb17ceecd3..098760e89d 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -87,13 +87,14 @@ public: SurfaceStats() = default; SurfaceStats(const sp& sc, nsecs_t time, const sp& prevReleaseFence, uint32_t hint, FrameEventHistoryStats frameEventStats, - std::vector jankData) + std::vector jankData, uint64_t previousBufferId) : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence), transformHint(hint), eventStats(frameEventStats), - jankData(std::move(jankData)) {} + jankData(std::move(jankData)), + previousBufferId(previousBufferId) {} sp surfaceControl; nsecs_t acquireTime = -1; @@ -101,6 +102,7 @@ public: uint32_t transformHint = 0; FrameEventHistoryStats eventStats; std::vector jankData; + uint64_t previousBufferId; }; class TransactionStats : public Parcelable { @@ -139,6 +141,8 @@ public: DECLARE_META_INTERFACE(TransactionCompletedListener) virtual void onTransactionCompleted(ListenerStats stats) = 0; + + virtual void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence) = 0; }; class BnTransactionCompletedListener : public SafeBnInterface { diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 183ec40fba..d68a9cfa4a 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -100,7 +100,7 @@ struct layer_state_t { eLayerStackChanged = 0x00000080, /* was eCropChanged_legacy, now available 0x00000100, */ eDeferTransaction_legacy = 0x00000200, - /* was ScalingModeChanged, now available 0x00000400, */ + eReleaseBufferListenerChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, eReparentChildren = 0x00001000, /* was eDetachChildren, now available 0x00002000, */ @@ -248,6 +248,11 @@ struct layer_state_t { // Stretch effect to be applied to this layer StretchEffect stretchEffect; + + // Listens to when the buffer is safe to be released. This is used for blast + // layers only. The callback includes a release fence as well as the graphic + // buffer id to identify the buffer. + sp releaseBufferListener; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 88484c0bbf..f29983cef7 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -80,6 +80,9 @@ using TransactionCompletedCallbackTakesContext = using TransactionCompletedCallback = std::function& /*presentFence*/, const std::vector& /*stats*/)>; +using ReleaseBufferCallback = + std::function& /*releaseFence*/)>; + using SurfaceStatsCallback = std::function& /*presentFence*/, @@ -388,6 +391,8 @@ public: void cacheBuffers(); void registerSurfaceControlForCallback(const sp& sc); + void setReleaseBufferCallback(layer_state_t* state, ReleaseBufferCallback callback); + void removeReleaseBufferCallback(layer_state_t* state); public: Transaction(); @@ -471,7 +476,8 @@ public: Transaction& setTransformToDisplayInverse(const sp& sc, bool transformToDisplayInverse); Transaction& setFrame(const sp& sc, const Rect& frame); - Transaction& setBuffer(const sp& sc, const sp& buffer); + Transaction& setBuffer(const sp& sc, const sp& buffer, + ReleaseBufferCallback callback = nullptr); Transaction& setCachedBuffer(const sp& sc, int32_t bufferId); Transaction& setAcquireFence(const sp& sc, const sp& fence); Transaction& setDataspace(const sp& sc, ui::Dataspace dataspace); @@ -650,6 +656,8 @@ class TransactionCompletedListener : public BnTransactionCompletedListener { std::unordered_map mCallbacks GUARDED_BY(mMutex); std::multimap, sp> mJankListeners GUARDED_BY(mMutex); + std::unordered_map + mReleaseBufferCallbacks GUARDED_BY(mMutex); std::multimap, SurfaceStatsCallbackEntry> mSurfaceStatsListeners GUARDED_BY(mMutex); @@ -683,8 +691,15 @@ public: SurfaceStatsCallback listener); void removeSurfaceStatsListener(void* context, void* cookie); - // Overrides BnTransactionCompletedListener's onTransactionCompleted + void setReleaseBufferCallback(uint64_t /* graphicsBufferId */, ReleaseBufferCallback); + void removeReleaseBufferCallback(uint64_t /* graphicsBufferId */); + + // BnTransactionCompletedListener overrides void onTransactionCompleted(ListenerStats stats) override; + void onReleaseBuffer(uint64_t /* graphicsBufferId */, sp releaseFence) override; + +private: + ReleaseBufferCallback popReleaseBufferCallbackLocked(uint64_t /* graphicsBufferId */); }; } // namespace android diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 7895e99cc3..fe48d88376 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -73,13 +73,34 @@ public: void waitForCallbacks() { std::unique_lock lock{mBlastBufferQueueAdapter->mMutex}; - while (mBlastBufferQueueAdapter->mSubmitted.size() > 0) { + // Wait until all but one of the submitted buffers have been released. + while (mBlastBufferQueueAdapter->mSubmitted.size() > 1) { mBlastBufferQueueAdapter->mCallbackCV.wait(lock); } } + void setTransactionCompleteCallback(int64_t frameNumber) { + mBlastBufferQueueAdapter->setTransactionCompleteCallback(frameNumber, [&](int64_t frame) { + std::unique_lock lock{mMutex}; + mLastTransactionCompleteFrameNumber = frame; + mCallbackCV.notify_all(); + }); + } + + void waitForCallback(int64_t frameNumber) { + std::unique_lock lock{mMutex}; + // Wait until all but one of the submitted buffers have been released. + while (mLastTransactionCompleteFrameNumber < frameNumber) { + mCallbackCV.wait(lock); + } + } + private: sp mBlastBufferQueueAdapter; + + std::mutex mMutex; + std::condition_variable mCallbackCV; + int64_t mLastTransactionCompleteFrameNumber = -1; }; class BLASTBufferQueueTest : public ::testing::Test { @@ -128,7 +149,7 @@ protected: mCaptureArgs.dataspace = ui::Dataspace::V0_SRGB; } - void setUpProducer(BLASTBufferQueueHelper adapter, sp& producer) { + void setUpProducer(BLASTBufferQueueHelper& adapter, sp& producer) { producer = adapter.getIGraphicBufferProducer(); setUpProducer(producer); } @@ -205,10 +226,10 @@ protected: EXPECT_GE(epsilon, abs(g - *(pixel + 1))); EXPECT_GE(epsilon, abs(b - *(pixel + 2))); } + ASSERT_EQ(false, ::testing::Test::HasFailure()); } } captureBuf->unlock(); - ASSERT_EQ(false, ::testing::Test::HasFailure()); } static status_t captureDisplay(DisplayCaptureArgs& captureArgs, @@ -315,7 +336,8 @@ TEST_F(BLASTBufferQueueTest, DISABLED_onFrameAvailable_ApplyDesiredPresentTime) nsecs_t desiredPresentTime = systemTime() + nsecs_t(5 * 1e8); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(desiredPresentTime, false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(desiredPresentTime, true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); @@ -351,7 +373,8 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) { buf->unlock(); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); @@ -396,7 +419,8 @@ TEST_F(BLASTBufferQueueTest, TripleBuffering) { nullptr, nullptr); ASSERT_EQ(NO_ERROR, ret); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); @@ -429,7 +453,8 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { buf->unlock(); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight / 2), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); @@ -486,7 +511,8 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { buf->unlock(); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(bufferSideLength, finalCropSideLength), NATIVE_WINDOW_SCALING_MODE_SCALE_CROP, 0, Fence::NO_FENCE); @@ -537,7 +563,8 @@ TEST_F(BLASTBufferQueueTest, CustomProducerListener) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); @@ -577,7 +604,7 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { sp slowIgbProducer; setUpProducer(slowAdapter, slowIgbProducer); nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); - queueBuffer(slowIgbProducer, 0 /* r */, 0 /* g */, 0 /* b */, presentTimeDelay); + queueBuffer(slowIgbProducer, 0 /* r */, 255 /* g */, 0 /* b */, presentTimeDelay); BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight); sp fastIgbProducer; @@ -617,7 +644,8 @@ public: fillQuadrants(buf); IGraphicBufferProducer::QueueBufferOutput qbOutput; - IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN, + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(bufWidth, bufHeight), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, tr, Fence::NO_FENCE); @@ -838,6 +866,7 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) { IGraphicBufferProducer::QueueBufferOutput qbOutput; nsecs_t requestedPresentTimeA = 0; nsecs_t postedTimeA = 0; + adapter.setTransactionCompleteCallback(1); setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true); history.applyDelta(qbOutput.frameTimestamps); @@ -848,7 +877,7 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) { ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); ASSERT_GE(events->postedTime, postedTimeA); - adapter.waitForCallbacks(); + adapter.waitForCallback(1); // queue another buffer so we query for frame event deltas nsecs_t requestedPresentTimeB = 0; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 96a0c3cd75..89dfb6fb6b 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -41,6 +41,16 @@ namespace android { using PresentState = frametimeline::SurfaceFrame::PresentState; +namespace { +void callReleaseBufferCallback(const sp& listener, + const sp& buffer, const sp& releaseFence) { + if (!listener) { + return; + } + listener->onReleaseBuffer(buffer->getId(), releaseFence ? releaseFence : Fence::NO_FENCE); +} +} // namespace + // clang-format off const std::array BufferStateLayer::IDENTITY_MATRIX{ 1, 0, 0, 0, @@ -65,7 +75,10 @@ BufferStateLayer::~BufferStateLayer() { // RenderEngine may have been using the buffer as an external texture // after the client uncached the buffer. auto& engine(mFlinger->getRenderEngine()); - engine.unbindExternalTextureBuffer(mBufferInfo.mBuffer->getId()); + const uint64_t bufferId = mBufferInfo.mBuffer->getId(); + engine.unbindExternalTextureBuffer(bufferId); + callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer, + mBufferInfo.mFence); } } @@ -74,6 +87,7 @@ status_t BufferStateLayer::addReleaseFence(const sp& ch, if (ch == nullptr) { return OK; } + ch->previousBufferId = mPreviousBufferId; if (!ch->previousReleaseFence.get()) { ch->previousReleaseFence = fence; return OK; @@ -190,6 +204,19 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { handle->dequeueReadyTime = dequeueReadyTime; } + // If there are multiple transactions in this frame, set the previous id on the earliest + // transacton. We don't need to pass in the released buffer id to multiple transactions. + // The buffer id does not have to correspond to any particular transaction as long as the + // listening end point is the same but the client expects the first transaction callback that + // replaces the presented buffer to contain the release fence. This follows the same logic. + // see BufferStateLayer::onLayerDisplayed. + for (auto& handle : mDrawingState.callbackHandles) { + if (handle->releasePreviousBuffer) { + handle->previousBufferId = mPreviousBufferId; + break; + } + } + std::vector jankData; jankData.reserve(mPendingJankClassifications.size()); while (!mPendingJankClassifications.empty() @@ -344,8 +371,8 @@ bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t post bool BufferStateLayer::setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, - std::optional dequeueTime, - const FrameTimelineInfo& info) { + std::optional dequeueTime, const FrameTimelineInfo& info, + const sp& releaseBufferListener) { ATRACE_CALL(); if (mCurrentState.buffer) { @@ -353,7 +380,10 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const sp& buffer, const sp& newBuffer) { + if (mDrawingState.buffer != nullptr && mDrawingState.buffer != mBufferInfo.mBuffer && + newBuffer != mDrawingState.buffer) { // If we are about to update mDrawingState.buffer but it has not yet latched - // then we will drop a buffer and should decrement the pending buffer count. - // This logic may not work perfectly in the face of a BufferStateLayer being the - // deferred side of a deferred transaction, but we don't expect this use case. + // then we will drop a buffer and should decrement the pending buffer count and + // call any release buffer callbacks if set. + callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer, + mDrawingState.acquireFence); decrementPendingBufferCount(); } - return Layer::doTransaction(flags); } } // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index ebf40cb6e4..036e8d2e85 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -70,7 +70,8 @@ public: bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, - std::optional dequeueTime, const FrameTimelineInfo& info) override; + std::optional dequeueTime, const FrameTimelineInfo& info, + const sp& transactionListener) override; bool setAcquireFence(const sp& fence) override; bool setDataspace(ui::Dataspace dataspace) override; bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; @@ -111,7 +112,7 @@ public: // See mPendingBufferTransactions void decrementPendingBufferCount(); - uint32_t doTransaction(uint32_t flags) override; + void bufferMayChange(sp& newBuffer) override; std::atomic* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } @@ -170,6 +171,9 @@ private: mutable bool mCurrentStateModified = false; bool mReleasePreviousBuffer = false; + + // Stores the last set acquire fence signal time used to populate the callback handle's acquire + // time. nsecs_t mCallbackHandleAcquireTime = -1; std::deque> mPendingJankClassifications; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0015bf27d1..cd3e8add9a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1048,6 +1048,9 @@ uint32_t Layer::doTransaction(uint32_t flags) { c.callbackHandles.push_back(handle); } + // Allow BufferStateLayer to release any unlatched buffers in drawing state. + bufferMayChange(c.buffer); + // Commit the transaction commitTransaction(c); mPendingStatesSnapshot = mPendingStates; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 26d8e7472a..85ff479344 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -312,6 +312,7 @@ public: // When the transaction was posted nsecs_t postTime; + sp releaseBufferListener; // SurfaceFrame that tracks the timeline of Transactions that contain a Buffer. Only one // such SurfaceFrame exists because only one buffer can be presented on the layer per vsync. // If multiple buffers are queued, the prior ones will be dropped, along with the @@ -466,7 +467,8 @@ public: nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */, std::optional /* dequeueTime */, - const FrameTimelineInfo& /*info*/) { + const FrameTimelineInfo& /*info*/, + const sp& /* releaseBufferListener */) { return false; }; virtual bool setAcquireFence(const sp& /*fence*/) { return false; }; @@ -773,6 +775,12 @@ public: */ virtual uint32_t doTransaction(uint32_t transactionFlags); + /* + * Called before updating the drawing state buffer. Used by BufferStateLayer to release any + * unlatched buffers in the drawing state. + */ + virtual void bufferMayChange(sp& /* newBuffer */){}; + /* * Remove relative z for the layer if its relative parent is not part of the * provided layer tree. diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index b29c624d00..1d00cc38f2 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -241,7 +241,8 @@ void RefreshRateOverlay::changeRefreshRate(const Fps& fps) { auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), - std::nullopt /* dequeueTime */, FrameTimelineInfo{}); + std::nullopt /* dequeueTime */, FrameTimelineInfo{}, + nullptr /* releaseBufferListener */); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } @@ -254,7 +255,8 @@ void RefreshRateOverlay::onInvalidate() { auto buffer = buffers[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), - std::nullopt /* dequeueTime */, FrameTimelineInfo{}); + std::nullopt /* dequeueTime */, FrameTimelineInfo{}, + nullptr /* releaseBufferListener */); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d048380dd2..61cc8a2ff0 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4027,7 +4027,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1; if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp, - s.cachedBuffer, frameNumber, dequeueBufferTimestamp, info)) { + s.cachedBuffer, frameNumber, dequeueBufferTimestamp, info, + s.releaseBufferListener)) { flags |= eTraversalNeeded; } } else if (info.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index a78510e902..3590e76cb9 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -201,7 +201,8 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp& handle->dequeueReadyTime); transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime, handle->previousReleaseFence, - handle->transformHint, eventStats, jankData); + handle->transformHint, eventStats, jankData, + handle->previousBufferId); } return NO_ERROR; } diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index a240c824a1..caa8a4fb45 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -50,6 +50,7 @@ public: nsecs_t refreshStartTime = 0; nsecs_t dequeueReadyTime = 0; uint64_t frameNumber = 0; + uint64_t previousBufferId = 0; }; class TransactionCallbackInvoker { diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 78187f7e9d..b96725fa12 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -44,6 +44,7 @@ cc_test { "MultiDisplayLayerBounds_test.cpp", "RefreshRateOverlay_test.cpp", "RelativeZ_test.cpp", + "ReleaseBufferCallback_test.cpp", "ScreenCapture_test.cpp", "SetFrameRate_test.cpp", "SetGeometry_test.cpp", diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index aa1cce2586..158801a705 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - #include #include @@ -25,6 +21,8 @@ #include "LayerTransactionTest.h" #include "utils/CallbackUtils.h" +using namespace std::chrono_literals; + namespace android { using android::hardware::graphics::common::V1_1::BufferUsage; @@ -801,7 +799,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime) { } // Try to present 100ms in the future - nsecs_t time = systemTime() + (100 * 1e6); + nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -825,7 +823,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) { } // Try to present 100ms in the future - nsecs_t time = systemTime() + (100 * 1e6); + nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -842,7 +840,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) { } // Try to present 33ms after the first frame - time += (33.3 * 1e6); + time += std::chrono::nanoseconds(33ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -870,7 +868,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) { } // Try to present 100ms in the future - nsecs_t time = systemTime() + (100 * 1e6); + nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -887,7 +885,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) { } // Try to present 33ms before the previous frame - time -= (33.3 * 1e6); + time -= std::chrono::nanoseconds(33ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -914,7 +912,7 @@ TEST_F(LayerCallbackTest, DesiredPresentTime_Past) { } // Try to present 100ms in the past - nsecs_t time = systemTime() - (100 * 1e6); + nsecs_t time = systemTime() - std::chrono::nanoseconds(100ms).count(); transaction.setDesiredPresentTime(time); transaction.apply(); @@ -948,6 +946,3 @@ TEST_F(LayerCallbackTest, ExpectedPresentTime) { } } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp new file mode 100644 index 0000000000..fb7d41c81e --- /dev/null +++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2021 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. + */ + +#include "LayerTransactionTest.h" +#include "utils/CallbackUtils.h" + +using namespace std::chrono_literals; + +namespace android { + +using android::hardware::graphics::common::V1_1::BufferUsage; + +::testing::Environment* const binderEnv = + ::testing::AddGlobalTestEnvironment(new BinderEnvironment()); + +// b/181132765 - disabled until cuttlefish failures are investigated +class ReleaseBufferCallbackHelper { +public: + static void function(void* callbackContext, uint64_t graphicsBufferId, + const sp& releaseFence) { + if (!callbackContext) { + FAIL() << "failed to get callback context"; + } + ReleaseBufferCallbackHelper* helper = + static_cast(callbackContext); + std::lock_guard lock(helper->mMutex); + helper->mCallbackDataQueue.emplace(graphicsBufferId, releaseFence); + helper->mConditionVariable.notify_all(); + } + + void getCallbackData(uint64_t* bufferId) { + std::unique_lock lock(mMutex); + if (mCallbackDataQueue.empty()) { + if (!mConditionVariable.wait_for(lock, std::chrono::seconds(3), + [&] { return !mCallbackDataQueue.empty(); })) { + FAIL() << "failed to get releaseBuffer callback"; + } + } + + auto callbackData = mCallbackDataQueue.front(); + mCallbackDataQueue.pop(); + *bufferId = callbackData.first; + } + + void verifyNoCallbacks() { + // Wait to see if there are extra callbacks + std::this_thread::sleep_for(300ms); + + std::lock_guard lock(mMutex); + EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received"; + mCallbackDataQueue = {}; + } + + android::ReleaseBufferCallback getCallback() { + return std::bind(function, static_cast(this) /* callbackContext */, + std::placeholders::_1, std::placeholders::_2); + } + + std::mutex mMutex; + std::condition_variable mConditionVariable; + std::queue>> mCallbackDataQueue; +}; + +class ReleaseBufferCallbackTest : public LayerTransactionTest { +public: + virtual sp createBufferStateLayer() { + return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState); + } + + static void submitBuffer(const sp& layer, sp buffer, + sp fence, CallbackHelper& callback, + ReleaseBufferCallbackHelper& releaseCallback) { + Transaction t; + t.setBuffer(layer, buffer, releaseCallback.getCallback()); + t.setAcquireFence(layer, fence); + t.addTransactionCompletedCallback(callback.function, callback.getContext()); + t.apply(); + } + + static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult) { + CallbackData callbackData; + helper.getCallbackData(&callbackData); + expectedResult.verifyCallbackData(callbackData); + } + + static void waitForReleaseBufferCallback(ReleaseBufferCallbackHelper& releaseCallback, + uint64_t expectedReleaseBufferId) { + uint64_t actualReleaseBufferId; + releaseCallback.getCallbackData(&actualReleaseBufferId); + EXPECT_EQ(expectedReleaseBufferId, actualReleaseBufferId); + releaseCallback.verifyNoCallbacks(); + } + static ReleaseBufferCallbackHelper* getReleaseBufferCallbackHelper() { + static std::vector sCallbacks; + sCallbacks.emplace_back(new ReleaseBufferCallbackHelper()); + return sCallbacks.back(); + } + + static sp getBuffer() { + return new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + } +}; + +TEST_F(ReleaseBufferCallbackTest, DISABLED_PresentBuffer) { + sp layer = createBufferStateLayer(); + CallbackHelper transactionCallback; + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + // If a buffer is being presented, we should not emit a release callback. + sp firstBuffer = getBuffer(); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + EXPECT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + + // if state doesn't change, no release callbacks are expected + Transaction t; + t.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()); + t.apply(); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, ExpectedResult())); + EXPECT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + + // If a presented buffer is replaced, we should emit a release callback for the + // previously presented buffer. + sp secondBuffer = getBuffer(); + submitBuffer(layer, secondBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); +} + +TEST_F(ReleaseBufferCallbackTest, DISABLED_OffScreenLayer) { + sp layer = createBufferStateLayer(); + + CallbackHelper transactionCallback; + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + // If a buffer is being presented, we should not emit a release callback. + sp firstBuffer = getBuffer(); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + releaseCallback->verifyNoCallbacks(); + + // If a layer is parented offscreen then it should not emit a callback since sf still owns + // the buffer and can render it again. + Transaction t; + t.reparent(layer, nullptr); + t.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()); + t.apply(); + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::NOT_RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + + // If a presented buffer is replaced, we should emit a release callback for the + // previously presented buffer. + sp secondBuffer = getBuffer(); + submitBuffer(layer, secondBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::NOT_RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); + + // If continue to submit buffer we continue to get release callbacks + sp thirdBuffer = getBuffer(); + submitBuffer(layer, thirdBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::NOT_RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, secondBuffer->getId())); +} + +TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_layerdestroy) { + sp layer = createBufferStateLayer(); + CallbackHelper* transactionCallback = new CallbackHelper(); + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + // If a buffer is being presented, we should not emit a release callback. + sp firstBuffer = getBuffer(); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback); + { + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(*transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + } + + // Destroying a currently presenting layer emits a callback. + Transaction t; + t.reparent(layer, nullptr); + t.apply(); + layer = nullptr; + + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); +} + +// Destroying a never presented layer emits a callback. +TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_OffScreenLayerDestroy) { + sp layer = createBufferStateLayer(); + + // make layer offscreen + Transaction t; + t.reparent(layer, nullptr); + t.apply(); + + CallbackHelper* transactionCallback = new CallbackHelper(); + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + // Submitting a buffer does not emit a callback. + sp firstBuffer = getBuffer(); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback); + { + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(*transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + } + + // Submitting a second buffer will replace the drawing state buffer and emit a callback. + sp secondBuffer = getBuffer(); + submitBuffer(layer, secondBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback); + { + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(*transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE( + waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); + } + + // Destroying the offscreen layer emits a callback. + layer = nullptr; + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, secondBuffer->getId())); +} + +TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { + sp layer = createBufferStateLayer(); + CallbackHelper transactionCallback; + ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper(); + + // If a buffer is being presented, we should not emit a release callback. + sp firstBuffer = getBuffer(); + + // Try to present 100ms in the future + nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count(); + + Transaction t; + t.setBuffer(layer, firstBuffer, releaseCallback->getCallback()); + t.setAcquireFence(layer, Fence::NO_FENCE); + t.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()); + t.setDesiredPresentTime(time); + t.apply(); + + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + EXPECT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks()); + + // Dropping frames in transaction queue emits a callback + sp secondBuffer = getBuffer(); + t.setBuffer(layer, secondBuffer, releaseCallback->getCallback()); + t.setAcquireFence(layer, Fence::NO_FENCE); + t.addTransactionCompletedCallback(transactionCallback.function, + transactionCallback.getContext()); + t.setDesiredPresentTime(time); + t.apply(); + + expected = ExpectedResult(); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::PreviousBuffer::RELEASED); + ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index dbadf75d44..b5ef0a1334 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -123,7 +123,8 @@ public: traceTimestamp(layerId, bufferId, frameNumber, postTime, FrameTracer::FrameEvent::QUEUE, /*duration*/ 0)); layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache, - frameNumber, dequeueTime, FrameTimelineInfo{}); + frameNumber, dequeueTime, FrameTimelineInfo{}, + nullptr /* releaseBufferCallback */); commitTransaction(layer.get()); bool computeVisisbleRegions; diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index 623a5e0608..c75538f476 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -126,7 +126,7 @@ public: auto acquireFence = fenceFactory.createFenceTimeForTest(fence); sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); commitTransaction(layer.get()); @@ -151,7 +151,7 @@ public: auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX; @@ -161,7 +161,7 @@ public: sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; nsecs_t start = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); nsecs_t end = systemTime(); acquireFence2->signalForTest(12); @@ -199,7 +199,7 @@ public: sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -225,7 +225,7 @@ public: sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); @@ -255,7 +255,7 @@ public: sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 3, /*inputEventId*/ 0}); + {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); const auto& bufferSurfaceFrameTX = layer->mCurrentState.bufferSurfaceFrameTX; @@ -353,7 +353,7 @@ public: auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX; @@ -361,7 +361,7 @@ public: auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence2->signalForTest(12); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); @@ -388,7 +388,7 @@ public: auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame1 = layer->mCurrentState.bufferSurfaceFrameTX; @@ -398,7 +398,8 @@ public: sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; auto dropStartTime1 = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}); + {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}, + nullptr /* releaseBufferCallback */); auto dropEndTime1 = systemTime(); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); @@ -409,7 +410,7 @@ public: sp buffer3{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; auto dropStartTime2 = systemTime(); layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 2, /*inputEventId*/ 0}); + {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); auto dropEndTime2 = systemTime(); acquireFence3->signalForTest(12); @@ -448,7 +449,8 @@ public: sp fence1(new Fence()); sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + {/*vsyncId*/ 1, /*inputEventId*/ 0}, + nullptr /* releaseBufferCallback */); layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, /*inputEventId*/ 0}, 10); -- cgit v1.2.3-59-g8ed1b From debd1cbcd488becc629293cfcc4fc5b2ee4ef8b2 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 16 Mar 2021 10:06:01 -0700 Subject: Remove legacy disable triple buffering config The config changes the dequeue limit of BQ (setMaxDequeuedBufferCount) from 2 to 1, decreasing the default size of the queue from (3 to 2). Some of the motivations behind this change include: - not applicable in most scenarios since producers in the system override this - breaks async mode, not well tested in other scenarios - simplifying some of the implementation and removes a configuration/flag. Clients can still manually call setMaxDequeuedBufferCount if they wish. Test: presubmit Fixes: 182314340 Change-Id: Iea88e8a795b91ff325610cfb1eefbcfe6e434841 --- libs/gui/BLASTBufferQueue.cpp | 8 +++----- libs/gui/include/gui/BLASTBufferQueue.h | 2 +- services/surfaceflinger/BufferQueueLayer.cpp | 5 +---- services/surfaceflinger/SurfaceFlinger.cpp | 7 ------- services/surfaceflinger/SurfaceFlinger.h | 7 ------- 5 files changed, 5 insertions(+), 24 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 82c9268feb..9490314b71 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -130,8 +130,7 @@ void BLASTBufferItemConsumer::onSidebandStreamChanged() { } BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp& surface, - int width, int height, int32_t format, - bool enableTripleBuffering) + int width, int height, int32_t format) : mName(name), mSurfaceControl(surface), mSize(width, height), @@ -143,9 +142,8 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetDequeueTimeout(std::numeric_limits::max()); - if (enableTripleBuffering) { - mProducer->setMaxDequeuedBufferCount(2); - } + // safe default, most producers are expected to override this + mProducer->setMaxDequeuedBufferCount(2); mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_HW_TEXTURE, diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index dd8e714e23..9516bfb4b0 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -74,7 +74,7 @@ class BLASTBufferQueue { public: BLASTBufferQueue(const std::string& name, const sp& surface, int width, - int height, int32_t format, bool enableTripleBuffering = true); + int height, int32_t format); sp getIGraphicBufferProducer() const { return mProducer; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 63dd25f72f..c0ce84f31b 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -521,10 +521,7 @@ void BufferQueueLayer::onFirstRef() { mConsumer->setContentsChangedListener(mContentsChangedListener); mConsumer->setName(String8(mName.data(), mName.size())); - // BufferQueueCore::mMaxDequeuedBufferCount is default to 1 - if (!mFlinger->isLayerTripleBufferingDisabled()) { - mProducer->setMaxDequeuedBufferCount(2); - } + mProducer->setMaxDequeuedBufferCount(2); } status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9da94832ae..284c715ef9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -441,10 +441,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mUseHwcVirtualDisplays = atoi(value); ALOGI_IF(mUseHwcVirtualDisplays, "Enabling HWC virtual displays"); - property_get("ro.sf.disable_triple_buffer", value, "0"); - mLayerTripleBufferingDisabled = atoi(value); - ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering"); - property_get("ro.surface_flinger.supports_background_blur", value, "0"); bool supportsBlurs = atoi(value); mSupportsBlur = supportsBlurs; @@ -4549,9 +4545,6 @@ void SurfaceFlinger::logFrameStats() { void SurfaceFlinger::appendSfConfigString(std::string& result) const { result.append(" [sf"); - if (isLayerTripleBufferingDisabled()) - result.append(" DISABLE_TRIPLE_BUFFERING"); - StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset); StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv); StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 3787b9db89..779859a7ad 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1093,10 +1093,6 @@ private: void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock); void dumpPlannerInfo(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock); - bool isLayerTripleBufferingDisabled() const { - return this->mLayerTripleBufferingDisabled; - } - status_t doDump(int fd, const DumpArgs& args, bool asProto); status_t dumpCritical(int fd, const DumpArgs&, bool asProto); @@ -1250,9 +1246,6 @@ private: TransactionCallbackInvoker mTransactionCallbackInvoker; - // Restrict layers to use two buffers in their bufferqueues. - bool mLayerTripleBufferingDisabled = false; - // these are thread safe std::unique_ptr mEventQueue; FrameTracker mAnimFrameTracker; -- cgit v1.2.3-59-g8ed1b From 8db101095526c49a58fd54bfb9d3501ea5351027 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 15 Mar 2021 17:19:23 -0700 Subject: SurfaceFlinger: remove SurfaceControl level vsyncId setting FrameTimelineInfo can be set on the entire transaction, or for an individual SurfaceControl. Later in the code the FrameTimelineInfo is unified based on the most recent vsyncId. For this reason we are removing the setting of a FrameTimelineInfo on a SurfaceControl and instead we use the transaction's one. Test: adb shell /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test Bug: 181978893 Bug: 169901895 Change-Id: Id4a8e46d57fbda66f6d478be82313482053dce20 --- libs/gui/BLASTBufferQueue.cpp | 2 +- libs/gui/LayerState.cpp | 7 ---- libs/gui/SurfaceComposerClient.cpp | 15 +------ libs/gui/include/gui/LayerState.h | 9 ++--- libs/gui/include/gui/SurfaceComposerClient.h | 3 -- services/surfaceflinger/BufferLayer.cpp | 18 --------- services/surfaceflinger/BufferLayer.h | 11 ------ services/surfaceflinger/BufferQueueLayer.cpp | 15 ------- services/surfaceflinger/BufferQueueLayer.h | 2 - services/surfaceflinger/BufferStateLayer.cpp | 10 ----- services/surfaceflinger/BufferStateLayer.h | 2 - services/surfaceflinger/Layer.h | 4 -- services/surfaceflinger/SurfaceFlinger.cpp | 48 +++++++++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 1 + services/surfaceflinger/tests/LayerState_test.cpp | 29 -------------- 15 files changed, 38 insertions(+), 138 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index f778232803..5b1b975283 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -401,7 +401,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber); if (!mNextFrameTimelineInfoQueue.empty()) { - t->setFrameTimelineInfo(mSurfaceControl, mNextFrameTimelineInfoQueue.front()); + t->setFrameTimelineInfo(mNextFrameTimelineInfoQueue.front()); mNextFrameTimelineInfoQueue.pop(); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 7a18ca61fe..a84e741482 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -62,7 +62,6 @@ layer_state_t::layer_state_t() shouldBeSeamless(true), fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0), - frameTimelineInfo(), autoRefresh(false), releaseBufferListener(nullptr) { matrix.dsdx = matrix.dtdy = 1.0f; @@ -151,7 +150,6 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeBool, shouldBeSeamless); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); - SAFE_PARCEL(frameTimelineInfo.write, output); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(releaseBufferListener)); @@ -274,7 +272,6 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); - SAFE_PARCEL(frameTimelineInfo.read, input); SAFE_PARCEL(input.readBool, &autoRefresh); tmpBinder = nullptr; @@ -543,10 +540,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameNumberChanged; frameNumber = other.frameNumber; } - if (other.what & eFrameTimelineInfoChanged) { - what |= eFrameTimelineInfoChanged; - frameTimelineInfo.merge(other.frameTimelineInfo); - } if (other.what & eAutoRefreshChanged) { what |= eAutoRefreshChanged; autoRefresh = other.autoRefresh; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 11fe49039d..eaccc5bab5 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1630,20 +1630,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( const FrameTimelineInfo& frameTimelineInfo) { - mFrameTimelineInfo = frameTimelineInfo; - return *this; -} - -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( - const sp& sc, const FrameTimelineInfo& frameTimelineInfo) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - - s->what |= layer_state_t::eFrameTimelineInfoChanged; - s->frameTimelineInfo = frameTimelineInfo; + mFrameTimelineInfo.merge(frameTimelineInfo); return *this; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index d68a9cfa4a..4a52168315 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -133,10 +133,9 @@ struct layer_state_t { eProducerDisconnect = 0x100'00000000, eFixedTransformHintChanged = 0x200'00000000, eFrameNumberChanged = 0x400'00000000, - eFrameTimelineInfoChanged = 0x800'00000000, - eBlurRegionsChanged = 0x1000'00000000, - eAutoRefreshChanged = 0x2000'00000000, - eStretchChanged = 0x4000'00000000, + eBlurRegionsChanged = 0x800'00000000, + eAutoRefreshChanged = 0x1000'00000000, + eStretchChanged = 0x2000'00000000, }; layer_state_t(); @@ -239,8 +238,6 @@ struct layer_state_t { // graphics producer. uint64_t frameNumber; - FrameTimelineInfo frameTimelineInfo; - // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant // in shared buffer mode. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index f29983cef7..ae7170e1aa 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -530,9 +530,6 @@ public: // to the transaction, and the input event id that identifies the input event that caused // the current frame. Transaction& setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo); - // Variant that only applies to a specific SurfaceControl. - Transaction& setFrameTimelineInfo(const sp& sc, - const FrameTimelineInfo& frameTimelineInfo); // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index eac3d95d8a..b3f97924bd 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -424,24 +424,6 @@ bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { return isBufferDue(expectedPresentTime); } -bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const { - // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the - // vsync period. We can do this change as soon as ag/13100772 is merged. - constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms; - - const auto presentTime = nextPredictedPresentTime(vsyncId); - if (!presentTime.has_value()) { - return false; - } - - if (std::abs(*presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) { - return false; - } - - return *presentTime >= expectedPresentTime && - *presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count(); -} - bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) { ATRACE_CALL(); diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 5fed79ffed..b8d3f12322 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -189,10 +189,6 @@ protected: // specific logic virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0; - // Returns true if the next frame is considered too early to present - // at the given expectedPresentTime - bool frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const; - std::atomic mAutoRefresh{false}; std::atomic mSidebandStreamChanged{false}; @@ -236,13 +232,6 @@ private: std::unique_ptr mCompositionState; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; - - // Returns the predicted present time of the next frame if available - virtual std::optional nextPredictedPresentTime(int64_t vsyncId) const = 0; - - // The amount of time SF can delay a frame if it is considered early based - // on the VsyncModulator::VsyncConfig::appWorkDuration - static constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms; }; } // namespace android diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 63dd25f72f..51e85c4dcc 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -215,21 +215,6 @@ bool BufferQueueLayer::hasFrameUpdate() const { return mQueuedFrames > 0; } -std::optional BufferQueueLayer::nextPredictedPresentTime(int64_t /*vsyncId*/) const { - Mutex::Autolock lock(mQueueItemLock); - if (mQueueItems.empty()) { - return std::nullopt; - } - - const auto& bufferData = mQueueItems[0]; - - if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) { - return std::nullopt; - } - - return bufferData.surfaceFrame->getPredictions().presentTime; -} - status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) { // This boolean is used to make sure that SurfaceFlinger's shadow copy diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 3a34b952f2..b3b7948935 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -117,8 +117,6 @@ private: // Temporary - Used only for LEGACY camera mode. uint32_t getProducerStickyTransform() const; - std::optional nextPredictedPresentTime(int64_t vsyncId) const override; - sp mConsumer; sp mProducer; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 89dfb6fb6b..00a6d661c0 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -644,16 +644,6 @@ bool BufferStateLayer::hasFrameUpdate() const { return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr); } -std::optional BufferStateLayer::nextPredictedPresentTime(int64_t vsyncId) const { - const auto prediction = - mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId); - if (!prediction.has_value()) { - return std::nullopt; - } - - return prediction->presentTime; -} - status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime, nsecs_t /*expectedPresentTime*/) { const State& s(getDrawingState()); diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 036e8d2e85..7a3da6fec1 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -156,8 +156,6 @@ private: bool bufferNeedsFiltering() const override; - std::optional nextPredictedPresentTime(int64_t vsyncId) const override; - static const std::array IDENTITY_MATRIX; std::unique_ptr mTextureImage; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 85ff479344..1c5d6ecb03 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -930,10 +930,6 @@ public: pid_t getOwnerPid() { return mOwnerPid; } - virtual bool frameIsEarly(nsecs_t /*expectedPresentTime*/, int64_t /*vsyncId*/) const { - return false; - } - // This layer is not a clone, but it's the parent to the cloned hierarchy. The // variable mClonedChild represents the top layer that will be cloned so this // layer will be the parent of mClonedChild. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 61cc8a2ff0..e580a97b90 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3379,6 +3379,28 @@ bool SurfaceFlinger::transactionFlushNeeded() { return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty(); } +bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const { + // The amount of time SF can delay a frame if it is considered early based + // on the VsyncModulator::VsyncConfig::appWorkDuration + constexpr static std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms; + + const auto currentVsyncPeriod = mScheduler->getDisplayStatInfo(systemTime()).vsyncPeriod; + const auto earlyLatchVsyncThreshold = currentVsyncPeriod / 2; + + const auto prediction = mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId); + if (!prediction.has_value()) { + return false; + } + + if (std::abs(prediction->presentTime - expectedPresentTime) >= + kEarlyLatchMaxThreshold.count()) { + return false; + } + + return prediction->presentTime >= expectedPresentTime && + prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold; +} + bool SurfaceFlinger::transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector& states, @@ -3399,6 +3421,13 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( ready = false; } + // 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"); + ready = false; + } + for (const ComposerState& state : states) { const layer_state_t& s = state.state; const bool acquireFenceChanged = (s.what & layer_state_t::eAcquireFenceChanged); @@ -3420,13 +3449,6 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( ATRACE_NAME(layer->getName().c_str()); - const bool frameTimelineInfoChanged = (s.what & layer_state_t::eFrameTimelineInfoChanged); - const auto vsyncId = frameTimelineInfoChanged ? s.frameTimelineInfo.vsyncId : info.vsyncId; - if (isAutoTimestamp && layer->frameIsEarly(expectedPresentTime, vsyncId)) { - ATRACE_NAME("frameIsEarly()"); - ready = false; - } - if (acquireFenceChanged) { // If backpressure is enabled and we already have a buffer to commit, keep the // transaction in the queue. @@ -3959,12 +3981,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } - FrameTimelineInfo info; - if (what & layer_state_t::eFrameTimelineInfoChanged) { - info = s.frameTimelineInfo; - } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { - info = frameTimelineInfo; - } if (what & layer_state_t::eFixedTransformHintChanged) { if (layer->setFixedTransformHint(s.fixedTransformHint)) { flags |= eTraversalNeeded | eTransformHintUpdateNeeded; @@ -4027,12 +4043,12 @@ uint32_t SurfaceFlinger::setClientStateLocked( : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1; if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp, - s.cachedBuffer, frameNumber, dequeueBufferTimestamp, info, + s.cachedBuffer, frameNumber, dequeueBufferTimestamp, frameTimelineInfo, s.releaseBufferListener)) { flags |= eTraversalNeeded; } - } else if (info.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { - layer->setFrameTimelineVsyncForBufferlessTransaction(info, postTime); + } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { + layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime); } if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a5b06dfbd4..a7cdcd1719 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -844,6 +844,7 @@ private: uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); + bool frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const; /* * Layer management */ diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp index f010786601..fa1a5ed6b0 100644 --- a/services/surfaceflinger/tests/LayerState_test.cpp +++ b/services/surfaceflinger/tests/LayerState_test.cpp @@ -114,34 +114,5 @@ TEST(LayerStateTest, ParcellingScreenCaptureResults) { ASSERT_EQ(results.result, results2.result); } -/** - * Parcel a layer_state_t struct, and then unparcel. Ensure that the object that was parceled - * matches the object that's unparceled. - */ -TEST(LayerStateTest, ParcelUnparcelLayerStateT) { - layer_state_t input; - input.frameTimelineInfo.vsyncId = 1; - input.frameTimelineInfo.inputEventId = 2; - Parcel p; - input.write(p); - layer_state_t output; - p.setDataPosition(0); - output.read(p); - ASSERT_EQ(input.frameTimelineInfo.vsyncId, output.frameTimelineInfo.vsyncId); - ASSERT_EQ(input.frameTimelineInfo.inputEventId, output.frameTimelineInfo.inputEventId); -} - -TEST(LayerStateTest, LayerStateMerge_SelectsValidInputEvent) { - layer_state_t layer1; - layer1.frameTimelineInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; - layer_state_t layer2; - layer2.frameTimelineInfo.inputEventId = 1; - layer2.what |= layer_state_t::eFrameTimelineInfoChanged; - - layer1.merge(layer2); - - ASSERT_EQ(1, layer1.frameTimelineInfo.inputEventId); -} - } // namespace test } // namespace android -- cgit v1.2.3-59-g8ed1b From aad6cf53e8cf0f527d2ef0415922f04ad1b8680f Mon Sep 17 00:00:00 2001 From: chaviw Date: Tue, 23 Mar 2021 17:27:20 -0500 Subject: Clear transaction that's passed to mergeWithNextTransaction The std::move wasn't actually clearing the incoming transaction so it was possible for the transaction to get applied by something else. This would cause unexpected behavior since the caller intented for the transaction to be merged with the next frame. Instead, just explicitly clear the transaction after storing in the vector. Test: No longer flickers when resizing pip Fixes: 182985130 Change-Id: Ie6ed0825074fb51ae3c260832002c012606241a1 --- libs/gui/BLASTBufferQueue.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index f778232803..ab75d03312 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -608,7 +608,9 @@ void BLASTBufferQueue::mergeWithNextTransaction(SurfaceComposerClient::Transacti // Apply the transaction since we have already acquired the desired frame. t->apply(); } else { - mPendingTransactions.emplace_back(frameNumber, std::move(*t)); + mPendingTransactions.emplace_back(frameNumber, *t); + // Clear the transaction so it can't be applied elsewhere. + t->clear(); } } -- cgit v1.2.3-59-g8ed1b From c5986778d0d6c7ab3f96fafb1b84887e901ed92b Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Tue, 16 Mar 2021 16:09:49 +0100 Subject: setFrameRate: Make shouldBeSeamless an enum Change the shouldBeSeamless parameter to an enum in order to make the API easier to understand. This changes - SurfaceControl.setFrameRate - Surface.setFrameRate - ANativeWindow_setFrameRateWithChangeStrategy - ASurfaceTransaction_setFrameRateWithChangeStrategy Bug: 179116474 Test: atest SetFrameRateTest Change-Id: I28a8863ea77101f90b878fbda5f00d98e075b7cc --- include/android/surface_control.h | 18 +++-- libs/gui/BLASTBufferQueue.cpp | 8 ++- libs/gui/ISurfaceComposer.cpp | 76 ++++++---------------- libs/gui/LayerState.cpp | 19 ++++-- libs/gui/Surface.cpp | 12 ++-- libs/gui/SurfaceComposerClient.cpp | 7 +- libs/gui/include/gui/ISurfaceComposer.h | 2 +- libs/gui/include/gui/LayerState.h | 7 +- libs/gui/include/gui/Surface.h | 3 +- libs/gui/include/gui/SurfaceComposerClient.h | 2 +- libs/gui/tests/Surface_test.cpp | 2 +- libs/nativewindow/ANativeWindow.cpp | 10 +-- libs/nativewindow/include/android/native_window.h | 31 ++++++--- libs/nativewindow/include/system/window.h | 4 +- libs/nativewindow/libnativewindow.map.txt | 2 +- services/surfaceflinger/Layer.cpp | 12 ++++ services/surfaceflinger/Layer.h | 13 ++-- services/surfaceflinger/SurfaceFlinger.cpp | 26 +++++--- services/surfaceflinger/SurfaceFlinger.h | 2 +- .../tests/unittests/SetFrameRateTest.cpp | 38 ++++++++--- 20 files changed, 159 insertions(+), 135 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/include/android/surface_control.h b/include/android/surface_control.h index c17f8224c2..26b63d2005 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -420,10 +420,10 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio __INTRODUCED_IN(29); /** - * Same as ASurfaceTransaction_setFrameRateWithSeamlessness(transaction, surface_control, - * frameRate, compatibility, true). + * Same as ASurfaceTransaction_setFrameRateWithChangeStrategy(transaction, surface_control, + * frameRate, compatibility, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS). * - * See ASurfaceTransaction_setFrameRateWithSeamlessness(). + * See ASurfaceTransaction_setFrameRateWithChangeStrategy(). * * Available since API level 30. */ @@ -451,17 +451,15 @@ void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, * influence the system's choice of display frame rate. To specify a compatibility use the * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum. * - * \param shouldBeSeamless Whether display refresh rate transitions should be seamless. A - * seamless transition is one that doesn't have any visual interruptions, such as a black - * screen for a second or two. True indicates that any frame rate changes caused by this - * request should be seamless. False indicates that non-seamless refresh rates are also - * acceptable. + * \param changeFrameRateStrategy Whether display refresh rate transitions should be seamless. + * A seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. See the ANATIVEWINDOW_CHANGE_FRAME_RATE_* values. * * Available since API level 31. */ -void ASurfaceTransaction_setFrameRateWithSeamlessness(ASurfaceTransaction* transaction, +void ASurfaceTransaction_setFrameRateWithChangeStrategy(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, float frameRate, - int8_t compatibility, bool shouldBeSeamless) + int8_t compatibility, int8_t changeFrameRateStrategy) __INTRODUCED_IN(31); __END_DECLS diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 82c9268feb..3f545b25e5 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -544,11 +544,13 @@ public: }).detach(); } - status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless) override { - if (!ValidateFrameRate(frameRate, compatibility, "BBQSurface::setFrameRate")) { + status_t setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override { + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "BBQSurface::setFrameRate")) { return BAD_VALUE; } - return mBbq->setFrameRate(frameRate, compatibility, shouldBeSeamless); + return mBbq->setFrameRate(frameRate, compatibility, changeFrameRateStrategy); } status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override { diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index f44f10a2ce..71215fef36 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1012,39 +1012,15 @@ public: } status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) override { + int8_t compatibility, int8_t changeFrameRateStrategy) override { Parcel data, reply; - status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed writing interface token: %s (%d)", strerror(-err), -err); - return err; - } - - err = data.writeStrongBinder(IInterface::asBinder(surface)); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed writing strong binder: %s (%d)", strerror(-err), -err); - return err; - } - - err = data.writeFloat(frameRate); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed writing float: %s (%d)", strerror(-err), -err); - return err; - } - - err = data.writeByte(compatibility); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed writing byte: %s (%d)", strerror(-err), -err); - return err; - } - - err = data.writeBool(shouldBeSeamless); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed writing bool: %s (%d)", strerror(-err), -err); - return err; - } + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(surface)); + SAFE_PARCEL(data.writeFloat, frameRate); + SAFE_PARCEL(data.writeByte, compatibility); + SAFE_PARCEL(data.writeByte, changeFrameRateStrategy); - err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); + status_t err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); if (err != NO_ERROR) { ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); return err; @@ -1873,36 +1849,24 @@ status_t BnSurfaceComposer::onTransact( case SET_FRAME_RATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp binder; - status_t err = data.readStrongBinder(&binder); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed to read strong binder: %s (%d)", strerror(-err), -err); - return err; - } + SAFE_PARCEL(data.readStrongBinder, &binder); + sp surface = interface_cast(binder); if (!surface) { - ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer: %s (%d)", - strerror(-err), -err); - return err; + ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer"); + return BAD_VALUE; } float frameRate; - err = data.readFloat(&frameRate); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed to read float: %s (%d)", strerror(-err), -err); - return err; - } + SAFE_PARCEL(data.readFloat, &frameRate); + int8_t compatibility; - err = data.readByte(&compatibility); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err); - return err; - } - bool shouldBeSeamless; - err = data.readBool(&shouldBeSeamless); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed to read bool: %s (%d)", strerror(-err), -err); - return err; - } - status_t result = setFrameRate(surface, frameRate, compatibility, shouldBeSeamless); + SAFE_PARCEL(data.readByte, &compatibility); + + int8_t changeFrameRateStrategy; + SAFE_PARCEL(data.readByte, &changeFrameRateStrategy); + + status_t result = + setFrameRate(surface, frameRate, compatibility, changeFrameRateStrategy); reply->writeInt32(result); return NO_ERROR; } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 04a878563e..2c4dfc54f3 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -60,7 +61,7 @@ layer_state_t::layer_state_t() frameRateSelectionPriority(-1), frameRate(0.0f), frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), - shouldBeSeamless(true), + changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS), fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0), frameTimelineInfo(), @@ -148,7 +149,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority); SAFE_PARCEL(output.writeFloat, frameRate); SAFE_PARCEL(output.writeByte, frameRateCompatibility); - SAFE_PARCEL(output.writeBool, shouldBeSeamless); + SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); SAFE_PARCEL(frameTimelineInfo.write, output); @@ -269,7 +270,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readInt32, &frameRateSelectionPriority); SAFE_PARCEL(input.readFloat, &frameRate); SAFE_PARCEL(input.readByte, &frameRateCompatibility); - SAFE_PARCEL(input.readBool, &shouldBeSeamless); + SAFE_PARCEL(input.readByte, &changeFrameRateStrategy); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); @@ -526,7 +527,7 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameRateChanged; frameRate = other.frameRate; frameRateCompatibility = other.frameRateCompatibility; - shouldBeSeamless = other.shouldBeSeamless; + changeFrameRateStrategy = other.changeFrameRateStrategy; } if (other.what & eFixedTransformHintChanged) { what |= eFixedTransformHintChanged; @@ -616,8 +617,8 @@ status_t InputWindowCommands::read(const Parcel& input) { return NO_ERROR; } -bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName, - bool privileged) { +bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, + const char* inFunctionName, bool privileged) { const char* functionName = inFunctionName != nullptr ? inFunctionName : "call"; int floatClassification = std::fpclassify(frameRate); if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) { @@ -633,6 +634,12 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunc return false; } + if (changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS && + changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS) { + ALOGE("%s failed - invalid change frame rate strategy value %d", functionName, + changeFrameRateStrategy); + } + return true; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 6de3e971b2..2fc9d47b89 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1729,8 +1729,8 @@ int Surface::dispatchGetLastQueueDuration(va_list args) { int Surface::dispatchSetFrameRate(va_list args) { float frameRate = static_cast(va_arg(args, double)); int8_t compatibility = static_cast(va_arg(args, int)); - bool shouldBeSeamless = static_cast(va_arg(args, int)); - return setFrameRate(frameRate, compatibility, shouldBeSeamless); + int8_t changeFrameRateStrategy = static_cast(va_arg(args, int)); + return setFrameRate(frameRate, compatibility, changeFrameRateStrategy); } int Surface::dispatchAddCancelInterceptor(va_list args) { @@ -2575,16 +2575,18 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vectoronBuffersDiscarded(discardedBufs); } -status_t Surface::setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless) { +status_t Surface::setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { ATRACE_CALL(); ALOGV("Surface::setFrameRate"); - if (!ValidateFrameRate(frameRate, compatibility, "Surface::setFrameRate")) { + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "Surface::setFrameRate")) { return BAD_VALUE; } return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility, - shouldBeSeamless); + changeFrameRateStrategy); } status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 18a0cbd1c0..3c10858dfe 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1511,7 +1511,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setShado SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate( const sp& sc, float frameRate, int8_t compatibility, - bool shouldBeSeamless) { + int8_t changeFrameRateStrategy) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1519,7 +1519,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame } // Allow privileged values as well here, those will be ignored by SF if // the caller is not privileged - if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate", + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "Transaction::setFrameRate", /*privileged=*/true)) { mStatus = BAD_VALUE; return *this; @@ -1527,7 +1528,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame s->what |= layer_state_t::eFrameRateChanged; s->frameRate = frameRate; s->frameRateCompatibility = compatibility; - s->shouldBeSeamless = shouldBeSeamless; + s->changeFrameRateStrategy = changeFrameRateStrategy; return *this; } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 88cfe4b9ac..3cf9a733b6 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -461,7 +461,7 @@ public: * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info. */ virtual status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) = 0; + int8_t compatibility, int8_t changeFrameRateStrategy) = 0; /* * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired, diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index f7a66985b7..cc8cc0d3ae 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -208,7 +208,7 @@ struct layer_state_t { // Layer frame rate and compatibility. See ANativeWindow_setFrameRate(). float frameRate; int8_t frameRateCompatibility; - bool shouldBeSeamless; + int8_t changeFrameRateStrategy; // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that @@ -305,10 +305,11 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) // // @param frameRate the frame rate in Hz // @param compatibility a ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* +// @param changeFrameRateStrategy a ANATIVEWINDOW_CHANGE_FRAME_RATE_* // @param functionName calling function or nullptr. Used for logging // @param privileged whether caller has unscoped surfaceflinger access -bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName, - bool privileged = false); +bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, + const char* functionName, bool privileged = false); struct CaptureArgs { const static int32_t UNSET_UID = -1; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 58812214d2..d22bdaaa98 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -187,7 +187,8 @@ public: status_t getUniqueId(uint64_t* outId) const; status_t getConsumerUsage(uint64_t* outUsage) const; - virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); + virtual status_t setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy); virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info); virtual status_t getExtraBufferCount(int* extraBuffers) const; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 40c4135a51..4997e36899 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -509,7 +509,7 @@ public: Transaction& setShadowRadius(const sp& sc, float cornerRadius); Transaction& setFrameRate(const sp& sc, float frameRate, - int8_t compatibility, bool shouldBeSeamless); + int8_t compatibility, int8_t changeFrameRateStrategy); // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e8fb71dc1d..68c834de63 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -855,7 +855,7 @@ public: } status_t setFrameRate(const sp& /*surface*/, float /*frameRate*/, - int8_t /*compatibility*/, bool /*shouldBeSeamless*/) override { + int8_t /*compatibility*/, int8_t /*changeFrameRateStrategy*/) override { return NO_ERROR; } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index b406a9c2fe..ada689ac42 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -159,8 +159,8 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) { } int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) { - return ANativeWindow_setFrameRateWithSeamlessness(window, frameRate, compatibility, - /*shouldBeSeamless*/ true); + return ANativeWindow_setFrameRateWithChangeStrategy(window, frameRate, compatibility, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); } void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { @@ -170,12 +170,12 @@ void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS); } -int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, - int8_t compatibility, bool shouldBeSeamless) { +int32_t ANativeWindow_setFrameRateWithChangeStrategy(ANativeWindow* window, float frameRate, + int8_t compatibility, int8_t changeFrameRateStrategy) { if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { return -EINVAL; } - return native_window_set_frame_rate(window, frameRate, compatibility, shouldBeSeamless); + return native_window_set_frame_rate(window, frameRate, compatibility, changeFrameRateStrategy); } /************************************************************************************************** diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 285f2fb7fe..50e9d53604 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -247,9 +247,10 @@ enum ANativeWindow_FrameRateCompatibility { }; /** - * Same as ANativeWindow_setFrameRateWithSeamlessness(window, frameRate, compatibility, true). + * Same as ANativeWindow_setFrameRateWithChangeStrategy(window, frameRate, compatibility, + * ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS). * - * See ANativeWindow_setFrameRateWithSeamlessness(). + * See ANativeWindow_setFrameRateWithChangeStrategy(). * * Available since API level 30. */ @@ -267,6 +268,19 @@ int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_ */ void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) __INTRODUCED_IN(30); +/** Change frame rate strategy value for ANativeWindow_setFrameRate. */ +enum ANativeWindow_ChangeFrameRateStrategy { + /** + * Change the frame rate only if the transition is going to be seamless. + */ + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0, + /** + * Change the frame rate even if the transition is going to be non-seamless, + * i.e. with visual interruptions for the user. + */ + ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS = 1 +} __INTRODUCED_IN(31); + /** * Sets the intended frame rate for this window. * @@ -296,17 +310,16 @@ void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) __INTRODUCED_IN(30) * compatibility value may influence the system's choice of display refresh * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. * - * \param shouldBeSeamless Whether display refresh rate transitions should be seamless. A - * seamless transition is one that doesn't have any visual interruptions, such as a black - * screen for a second or two. True indicates that any frame rate changes caused by this - * request should be seamless. False indicates that non-seamless refresh rates are also - * acceptable. + * \param changeFrameRateStrategy Whether display refresh rate transitions should be seamless. + * A seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. See the ANATIVEWINDOW_CHANGE_FRAME_RATE_* values. * * \return 0 for success, -EINVAL if the window, frame rate, or compatibility * value are invalid. */ -int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, - int8_t compatibility, bool shouldBeSeamless) __INTRODUCED_IN(31); +int32_t ANativeWindow_setFrameRateWithChangeStrategy(ANativeWindow* window, float frameRate, + int8_t compatibility, int8_t changeFrameRateStrategy) + __INTRODUCED_IN(31); #ifdef __cplusplus }; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 7aa2cf4404..cc82bb4699 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1019,9 +1019,9 @@ static inline int native_window_set_auto_prerotation(struct ANativeWindow* windo } static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, - int8_t compatibility, bool shouldBeSeamless) { + int8_t compatibility, int8_t changeFrameRateStrategy) { return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, - (int)compatibility, (int)shouldBeSeamless); + (int)compatibility, (int)changeFrameRateStrategy); } static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window, diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 24d0e3badc..988132cd1c 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -47,7 +47,7 @@ LIBNATIVEWINDOW { ANativeWindow_setBuffersTransform; ANativeWindow_setDequeueTimeout; # apex # introduced=30 ANativeWindow_setFrameRate; # introduced=30 - ANativeWindow_setFrameRateWithSeamlessness; # introduced=31 + ANativeWindow_setFrameRateWithChangeStrategy; # introduced=31 ANativeWindow_setSharedBufferMode; # llndk ANativeWindow_setSwapInterval; # llndk ANativeWindow_setUsage; # llndk diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0015bf27d1..782a7553f0 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2864,6 +2864,18 @@ Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t comp } } +scheduler::Seamlessness Layer::FrameRate::convertChangeFrameRateStrategy(int8_t strategy) { + switch (strategy) { + case ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS: + return Seamlessness::OnlySeamless; + case ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS: + return Seamlessness::SeamedAndSeamless; + default: + LOG_ALWAYS_FATAL("Invalid change frame sate strategy value %d", strategy); + return Seamlessness::Default; + } +} + bool Layer::getPrimaryDisplayOnly() const { const State& s(mDrawingState); if (s.flags & layer_state_t::eLayerSkipScreenshot) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 26d8e7472a..8534844a41 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -168,8 +168,9 @@ public: : rate(0), type(FrameRateCompatibility::Default), seamlessness(Seamlessness::Default) {} - FrameRate(Fps rate, FrameRateCompatibility type, bool shouldBeSeamless = true) - : rate(rate), type(type), seamlessness(getSeamlessness(rate, shouldBeSeamless)) {} + FrameRate(Fps rate, FrameRateCompatibility type, + Seamlessness seamlessness = Seamlessness::OnlySeamless) + : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} bool operator==(const FrameRate& other) const { return rate.equalsWithMargin(other.rate) && type == other.type && @@ -181,18 +182,16 @@ public: // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. static FrameRateCompatibility convertCompatibility(int8_t compatibility); + static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); private: - static Seamlessness getSeamlessness(Fps rate, bool shouldBeSeamless) { + static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) { if (!rate.isValid()) { // Refresh rate of 0 is a special value which should reset the vote to // its default value. return Seamlessness::Default; - } else if (shouldBeSeamless) { - return Seamlessness::OnlySeamless; - } else { - return Seamlessness::SeamedAndSeamless; } + return seamlessness; } }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9da94832ae..7e8df89a4b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3948,13 +3948,16 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } if (what & layer_state_t::eFrameRateChanged) { - if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility, - "SurfaceFlinger::setClientStateLocked", privileged) && - layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), - Layer::FrameRate::convertCompatibility( - s.frameRateCompatibility), - s.shouldBeSeamless))) { - flags |= eTraversalNeeded; + if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility, s.changeFrameRateStrategy, + "SurfaceFlinger::setClientStateLocked", privileged)) { + const auto compatibility = + Layer::FrameRate::convertCompatibility(s.frameRateCompatibility); + const auto strategy = + Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy); + + if (layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), compatibility, strategy))) { + flags |= eTraversalNeeded; + } } } FrameTimelineInfo info; @@ -6367,8 +6370,9 @@ const std::unordered_map& SurfaceFlinger::getGenericLayer } status_t SurfaceFlinger::setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) { - if (!ValidateFrameRate(frameRate, compatibility, "SurfaceFlinger::setFrameRate")) { + int8_t compatibility, int8_t changeFrameRateStrategy) { + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "SurfaceFlinger::setFrameRate")) { return BAD_VALUE; } @@ -6380,10 +6384,12 @@ status_t SurfaceFlinger::setFrameRate(const sp& surface, ALOGE("Attempt to set frame rate on a layer that no longer exists"); return BAD_VALUE; } + const auto strategy = + Layer::FrameRate::convertChangeFrameRateStrategy(changeFrameRateStrategy); if (layer->setFrameRate( Layer::FrameRate(Fps{frameRate}, Layer::FrameRate::convertCompatibility(compatibility), - shouldBeSeamless))) { + strategy))) { setTransactionFlags(eTraversalNeeded); } } else { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 3787b9db89..65e00198b3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -685,7 +685,7 @@ private: status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) override; status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) override; + int8_t compatibility, int8_t changeFrameRateStrategy) override; status_t acquireFrameRateFlexibilityToken(sp* outToken) override; status_t setFrameTimelineInfo(const sp& surface, diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 5c8c2d888c..7ef1f2b378 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -475,18 +475,36 @@ INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest, PrintToStringParamName); TEST_F(SetFrameRateTest, ValidateFrameRate) { - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, "", /*privileged=*/true)); - - EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); - EXPECT_FALSE( - ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", + /*privileged=*/true)); + + EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + // Invalid compatibility EXPECT_FALSE( - ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); + ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, "")); + // Invalid change frame rate strategy + EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, -1, "")); + EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, 2, "")); } TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { -- cgit v1.2.3-59-g8ed1b From 9a93ea66bb7116b8821877a69991ae94557b1303 Mon Sep 17 00:00:00 2001 From: chaviw Date: Thu, 11 Mar 2021 16:44:42 -0600 Subject: Remove setFrame from BufferStateLayer Replace setFrame with setCrop, setMatrix, and setPosition Test: SurfaceFlinger_tests Test: ASurfaceControlTest Bug: 170765639 Change-Id: I32ee0e3e48e5171d99a5f5af0b7583165d4dd9f9 --- libs/gui/BLASTBufferQueue.cpp | 29 +++- libs/gui/LayerState.cpp | 4 - libs/gui/SurfaceComposerClient.cpp | 14 -- libs/gui/include/gui/BLASTBufferQueue.h | 32 +++- libs/gui/include/gui/LayerState.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 1 - libs/gui/tests/BLASTBufferQueue_test.cpp | 34 ++-- services/surfaceflinger/BufferStateLayer.cpp | 98 +++++------- services/surfaceflinger/BufferStateLayer.h | 10 +- services/surfaceflinger/Layer.cpp | 4 +- services/surfaceflinger/Layer.h | 1 - services/surfaceflinger/RefreshRateOverlay.cpp | 8 +- services/surfaceflinger/SurfaceFlinger.cpp | 3 - services/surfaceflinger/tests/BufferGenerator.cpp | 14 +- services/surfaceflinger/tests/BufferGenerator.h | 2 + services/surfaceflinger/tests/EffectLayer_test.cpp | 1 - services/surfaceflinger/tests/IPC_test.cpp | 1 - .../surfaceflinger/tests/LayerCallback_test.cpp | 131 +++++++++++++--- .../tests/LayerRenderTypeTransaction_test.cpp | 174 ++++++++++----------- .../surfaceflinger/tests/LayerTransactionTest.h | 5 + .../LayerTypeAndRenderTypeTransaction_test.cpp | 60 ++----- services/surfaceflinger/tests/MirrorLayer_test.cpp | 2 +- .../surfaceflinger/tests/utils/TransactionUtils.h | 18 ++- 23 files changed, 353 insertions(+), 295 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 1976b493b2..1d7ed2f97b 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -204,13 +204,16 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, if (mRequestedSize != newSize) { mRequestedSize.set(newSize); mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height); - if (mLastBufferScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { + if (mLastBufferInfo.scalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { // If the buffer supports scaling, update the frame immediately since the client may // want to scale the existing buffer to the new size. mSize = mRequestedSize; - t.setFrame(mSurfaceControl, - {0, 0, static_cast(mSize.width), - static_cast(mSize.height)}); + // We only need to update the scale if we've received at least one buffer. The reason + // for this is the scale is calculated based on the requested size and buffer size. + // If there's no buffer, the scale will always be 1. + if (mLastBufferInfo.hasBuffer) { + setMatrix(&t, mLastBufferInfo); + } applyTransaction = true; } } @@ -374,8 +377,10 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); - mLastBufferScalingMode = bufferItem.mScalingMode; mLastAcquiredFrameNumber = bufferItem.mFrameNumber; + mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(), + bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, + bufferItem.mScalingMode); auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp(this) /* callbackContext */, @@ -388,8 +393,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); - t->setFrame(mSurfaceControl, - {0, 0, static_cast(mSize.width), static_cast(mSize.height)}); + setMatrix(t, mLastBufferInfo); t->setCrop(mSurfaceControl, computeCrop(bufferItem)); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); @@ -515,6 +519,17 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { return mSize != bufferSize; } +void BLASTBufferQueue::setMatrix(SurfaceComposerClient::Transaction* t, + const BufferInfo& bufferInfo) { + uint32_t bufWidth = bufferInfo.width; + uint32_t bufHeight = bufferInfo.height; + + float dsdx = mSize.width / static_cast(bufWidth); + float dsdy = mSize.height / static_cast(bufHeight); + + t->setMatrix(mSurfaceControl, dsdx, 0, 0, dsdy); +} + void BLASTBufferQueue::setTransactionCompleteCallback( uint64_t frameNumber, std::function&& transactionCompleteCallback) { std::lock_guard _lock{mMutex}; diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index d653ae71be..8c21553bff 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -458,10 +458,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eCropChanged; crop = other.crop; } - if (other.what & eFrameChanged) { - what |= eFrameChanged; - orientedDisplaySpaceRect = other.orientedDisplaySpaceRect; - } if (other.what & eBufferChanged) { what |= eBufferChanged; buffer = other.buffer; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 0b01084633..f12b77e48f 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1246,20 +1246,6 @@ SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp& sc, const Rect& frame) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eFrameChanged; - s->orientedDisplaySpaceRect = frame; - - registerSurfaceControlForCallback(sc); - return *this; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( const sp& sc, const sp& buffer, ReleaseBufferCallback callback) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index fbd16f4ea2..a48f95ae73 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -142,6 +142,33 @@ private: ui::Size mRequestedSize GUARDED_BY(mMutex); int32_t mFormat GUARDED_BY(mMutex); + struct BufferInfo { + bool hasBuffer = false; + uint32_t width; + uint32_t height; + uint32_t transform; + // This is used to check if we should update the blast layer size immediately or wait until + // we get the next buffer. This will support scenarios where the layer can change sizes + // and the buffer will scale to fit the new size. + uint32_t scalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; + + void update(bool hasBuffer, uint32_t width, uint32_t height, uint32_t transform, + uint32_t scalingMode) { + this->hasBuffer = hasBuffer; + this->width = width; + this->height = height; + this->transform = transform; + this->scalingMode = scalingMode; + } + }; + + // Last acquired buffer's info. This is used to calculate the correct scale when size change is + // requested. We need to use the old buffer's info to determine what scale we need to apply to + // ensure the correct size. + BufferInfo mLastBufferInfo GUARDED_BY(mMutex); + void setMatrix(SurfaceComposerClient::Transaction* t, const BufferInfo& bufferInfo) + REQUIRES(mMutex); + uint32_t mTransformHint GUARDED_BY(mMutex); sp mConsumer; @@ -159,11 +186,6 @@ private: std::queue mNextFrameTimelineInfoQueue GUARDED_BY(mMutex); - // Last acquired buffer's scaling mode. This is used to check if we should update the blast - // layer size immediately or wait until we get the next buffer. This will support scenarios - // where the layer can change sizes and the buffer will scale to fit the new size. - uint32_t mLastBufferScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; - // Tracks the last acquired frame number uint64_t mLastAcquiredFrameNumber GUARDED_BY(mMutex) = 0; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 92747779fd..9186ed289e 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -106,7 +106,7 @@ struct layer_state_t { eHasListenerCallbacksChanged = 0x20000000, eInputInfoChanged = 0x40000000, eCornerRadiusChanged = 0x80000000, - eFrameChanged = 0x1'00000000, + /* was eFrameChanged, now available 0x1'00000000, */ eCachedBufferChanged = 0x2'00000000, eBackgroundColorChanged = 0x4'00000000, eMetadataChanged = 0x8'00000000, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index c38375cf77..19d898c96a 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -474,7 +474,6 @@ public: Transaction& setTransform(const sp& sc, uint32_t transform); Transaction& setTransformToDisplayInverse(const sp& sc, bool transformToDisplayInverse); - Transaction& setFrame(const sp& sc, const Rect& frame); Transaction& setBuffer(const sp& sc, const sp& buffer, ReleaseBufferCallback callback = nullptr); Transaction& setCachedBuffer(const sp& sc, int32_t bufferId); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index fe48d88376..9b1f0db83b 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -140,7 +140,6 @@ protected: /*parent*/ nullptr); t.setLayerStack(mSurfaceControl, 0) .setLayer(mSurfaceControl, std::numeric_limits::max()) - .setFrame(mSurfaceControl, Rect(resolution)) .show(mSurfaceControl) .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) .apply(); @@ -218,13 +217,13 @@ protected: col >= region.left - border && col < region.right + border; } if (!outsideRegion && inRegion) { - EXPECT_GE(epsilon, abs(r - *(pixel))); - EXPECT_GE(epsilon, abs(g - *(pixel + 1))); - EXPECT_GE(epsilon, abs(b - *(pixel + 2))); + ASSERT_GE(epsilon, abs(r - *(pixel))); + ASSERT_GE(epsilon, abs(g - *(pixel + 1))); + ASSERT_GE(epsilon, abs(b - *(pixel + 2))); } else if (outsideRegion && !inRegion) { - EXPECT_GE(epsilon, abs(r - *(pixel))); - EXPECT_GE(epsilon, abs(g - *(pixel + 1))); - EXPECT_GE(epsilon, abs(b - *(pixel + 2))); + ASSERT_GE(epsilon, abs(r - *(pixel))); + ASSERT_GE(epsilon, abs(g - *(pixel + 1))); + ASSERT_GE(epsilon, abs(b - *(pixel + 2))); } ASSERT_EQ(false, ::testing::Test::HasFailure()); } @@ -466,7 +465,8 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + checkScreenCapture(r, g, b, + {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); } TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { @@ -523,13 +523,15 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + Rect bounds; + bounds.left = finalCropSideLength / 2; + bounds.top = 0; + bounds.right = bounds.left + finalCropSideLength; + bounds.bottom = finalCropSideLength; + + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, bounds)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, - {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength})); - ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(0, 0, 0, - {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength}, - /*border*/ 0, /*outsideRegion*/ true)); + checkScreenCapture(0, 0, 0, bounds, /*border*/ 0, /*outsideRegion*/ true)); } class TestProducerListener : public BnProducerListener { @@ -596,7 +598,6 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { t.setLayerStack(bgSurface, 0) .show(bgSurface) .setDataspace(bgSurface, ui::Dataspace::V0_SRGB) - .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setLayer(bgSurface, std::numeric_limits::max() - 1) .apply(); @@ -619,7 +620,8 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + checkScreenCapture(r, g, b, + {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); } class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index a974dc4488..7a10769757 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -278,9 +278,8 @@ bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) { return stateUpdateAvailable; } -// Crop that applies to the window -Rect BufferStateLayer::getCrop(const Layer::State& /*s*/) const { - return Rect::INVALID_RECT; +Rect BufferStateLayer::getCrop(const Layer::State& s) const { + return s.crop; } bool BufferStateLayer::setTransform(uint32_t transform) { @@ -301,57 +300,53 @@ bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInver } bool BufferStateLayer::setCrop(const Rect& crop) { - Rect c = crop; - if (c.left < 0) { - c.left = 0; - } - if (c.top < 0) { - c.top = 0; - } - // If the width and/or height are < 0, make it [0, 0, -1, -1] so the equality comparision below - // treats all invalid rectangles the same. - if (!c.isValid()) { - c.makeInvalid(); - } + if (mCurrentState.crop == crop) return false; + mCurrentState.sequence++; + mCurrentState.crop = crop; - if (mCurrentState.crop == c) return false; - mCurrentState.crop = c; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } -bool BufferStateLayer::setFrame(const Rect& frame) { - int x = frame.left; - int y = frame.top; - int w = frame.getWidth(); - int h = frame.getHeight(); - - if (x < 0) { - x = 0; - w = frame.right; +bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix, + bool allowNonRectPreservingTransforms) { + if (mCurrentState.transform.dsdx() == matrix.dsdx && + mCurrentState.transform.dtdy() == matrix.dtdy && + mCurrentState.transform.dtdx() == matrix.dtdx && + mCurrentState.transform.dsdy() == matrix.dsdy) { + return false; } - if (y < 0) { - y = 0; - h = frame.bottom; - } + ui::Transform t; + t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y && - mCurrentState.width == w && mCurrentState.height == h) { + if (!allowNonRectPreservingTransforms && !t.preserveRects()) { + ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER nor " + "ROTATE_SURFACE_FLINGER ignored"); return false; } - if (!frame.isValid()) { - x = y = w = h = 0; + mCurrentState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); + + mCurrentState.sequence++; + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); + + return true; +} + +bool BufferStateLayer::setPosition(float x, float y) { + if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) { + return false; } + mCurrentState.transform.set(x, y); - mCurrentState.width = w; - mCurrentState.height = h; mCurrentState.sequence++; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); + return true; } @@ -428,6 +423,10 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const spmFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime, FrameTracer::FrameEvent::QUEUE); } + + mCurrentState.width = mCurrentState.buffer->width; + mCurrentState.height = mCurrentState.buffer->height; + return true; } @@ -855,33 +854,6 @@ sp BufferStateLayer::createClone() { return layer; } -Layer::RoundedCornerState BufferStateLayer::getRoundedCornerState() const { - const auto& p = mDrawingParent.promote(); - if (p != nullptr) { - RoundedCornerState parentState = p->getRoundedCornerState(); - if (parentState.radius > 0) { - ui::Transform t = getActiveTransform(getDrawingState()); - t = t.inverse(); - parentState.cropRect = t.transform(parentState.cropRect); - // The rounded corners shader only accepts 1 corner radius for performance reasons, - // but a transform matrix can define horizontal and vertical scales. - // Let's take the average between both of them and pass into the shader, practically we - // never do this type of transformation on windows anyway. - parentState.radius *= (t[0][0] + t[1][1]) / 2.0f; - return parentState; - } - } - const float radius = getDrawingState().cornerRadius; - const State& s(getDrawingState()); - if (radius <= 0 || (getActiveWidth(s) == UINT32_MAX && getActiveHeight(s) == UINT32_MAX)) - return RoundedCornerState(); - return RoundedCornerState(FloatRect(static_cast(s.transform.tx()), - static_cast(s.transform.ty()), - static_cast(s.transform.tx() + s.width), - static_cast(s.transform.ty() + s.height)), - radius); -} - bool BufferStateLayer::bufferNeedsFiltering() const { const State& s(getDrawingState()); if (!s.buffer) { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 7a3da6fec1..af2819eac7 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -66,7 +66,6 @@ public: bool setTransform(uint32_t transform) override; bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; - bool setFrame(const Rect& frame) override; bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, @@ -81,15 +80,13 @@ public: bool setTransactionCompletedListeners(const std::vector>& handles) override; bool addFrameEvent(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime) override; + bool setPosition(float /*x*/, float /*y*/) override; + bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, + bool /*allowNonRectPreservingTransforms*/); // Override to ignore legacy layer state properties that are not used by BufferStateLayer bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } - bool setPosition(float /*x*/, float /*y*/) override { return false; } bool setTransparentRegionHint(const Region& transparent) override; - bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, - bool /*allowNonRectPreservingTransforms*/) override { - return false; - } void deferTransactionUntil_legacy(const sp& /*barrierHandle*/, uint64_t /*frameNumber*/) override {} void deferTransactionUntil_legacy(const sp& /*barrierLayer*/, @@ -97,7 +94,6 @@ public: Rect getBufferSize(const State& s) const override; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; - Layer::RoundedCornerState getRoundedCornerState() const override; void setAutoRefresh(bool autoRefresh) override; // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index cd3e8add9a..447cbb3854 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2312,8 +2312,8 @@ Layer::RoundedCornerState Layer::getRoundedCornerState() const { } } const float radius = getDrawingState().cornerRadius; - return radius > 0 && getCrop(getDrawingState()).isValid() - ? RoundedCornerState(getCrop(getDrawingState()).toFloatRect(), radius) + return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid() + ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius) : RoundedCornerState(); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 1c5d6ecb03..4cd379b963 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -462,7 +462,6 @@ public: // Used only to set BufferStateLayer state virtual bool setTransform(uint32_t /*transform*/) { return false; }; virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; }; - virtual bool setFrame(const Rect& /*frame*/) { return false; }; virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 1d00cc38f2..7a3e433660 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -231,8 +231,14 @@ const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uin void RefreshRateOverlay::setViewport(ui::Size viewport) { Rect frame((3 * viewport.width) >> 4, viewport.height >> 5); frame.offsetBy(viewport.width >> 5, viewport.height >> 4); - mLayer->setFrame(frame); + layer_state_t::matrix22_t matrix; + matrix.dsdx = frame.getWidth() / static_cast(SevenSegmentDrawer::getWidth()); + matrix.dtdx = 0; + matrix.dtdy = 0; + matrix.dsdy = frame.getHeight() / static_cast(SevenSegmentDrawer::getHeight()); + mLayer->setMatrix(matrix, true); + mLayer->setPosition(frame.left, frame.top); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a387587d7f..b1d63f0ce7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3936,9 +3936,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (what & layer_state_t::eCropChanged) { if (layer->setCrop(s.crop)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eFrameChanged) { - if (layer->setFrame(s.orientedDisplaySpaceRect)) flags |= eTraversalNeeded; - } if (what & layer_state_t::eAcquireFenceChanged) { if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded; } diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp index 03f8e1afba..47a150dd35 100644 --- a/services/surfaceflinger/tests/BufferGenerator.cpp +++ b/services/surfaceflinger/tests/BufferGenerator.cpp @@ -296,12 +296,12 @@ private: BufferGenerator::BufferGenerator() : mSurfaceManager(new SurfaceManager), mEglManager(new EglManager), mProgram(new Program) { - const float width = 1000.0; - const float height = 1000.0; + mBufferSize.set(1000.0, 1000.0); auto setBufferWithContext = std::bind(setBuffer, std::placeholders::_1, std::placeholders::_2, this); - mSurfaceManager->initialize(width, height, HAL_PIXEL_FORMAT_RGBA_8888, setBufferWithContext); + mSurfaceManager->initialize(mBufferSize.width, mBufferSize.height, HAL_PIXEL_FORMAT_RGBA_8888, + setBufferWithContext); if (!mEglManager->initialize(mSurfaceManager->getSurface())) return; @@ -309,7 +309,9 @@ BufferGenerator::BufferGenerator() if (!mProgram->initialize(VERTEX_SHADER, FRAGMENT_SHADER)) return; mProgram->use(); - mProgram->bindVec4(0, vec4{width, height, 1.0f / width, 1.0f / height}); + mProgram->bindVec4(0, + vec4{mBufferSize.width, mBufferSize.height, 1.0f / mBufferSize.width, + 1.0f / mBufferSize.height}); mProgram->bindVec3(2, &SPHERICAL_HARMONICS[0], 4); glEnableVertexAttribArray(0); @@ -372,6 +374,10 @@ status_t BufferGenerator::get(sp* outBuffer, sp* outFence) return NO_ERROR; } +ui::Size BufferGenerator::getSize() { + return mBufferSize; +} + // static void BufferGenerator::setBuffer(const sp& buffer, int32_t fence, void* bufferGenerator) { diff --git a/services/surfaceflinger/tests/BufferGenerator.h b/services/surfaceflinger/tests/BufferGenerator.h index a3ffe86572..f7d548b6bf 100644 --- a/services/surfaceflinger/tests/BufferGenerator.h +++ b/services/surfaceflinger/tests/BufferGenerator.h @@ -37,6 +37,7 @@ public: /* Static callback that sets the fence on a particular instance */ static void setBuffer(const sp& buffer, int32_t fence, void* fenceGenerator); + ui::Size getSize(); private: bool mInitialized = false; @@ -53,6 +54,7 @@ private: using Epoch = std::chrono::time_point; Epoch mEpoch = std::chrono::steady_clock::now(); + ui::Size mBufferSize; }; } // namespace android diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp index f470eda7d3..af00ec7fc9 100644 --- a/services/surfaceflinger/tests/EffectLayer_test.cpp +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -149,7 +149,6 @@ TEST_F(EffectLayerTest, BlurEffectLayerIsVisible) { t.reparent(blurLayer, mParentLayer); t.setBackgroundBlurRadius(blurLayer, blurRadius); t.setCrop(blurLayer, blurRect); - t.setFrame(blurLayer, blurRect); t.setAlpha(blurLayer, 0.0f); t.show(blurLayer); }); diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp index a8647c3e50..9fa3d4c417 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -161,7 +161,6 @@ public: Color::RED); transaction->setLayerStack(mSurfaceControl, 0) .setLayer(mSurfaceControl, std::numeric_limits::max()) - .setFrame(mSurfaceControl, Rect(0, 0, width, height)) .setBuffer(mSurfaceControl, gb) .setAcquireFence(mSurfaceControl, fence) .show(mSurfaceControl) diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 158801a705..011ff70409 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -164,7 +164,10 @@ TEST_F(LayerCallbackTest, NoBufferNoColor) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer, @@ -184,7 +187,10 @@ TEST_F(LayerCallbackTest, BufferNoColor) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -203,7 +209,10 @@ TEST_F(LayerCallbackTest, NoBufferColor) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, @@ -238,7 +247,10 @@ TEST_F(LayerCallbackTest, OffScreen) { return; } - transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(-100, -100, 100, 100)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -263,8 +275,15 @@ TEST_F(LayerCallbackTest, MergeBufferNoColor) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -290,8 +309,15 @@ TEST_F(LayerCallbackTest, MergeNoBufferColor) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -318,8 +344,15 @@ TEST_F(LayerCallbackTest, MergeOneBufferOneColor) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1); @@ -405,8 +438,15 @@ TEST_F(LayerCallbackTest, Merge_DifferentClients) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -491,7 +531,11 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) { } } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED @@ -523,8 +567,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -564,8 +616,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -606,8 +666,15 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateCha return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -661,8 +728,15 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -682,7 +756,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC return; } - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + transaction2.merge(std::move(transaction1)).apply(); expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2, ExpectedResult::Buffer::NOT_ACQUIRED); @@ -762,7 +839,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expectedResult; expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -781,7 +861,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + TransactionUtils::setFrame(transaction, layer, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); } EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 7505e6ea9b..53d230abe7 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -204,11 +204,7 @@ void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply(); break; case ISurfaceComposerClient::eFXSurfaceBufferState: - Transaction() - .setFrame(layerR, Rect(0, 0, 32, 32)) - .setFrame(layerG, Rect(16, 16, 48, 48)) - .setRelativeLayer(layerG, layerR, 1) - .apply(); + Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply(); break; default: ASSERT_FALSE(true) << "Unsupported layer type"; @@ -260,10 +256,9 @@ void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) break; case ISurfaceComposerClient::eFXSurfaceBufferState: Transaction() - .setFrame(layerR, Rect(0, 0, 32, 32)) - .setFrame(layerG, Rect(8, 8, 40, 40)) + .setPosition(layerG, 8, 8) .setRelativeLayer(layerG, layerR, 3) - .setFrame(layerB, Rect(16, 16, 48, 48)) + .setPosition(layerB, 16, 16) .setLayer(layerB, mLayerZBase + 2) .apply(); break; @@ -388,7 +383,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState Transaction() .setTransparentRegionHint(layer, Region(top)) .setBuffer(layer, buffer) - .setFrame(layer, Rect(0, 0, 32, 32)) .apply(); { SCOPED_TRACE("top transparent"); @@ -447,7 +441,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_Buffe // check that transparent region hint is bound by the layer size Transaction() .setTransparentRegionHint(layerTransparent, Region(mDisplayRect)) - .setFrame(layerR, Rect(16, 16, 48, 48)) + .setPosition(layerR, 16, 16) .setLayer(layerR, mLayerZBase + 1) .apply(); ASSERT_NO_FATAL_FAILURE( @@ -477,8 +471,7 @@ void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) { Transaction() .setAlpha(layer1, 0.25f) .setAlpha(layer2, 0.75f) - .setFrame(layer1, Rect(0, 0, 32, 32)) - .setFrame(layer2, Rect(16, 0, 48, 32)) + .setPosition(layer2, 16, 0) .setLayer(layer2, mLayerZBase + 1) .apply(); break; @@ -573,7 +566,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height)); expectedColor = fillColor; } - Transaction().setFrame(layer, Rect(0, 0, width, height)).apply(); + Transaction().setCrop(layer, Rect(0, 0, width, height)).apply(); break; default: GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper"; @@ -849,42 +842,39 @@ TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE)); - Transaction() - .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f) - .setFrame(layer, Rect(0, 0, 32, 32)) - .apply(); + Transaction().setPosition(layer, 32, 32).setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).apply(); { SCOPED_TRACE("IDENTITY"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, + getScreenCapture()->expectQuadrant(Rect(32, 32, 64, 64), Color::RED, Color::GREEN, Color::BLUE, Color::WHITE); } Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply(); { SCOPED_TRACE("FLIP_H"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(0, 32, 32, 64), Color::GREEN, Color::RED, + Color::WHITE, Color::BLUE); } Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply(); { SCOPED_TRACE("FLIP_V"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(32, 0, 64, 32), Color::BLUE, Color::WHITE, + Color::RED, Color::GREEN); } Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply(); { SCOPED_TRACE("ROT_90"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(0, 32, 32, 64), Color::BLUE, Color::RED, + Color::WHITE, Color::GREEN); } Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply(); { SCOPED_TRACE("SCALE"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(32, 32, 96, 96), Color::RED, Color::GREEN, + Color::BLUE, Color::WHITE, 1 /* tolerance */); } } @@ -955,8 +945,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) { Transaction().setCrop(layer, crop).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(crop, Color::RED); + shot->expectBorder(crop, Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) { @@ -986,13 +976,13 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) { { SCOPED_TRACE("empty rect"); Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); } { SCOPED_TRACE("negative rect"); Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); } } @@ -1016,8 +1006,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED); - Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply(); - Transaction().setBuffer(layer, buffer).apply(); // Partially out of bounds in the negative (upper left) direction @@ -1025,8 +1013,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("out of bounds, negative (upper left) direction"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE); - shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 16), Color::BLUE); + shot->expectBorder(Rect(0, 0, 32, 16), Color::BLACK); } // Partially out of bounds in the positive (lower right) direction @@ -1034,8 +1022,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("out of bounds, positive (lower right) direction"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 64, 64), Color::RED); - shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); + shot->expectColor(Rect(0, 16, 32, 64), Color::RED); + shot->expectBorder(Rect(0, 16, 32, 64), Color::BLACK); } // Fully out of buffer space bounds @@ -1043,9 +1031,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("Fully out of bounds"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE); - shot->expectColor(Rect(0, 16, 64, 64), Color::RED); - shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); + shot->expectColor(Rect(0, 0, 64, 64), Color::BLACK); } } @@ -1068,12 +1054,11 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); - const Rect frame(32, 32, 64, 64); const Rect crop(8, 8, 24, 24); - Transaction().setFrame(layer, frame).setCrop(layer, crop).apply(); + Transaction().setPosition(layer, 32, 32).setCrop(layer, crop).apply(); auto shot = getScreenCapture(); - shot->expectColor(frame, Color::RED); - shot->expectBorder(frame, Color::BLACK); + shot->expectColor(Rect(40, 40, 56, 56), Color::RED); + shot->expectBorder(Rect(40, 40, 56, 56), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) { @@ -1121,7 +1106,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); const Rect frame(8, 8, 24, 24); - Transaction().setFrame(layer, frame).apply(); + Transaction t; + TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), frame); + t.apply(); + auto shot = getScreenCapture(); shot->expectColor(frame, Color::RED); shot->expectBorder(frame, Color::BLACK); @@ -1133,16 +1121,23 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + Transaction t; { SCOPED_TRACE("empty rect"); - Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply(); + TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), Rect(8, 8, 8, 8)); + t.apply(); + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); } { SCOPED_TRACE("negative rect"); - Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); + TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), Rect(8, 8, 0, 0)); + t.apply(); + + auto shot = getScreenCapture(); + shot->expectColor(Rect(0, 0, 8, 8), Color::RED); + shot->expectBorder(Rect(0, 0, 8, 8), Color::BLACK); } } @@ -1152,10 +1147,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10)); - // A parentless layer will default to a frame with the same size as the buffer + // A layer with a buffer will have a computed size that matches the buffer size. auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 10, 10), Color::RED); + shot->expectBorder(Rect(0, 0, 10, 10), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) { @@ -1163,17 +1158,16 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) { ASSERT_NO_FATAL_FAILURE( parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); - Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply(); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); Transaction().reparent(child, parent).apply(); - // A layer will default to the frame of its parent + // A layer with a buffer will have a computed size that matches the buffer size. auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); + shot->expectColor(Rect(0, 0, 10, 10), Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1183,14 +1177,14 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); Transaction().reparent(child, parent).apply(); - // A layer will default to the frame of its parent + // A layer with a buffer will have a computed size that matches the buffer size. auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); + shot->expectColor(Rect(0, 0, 10, 10), Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1199,11 +1193,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) { ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); - Transaction().setFrame(layer, Rect(0, 0, 32, 32)).apply(); std::this_thread::sleep_for(500ms); - Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply(); + Transaction().setPosition(layer, 16, 16).apply(); auto shot = getScreenCapture(); shot->expectColor(Rect(16, 16, 48, 48), Color::RED); @@ -1215,18 +1208,20 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) { ASSERT_NO_FATAL_FAILURE( parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); Transaction().reparent(child, parent).apply(); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); - Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply(); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); - Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply(); + Rect childDst(0, 16, 32, 32); + Transaction t; + TransactionUtils::setFrame(t, child, Rect(0, 0, 10, 10), childDst); + t.apply(); auto shot = getScreenCapture(); shot->expectColor(Rect(0, 0, 32, 16), Color::RED); - shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE); + shot->expectColor(childDst, Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1238,8 +1233,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { @@ -1252,8 +1247,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 1"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32)); @@ -1261,8 +1256,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 2"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); @@ -1270,8 +1265,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 3"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } } @@ -1286,7 +1281,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64)); - Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply(); { SCOPED_TRACE("set layer 1 buffer red"); auto shot = getScreenCapture(); @@ -1295,7 +1289,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32)); - Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply(); { SCOPED_TRACE("set layer 2 buffer blue"); auto shot = getScreenCapture(); @@ -1350,8 +1343,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) { Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } idx++; } @@ -1383,8 +1376,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_Buffer Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } idx++; } @@ -1416,8 +1409,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferSt Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } if (idx == 0) { buffers[0].clear(); @@ -1435,7 +1428,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) { Color::BLUE, Color::WHITE)); Transaction() - .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90) .apply(); @@ -1452,7 +1444,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) { Color::BLUE, Color::WHITE)); Transaction() - .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H) .apply(); @@ -1469,7 +1460,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) { Color::BLUE, Color::WHITE)); Transaction() - .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V) .apply(); @@ -1518,8 +1508,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) { Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) { @@ -1534,8 +1524,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) { Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) { @@ -1552,8 +1542,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) { Transaction().setBuffer(layer, buffer).setHdrMetadata(layer, hdrMetadata).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) { @@ -1570,8 +1560,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) Transaction().setBuffer(layer, buffer).setSurfaceDamageRegion(layer, region).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) { @@ -1586,8 +1576,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) { Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) { diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 87c7b7d829..0bc8fe7aa0 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -244,6 +244,11 @@ protected: return bufferGenerator.get(outBuffer, outFence); } + static ui::Size getBufferSize() { + static BufferGenerator bufferGenerator; + return bufferGenerator.getSize(); + } + sp mClient; bool deviceSupportsBlurs() { diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index ac5e297e43..edf55ea6ef 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -196,17 +196,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size)); - if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { - Transaction() - .setCornerRadius(layer, cornerRadius) - .setCrop(layer, Rect(0, 0, size, size)) - .apply(); - } else { - Transaction() - .setCornerRadius(layer, cornerRadius) - .setFrame(layer, Rect(0, 0, size, size)) - .apply(); - } + Transaction().setCornerRadius(layer, cornerRadius).apply(); { const uint8_t bottom = size - 1; const uint8_t right = size - 1; @@ -234,19 +224,13 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) { ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); - auto transaction = Transaction() - .setCornerRadius(parent, cornerRadius) - .setCrop(parent, Rect(0, 0, size, size)) - .reparent(child, parent) - .setPosition(child, 0, size) - // Rotate by half PI - .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f); - if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { - transaction.setCrop(parent, Rect(0, 0, size, size)); - } else { - transaction.setFrame(parent, Rect(0, 0, size, size)); - } - transaction.apply(); + Transaction() + .setCornerRadius(parent, cornerRadius) + .reparent(child, parent) + .setPosition(child, 0, size) + // Rotate by half PI + .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f) + .apply(); { const uint8_t bottom = size - 1; @@ -275,21 +259,12 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) { ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2)); - if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { - Transaction() - .setCornerRadius(parent, cornerRadius) - .setCrop(parent, Rect(0, 0, size, size)) - .reparent(child, parent) - .setPosition(child, 0, size / 2) - .apply(); - } else { - Transaction() - .setCornerRadius(parent, cornerRadius) - .setFrame(parent, Rect(0, 0, size, size)) - .reparent(child, parent) - .setFrame(child, Rect(0, size / 2, size, size)) - .apply(); - } + Transaction() + .setCornerRadius(parent, cornerRadius) + .reparent(child, parent) + .setPosition(child, 0, size / 2) + .apply(); + { const uint8_t bottom = size - 1; const uint8_t right = size - 1; @@ -331,12 +306,9 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { Transaction() .setLayer(greenLayer, mLayerZBase) - .setFrame(leftLayer, {0, 0, canvasSize * 2, canvasSize * 2}) .setLayer(leftLayer, mLayerZBase + 1) - .setFrame(leftLayer, leftRect) .setLayer(rightLayer, mLayerZBase + 2) .setPosition(rightLayer, rightRect.left, rightRect.top) - .setFrame(rightLayer, rightRect) .apply(); { @@ -352,7 +324,6 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { .setLayer(blurLayer, mLayerZBase + 3) .setBackgroundBlurRadius(blurLayer, blurRadius) .setCrop(blurLayer, blurRect) - .setFrame(blurLayer, blurRect) .setSize(blurLayer, blurRect.getWidth(), blurRect.getHeight()) .setAlpha(blurLayer, 0.0f) .apply(); @@ -435,10 +406,8 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurAffectedByParentA Transaction() .setLayer(left, mLayerZBase + 1) - .setFrame(left, {0, 0, size, size}) .setLayer(right, mLayerZBase + 2) .setPosition(right, size, 0) - .setFrame(right, {size, 0, size * 2, size}) .apply(); { @@ -457,7 +426,6 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurAffectedByParentA .setAlpha(blurParent, 0.5) .setLayer(blur, mLayerZBase + 4) .setBackgroundBlurRadius(blur, size) // set the blur radius to the size of one rect - .setFrame(blur, {0, 0, size * 2, size}) .reparent(blur, blurParent) .apply(); diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index 613b21ef04..ccf434d63a 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -195,7 +195,7 @@ TEST_F(MirrorLayerTest, MirrorBufferLayer) { createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState, mChildLayer.get()); fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200); - Transaction().setFrame(bufferStateLayer, Rect(0, 0, 200, 200)).show(bufferStateLayer).apply(); + Transaction().show(bufferStateLayer).apply(); { SCOPED_TRACE("Initial Mirror BufferStateLayer"); diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h index 3cbfed98f5..8c448e2f96 100644 --- a/services/surfaceflinger/tests/utils/TransactionUtils.h +++ b/services/surfaceflinger/tests/utils/TransactionUtils.h @@ -126,7 +126,7 @@ public: const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4; for (int32_t i = 0; i < width; i++) { const uint8_t expected[4] = {color.r, color.g, color.b, color.a}; - EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare)) + ASSERT_TRUE(std::equal(src, src + 4, expected, colorCompare)) << "pixel @ (" << x + i << ", " << y + j << "): " << "expected (" << color << "), " << "got (" << Color{src[0], src[1], src[2], src[3]} << ")"; @@ -161,6 +161,22 @@ public: ASSERT_EQ(NO_ERROR, s->unlockAndPost()); } } + + static void setFrame(Transaction& t, const sp& sc, Rect source, Rect dest, + int32_t transform = 0) { + uint32_t sourceWidth = source.getWidth(); + uint32_t sourceHeight = source.getHeight(); + + if (transform & ui::Transform::ROT_90) { + std::swap(sourceWidth, sourceHeight); + } + + float dsdx = dest.getWidth() / static_cast(sourceWidth); + float dsdy = dest.getHeight() / static_cast(sourceHeight); + + t.setMatrix(sc, dsdx, 0, 0, dsdy); + t.setPosition(sc, dest.left, dest.top); + } }; enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY }; -- cgit v1.2.3-59-g8ed1b From 1014c4bf14f5c250b78d7e917fb59aaa9b0d9b0a Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Thu, 8 Apr 2021 12:30:21 +0000 Subject: Revert "Remove setFrame from BufferStateLayer" Revert "Update tests to reflect the new behavior for setGeometry" Revert submission 13843937-sc_remove_set_frame Reason for revert: Candidate CL for b/184807094 Reverted Changes: Iffbd955a3:Remove setFrame I27f17bc61:Update tests to reflect the new behavior for setGe... I5720276c1:Remove setFrame from surface_control setGeometry I32ee0e3e4:Remove setFrame from BufferStateLayer Bug: 184807094 Change-Id: I8330f374c50c76d8c2e70b79815bc2bc32b89480 --- libs/gui/BLASTBufferQueue.cpp | 29 +--- libs/gui/LayerState.cpp | 4 + libs/gui/SurfaceComposerClient.cpp | 14 ++ libs/gui/include/gui/BLASTBufferQueue.h | 32 +--- libs/gui/include/gui/LayerState.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 1 + libs/gui/tests/BLASTBufferQueue_test.cpp | 34 ++-- services/surfaceflinger/BufferStateLayer.cpp | 98 +++++++----- services/surfaceflinger/BufferStateLayer.h | 10 +- services/surfaceflinger/Layer.cpp | 4 +- services/surfaceflinger/Layer.h | 1 + services/surfaceflinger/RefreshRateOverlay.cpp | 8 +- services/surfaceflinger/SurfaceFlinger.cpp | 3 + services/surfaceflinger/tests/BufferGenerator.cpp | 14 +- services/surfaceflinger/tests/BufferGenerator.h | 2 - services/surfaceflinger/tests/EffectLayer_test.cpp | 1 + services/surfaceflinger/tests/IPC_test.cpp | 1 + .../surfaceflinger/tests/LayerCallback_test.cpp | 131 +++------------- .../tests/LayerRenderTypeTransaction_test.cpp | 174 +++++++++++---------- .../surfaceflinger/tests/LayerTransactionTest.h | 5 - .../LayerTypeAndRenderTypeTransaction_test.cpp | 60 +++++-- services/surfaceflinger/tests/MirrorLayer_test.cpp | 2 +- .../surfaceflinger/tests/utils/TransactionUtils.h | 18 +-- 23 files changed, 295 insertions(+), 353 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 1d7ed2f97b..1976b493b2 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -204,16 +204,13 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, if (mRequestedSize != newSize) { mRequestedSize.set(newSize); mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height); - if (mLastBufferInfo.scalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { + if (mLastBufferScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { // If the buffer supports scaling, update the frame immediately since the client may // want to scale the existing buffer to the new size. mSize = mRequestedSize; - // We only need to update the scale if we've received at least one buffer. The reason - // for this is the scale is calculated based on the requested size and buffer size. - // If there's no buffer, the scale will always be 1. - if (mLastBufferInfo.hasBuffer) { - setMatrix(&t, mLastBufferInfo); - } + t.setFrame(mSurfaceControl, + {0, 0, static_cast(mSize.width), + static_cast(mSize.height)}); applyTransaction = true; } } @@ -377,10 +374,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); + mLastBufferScalingMode = bufferItem.mScalingMode; mLastAcquiredFrameNumber = bufferItem.mFrameNumber; - mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(), - bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, - bufferItem.mScalingMode); auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp(this) /* callbackContext */, @@ -393,7 +388,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); - setMatrix(t, mLastBufferInfo); + t->setFrame(mSurfaceControl, + {0, 0, static_cast(mSize.width), static_cast(mSize.height)}); t->setCrop(mSurfaceControl, computeCrop(bufferItem)); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); @@ -519,17 +515,6 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { return mSize != bufferSize; } -void BLASTBufferQueue::setMatrix(SurfaceComposerClient::Transaction* t, - const BufferInfo& bufferInfo) { - uint32_t bufWidth = bufferInfo.width; - uint32_t bufHeight = bufferInfo.height; - - float dsdx = mSize.width / static_cast(bufWidth); - float dsdy = mSize.height / static_cast(bufHeight); - - t->setMatrix(mSurfaceControl, dsdx, 0, 0, dsdy); -} - void BLASTBufferQueue::setTransactionCompleteCallback( uint64_t frameNumber, std::function&& transactionCompleteCallback) { std::lock_guard _lock{mMutex}; diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 8c21553bff..d653ae71be 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -458,6 +458,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eCropChanged; crop = other.crop; } + if (other.what & eFrameChanged) { + what |= eFrameChanged; + orientedDisplaySpaceRect = other.orientedDisplaySpaceRect; + } if (other.what & eBufferChanged) { what |= eBufferChanged; buffer = other.buffer; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index f12b77e48f..0b01084633 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1246,6 +1246,20 @@ SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp& sc, const Rect& frame) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eFrameChanged; + s->orientedDisplaySpaceRect = frame; + + registerSurfaceControlForCallback(sc); + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( const sp& sc, const sp& buffer, ReleaseBufferCallback callback) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index a48f95ae73..fbd16f4ea2 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -142,33 +142,6 @@ private: ui::Size mRequestedSize GUARDED_BY(mMutex); int32_t mFormat GUARDED_BY(mMutex); - struct BufferInfo { - bool hasBuffer = false; - uint32_t width; - uint32_t height; - uint32_t transform; - // This is used to check if we should update the blast layer size immediately or wait until - // we get the next buffer. This will support scenarios where the layer can change sizes - // and the buffer will scale to fit the new size. - uint32_t scalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; - - void update(bool hasBuffer, uint32_t width, uint32_t height, uint32_t transform, - uint32_t scalingMode) { - this->hasBuffer = hasBuffer; - this->width = width; - this->height = height; - this->transform = transform; - this->scalingMode = scalingMode; - } - }; - - // Last acquired buffer's info. This is used to calculate the correct scale when size change is - // requested. We need to use the old buffer's info to determine what scale we need to apply to - // ensure the correct size. - BufferInfo mLastBufferInfo GUARDED_BY(mMutex); - void setMatrix(SurfaceComposerClient::Transaction* t, const BufferInfo& bufferInfo) - REQUIRES(mMutex); - uint32_t mTransformHint GUARDED_BY(mMutex); sp mConsumer; @@ -186,6 +159,11 @@ private: std::queue mNextFrameTimelineInfoQueue GUARDED_BY(mMutex); + // Last acquired buffer's scaling mode. This is used to check if we should update the blast + // layer size immediately or wait until we get the next buffer. This will support scenarios + // where the layer can change sizes and the buffer will scale to fit the new size. + uint32_t mLastBufferScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; + // Tracks the last acquired frame number uint64_t mLastAcquiredFrameNumber GUARDED_BY(mMutex) = 0; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 9186ed289e..92747779fd 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -106,7 +106,7 @@ struct layer_state_t { eHasListenerCallbacksChanged = 0x20000000, eInputInfoChanged = 0x40000000, eCornerRadiusChanged = 0x80000000, - /* was eFrameChanged, now available 0x1'00000000, */ + eFrameChanged = 0x1'00000000, eCachedBufferChanged = 0x2'00000000, eBackgroundColorChanged = 0x4'00000000, eMetadataChanged = 0x8'00000000, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 19d898c96a..c38375cf77 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -474,6 +474,7 @@ public: Transaction& setTransform(const sp& sc, uint32_t transform); Transaction& setTransformToDisplayInverse(const sp& sc, bool transformToDisplayInverse); + Transaction& setFrame(const sp& sc, const Rect& frame); Transaction& setBuffer(const sp& sc, const sp& buffer, ReleaseBufferCallback callback = nullptr); Transaction& setCachedBuffer(const sp& sc, int32_t bufferId); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 9b1f0db83b..fe48d88376 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -140,6 +140,7 @@ protected: /*parent*/ nullptr); t.setLayerStack(mSurfaceControl, 0) .setLayer(mSurfaceControl, std::numeric_limits::max()) + .setFrame(mSurfaceControl, Rect(resolution)) .show(mSurfaceControl) .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) .apply(); @@ -217,13 +218,13 @@ protected: col >= region.left - border && col < region.right + border; } if (!outsideRegion && inRegion) { - ASSERT_GE(epsilon, abs(r - *(pixel))); - ASSERT_GE(epsilon, abs(g - *(pixel + 1))); - ASSERT_GE(epsilon, abs(b - *(pixel + 2))); + EXPECT_GE(epsilon, abs(r - *(pixel))); + EXPECT_GE(epsilon, abs(g - *(pixel + 1))); + EXPECT_GE(epsilon, abs(b - *(pixel + 2))); } else if (outsideRegion && !inRegion) { - ASSERT_GE(epsilon, abs(r - *(pixel))); - ASSERT_GE(epsilon, abs(g - *(pixel + 1))); - ASSERT_GE(epsilon, abs(b - *(pixel + 2))); + EXPECT_GE(epsilon, abs(r - *(pixel))); + EXPECT_GE(epsilon, abs(g - *(pixel + 1))); + EXPECT_GE(epsilon, abs(b - *(pixel + 2))); } ASSERT_EQ(false, ::testing::Test::HasFailure()); } @@ -465,8 +466,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, - {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); + checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { @@ -523,15 +523,13 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); - Rect bounds; - bounds.left = finalCropSideLength / 2; - bounds.top = 0; - bounds.right = bounds.left + finalCropSideLength; - bounds.bottom = finalCropSideLength; - - ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, bounds)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(0, 0, 0, bounds, /*border*/ 0, /*outsideRegion*/ true)); + checkScreenCapture(r, g, b, + {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength})); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 0, + {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength}, + /*border*/ 0, /*outsideRegion*/ true)); } class TestProducerListener : public BnProducerListener { @@ -598,6 +596,7 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { t.setLayerStack(bgSurface, 0) .show(bgSurface) .setDataspace(bgSurface, ui::Dataspace::V0_SRGB) + .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setLayer(bgSurface, std::numeric_limits::max() - 1) .apply(); @@ -620,8 +619,7 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, - {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); + checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 7a10769757..a974dc4488 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -278,8 +278,9 @@ bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) { return stateUpdateAvailable; } -Rect BufferStateLayer::getCrop(const Layer::State& s) const { - return s.crop; +// Crop that applies to the window +Rect BufferStateLayer::getCrop(const Layer::State& /*s*/) const { + return Rect::INVALID_RECT; } bool BufferStateLayer::setTransform(uint32_t transform) { @@ -300,53 +301,57 @@ bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInver } bool BufferStateLayer::setCrop(const Rect& crop) { - if (mCurrentState.crop == crop) return false; - mCurrentState.sequence++; - mCurrentState.crop = crop; + Rect c = crop; + if (c.left < 0) { + c.left = 0; + } + if (c.top < 0) { + c.top = 0; + } + // If the width and/or height are < 0, make it [0, 0, -1, -1] so the equality comparision below + // treats all invalid rectangles the same. + if (!c.isValid()) { + c.makeInvalid(); + } + if (mCurrentState.crop == c) return false; + mCurrentState.crop = c; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } -bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix, - bool allowNonRectPreservingTransforms) { - if (mCurrentState.transform.dsdx() == matrix.dsdx && - mCurrentState.transform.dtdy() == matrix.dtdy && - mCurrentState.transform.dtdx() == matrix.dtdx && - mCurrentState.transform.dsdy() == matrix.dsdy) { - return false; - } +bool BufferStateLayer::setFrame(const Rect& frame) { + int x = frame.left; + int y = frame.top; + int w = frame.getWidth(); + int h = frame.getHeight(); - ui::Transform t; - t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - - if (!allowNonRectPreservingTransforms && !t.preserveRects()) { - ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER nor " - "ROTATE_SURFACE_FLINGER ignored"); - return false; + if (x < 0) { + x = 0; + w = frame.right; } - mCurrentState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - - mCurrentState.sequence++; - mCurrentState.modified = true; - setTransactionFlags(eTransactionNeeded); - - return true; -} + if (y < 0) { + y = 0; + h = frame.bottom; + } -bool BufferStateLayer::setPosition(float x, float y) { - if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) { + if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y && + mCurrentState.width == w && mCurrentState.height == h) { return false; } + if (!frame.isValid()) { + x = y = w = h = 0; + } mCurrentState.transform.set(x, y); + mCurrentState.width = w; + mCurrentState.height = h; mCurrentState.sequence++; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); - return true; } @@ -423,10 +428,6 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const spmFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime, FrameTracer::FrameEvent::QUEUE); } - - mCurrentState.width = mCurrentState.buffer->width; - mCurrentState.height = mCurrentState.buffer->height; - return true; } @@ -854,6 +855,33 @@ sp BufferStateLayer::createClone() { return layer; } +Layer::RoundedCornerState BufferStateLayer::getRoundedCornerState() const { + const auto& p = mDrawingParent.promote(); + if (p != nullptr) { + RoundedCornerState parentState = p->getRoundedCornerState(); + if (parentState.radius > 0) { + ui::Transform t = getActiveTransform(getDrawingState()); + t = t.inverse(); + parentState.cropRect = t.transform(parentState.cropRect); + // The rounded corners shader only accepts 1 corner radius for performance reasons, + // but a transform matrix can define horizontal and vertical scales. + // Let's take the average between both of them and pass into the shader, practically we + // never do this type of transformation on windows anyway. + parentState.radius *= (t[0][0] + t[1][1]) / 2.0f; + return parentState; + } + } + const float radius = getDrawingState().cornerRadius; + const State& s(getDrawingState()); + if (radius <= 0 || (getActiveWidth(s) == UINT32_MAX && getActiveHeight(s) == UINT32_MAX)) + return RoundedCornerState(); + return RoundedCornerState(FloatRect(static_cast(s.transform.tx()), + static_cast(s.transform.ty()), + static_cast(s.transform.tx() + s.width), + static_cast(s.transform.ty() + s.height)), + radius); +} + bool BufferStateLayer::bufferNeedsFiltering() const { const State& s(getDrawingState()); if (!s.buffer) { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index af2819eac7..7a3da6fec1 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -66,6 +66,7 @@ public: bool setTransform(uint32_t transform) override; bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; + bool setFrame(const Rect& frame) override; bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, @@ -80,13 +81,15 @@ public: bool setTransactionCompletedListeners(const std::vector>& handles) override; bool addFrameEvent(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime) override; - bool setPosition(float /*x*/, float /*y*/) override; - bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, - bool /*allowNonRectPreservingTransforms*/); // Override to ignore legacy layer state properties that are not used by BufferStateLayer bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } + bool setPosition(float /*x*/, float /*y*/) override { return false; } bool setTransparentRegionHint(const Region& transparent) override; + bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, + bool /*allowNonRectPreservingTransforms*/) override { + return false; + } void deferTransactionUntil_legacy(const sp& /*barrierHandle*/, uint64_t /*frameNumber*/) override {} void deferTransactionUntil_legacy(const sp& /*barrierLayer*/, @@ -94,6 +97,7 @@ public: Rect getBufferSize(const State& s) const override; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; + Layer::RoundedCornerState getRoundedCornerState() const override; void setAutoRefresh(bool autoRefresh) override; // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 447cbb3854..cd3e8add9a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2312,8 +2312,8 @@ Layer::RoundedCornerState Layer::getRoundedCornerState() const { } } const float radius = getDrawingState().cornerRadius; - return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid() - ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius) + return radius > 0 && getCrop(getDrawingState()).isValid() + ? RoundedCornerState(getCrop(getDrawingState()).toFloatRect(), radius) : RoundedCornerState(); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4cd379b963..1c5d6ecb03 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -462,6 +462,7 @@ public: // Used only to set BufferStateLayer state virtual bool setTransform(uint32_t /*transform*/) { return false; }; virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; }; + virtual bool setFrame(const Rect& /*frame*/) { return false; }; virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 7a3e433660..1d00cc38f2 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -231,14 +231,8 @@ const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uin void RefreshRateOverlay::setViewport(ui::Size viewport) { Rect frame((3 * viewport.width) >> 4, viewport.height >> 5); frame.offsetBy(viewport.width >> 5, viewport.height >> 4); + mLayer->setFrame(frame); - layer_state_t::matrix22_t matrix; - matrix.dsdx = frame.getWidth() / static_cast(SevenSegmentDrawer::getWidth()); - matrix.dtdx = 0; - matrix.dtdy = 0; - matrix.dsdy = frame.getHeight() / static_cast(SevenSegmentDrawer::getHeight()); - mLayer->setMatrix(matrix, true); - mLayer->setPosition(frame.left, frame.top); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b1d63f0ce7..a387587d7f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3936,6 +3936,9 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (what & layer_state_t::eCropChanged) { if (layer->setCrop(s.crop)) flags |= eTraversalNeeded; } + if (what & layer_state_t::eFrameChanged) { + if (layer->setFrame(s.orientedDisplaySpaceRect)) flags |= eTraversalNeeded; + } if (what & layer_state_t::eAcquireFenceChanged) { if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded; } diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp index 47a150dd35..03f8e1afba 100644 --- a/services/surfaceflinger/tests/BufferGenerator.cpp +++ b/services/surfaceflinger/tests/BufferGenerator.cpp @@ -296,12 +296,12 @@ private: BufferGenerator::BufferGenerator() : mSurfaceManager(new SurfaceManager), mEglManager(new EglManager), mProgram(new Program) { - mBufferSize.set(1000.0, 1000.0); + const float width = 1000.0; + const float height = 1000.0; auto setBufferWithContext = std::bind(setBuffer, std::placeholders::_1, std::placeholders::_2, this); - mSurfaceManager->initialize(mBufferSize.width, mBufferSize.height, HAL_PIXEL_FORMAT_RGBA_8888, - setBufferWithContext); + mSurfaceManager->initialize(width, height, HAL_PIXEL_FORMAT_RGBA_8888, setBufferWithContext); if (!mEglManager->initialize(mSurfaceManager->getSurface())) return; @@ -309,9 +309,7 @@ BufferGenerator::BufferGenerator() if (!mProgram->initialize(VERTEX_SHADER, FRAGMENT_SHADER)) return; mProgram->use(); - mProgram->bindVec4(0, - vec4{mBufferSize.width, mBufferSize.height, 1.0f / mBufferSize.width, - 1.0f / mBufferSize.height}); + mProgram->bindVec4(0, vec4{width, height, 1.0f / width, 1.0f / height}); mProgram->bindVec3(2, &SPHERICAL_HARMONICS[0], 4); glEnableVertexAttribArray(0); @@ -374,10 +372,6 @@ status_t BufferGenerator::get(sp* outBuffer, sp* outFence) return NO_ERROR; } -ui::Size BufferGenerator::getSize() { - return mBufferSize; -} - // static void BufferGenerator::setBuffer(const sp& buffer, int32_t fence, void* bufferGenerator) { diff --git a/services/surfaceflinger/tests/BufferGenerator.h b/services/surfaceflinger/tests/BufferGenerator.h index f7d548b6bf..a3ffe86572 100644 --- a/services/surfaceflinger/tests/BufferGenerator.h +++ b/services/surfaceflinger/tests/BufferGenerator.h @@ -37,7 +37,6 @@ public: /* Static callback that sets the fence on a particular instance */ static void setBuffer(const sp& buffer, int32_t fence, void* fenceGenerator); - ui::Size getSize(); private: bool mInitialized = false; @@ -54,7 +53,6 @@ private: using Epoch = std::chrono::time_point; Epoch mEpoch = std::chrono::steady_clock::now(); - ui::Size mBufferSize; }; } // namespace android diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp index af00ec7fc9..f470eda7d3 100644 --- a/services/surfaceflinger/tests/EffectLayer_test.cpp +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -149,6 +149,7 @@ TEST_F(EffectLayerTest, BlurEffectLayerIsVisible) { t.reparent(blurLayer, mParentLayer); t.setBackgroundBlurRadius(blurLayer, blurRadius); t.setCrop(blurLayer, blurRect); + t.setFrame(blurLayer, blurRect); t.setAlpha(blurLayer, 0.0f); t.show(blurLayer); }); diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp index 9fa3d4c417..a8647c3e50 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -161,6 +161,7 @@ public: Color::RED); transaction->setLayerStack(mSurfaceControl, 0) .setLayer(mSurfaceControl, std::numeric_limits::max()) + .setFrame(mSurfaceControl, Rect(0, 0, width, height)) .setBuffer(mSurfaceControl, gb) .setAcquireFence(mSurfaceControl, fence) .show(mSurfaceControl) diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 011ff70409..158801a705 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -164,10 +164,7 @@ TEST_F(LayerCallbackTest, NoBufferNoColor) { return; } - ui::Size bufferSize = getBufferSize(); - TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(0, 0, 32, 32)); - transaction.apply(); + transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer, @@ -187,10 +184,7 @@ TEST_F(LayerCallbackTest, BufferNoColor) { return; } - ui::Size bufferSize = getBufferSize(); - TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(0, 0, 32, 32)); - transaction.apply(); + transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -209,10 +203,7 @@ TEST_F(LayerCallbackTest, NoBufferColor) { return; } - ui::Size bufferSize = getBufferSize(); - TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(0, 0, 32, 32)); - transaction.apply(); + transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, @@ -247,10 +238,7 @@ TEST_F(LayerCallbackTest, OffScreen) { return; } - ui::Size bufferSize = getBufferSize(); - TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(-100, -100, 100, 100)); - transaction.apply(); + transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -275,15 +263,8 @@ TEST_F(LayerCallbackTest, MergeBufferNoColor) { return; } - ui::Size bufferSize = getBufferSize(); - - TransactionUtils::setFrame(transaction1, layer1, - Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); - TransactionUtils::setFrame(transaction2, layer2, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(32, 32, 64, 64)); - - transaction2.merge(std::move(transaction1)).apply(); + transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); + transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -309,15 +290,8 @@ TEST_F(LayerCallbackTest, MergeNoBufferColor) { return; } - ui::Size bufferSize = getBufferSize(); - - TransactionUtils::setFrame(transaction1, layer1, - Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); - TransactionUtils::setFrame(transaction2, layer2, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(32, 32, 64, 64)); - - transaction2.merge(std::move(transaction1)).apply(); + transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); + transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -344,15 +318,8 @@ TEST_F(LayerCallbackTest, MergeOneBufferOneColor) { return; } - ui::Size bufferSize = getBufferSize(); - - TransactionUtils::setFrame(transaction1, layer1, - Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); - TransactionUtils::setFrame(transaction2, layer2, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(32, 32, 64, 64)); - - transaction2.merge(std::move(transaction1)).apply(); + transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); + transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1); @@ -438,15 +405,8 @@ TEST_F(LayerCallbackTest, Merge_DifferentClients) { return; } - ui::Size bufferSize = getBufferSize(); - - TransactionUtils::setFrame(transaction1, layer1, - Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); - TransactionUtils::setFrame(transaction2, layer2, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(32, 32, 64, 64)); - - transaction2.merge(std::move(transaction1)).apply(); + transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); + transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -531,11 +491,7 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) { } } - ui::Size bufferSize = getBufferSize(); - TransactionUtils::setFrame(transaction, layer, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(0, 0, 32, 32)); - transaction.apply(); + transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); ExpectedResult expected; expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED @@ -567,16 +523,8 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge) { return; } - ui::Size bufferSize = getBufferSize(); - - TransactionUtils::setFrame(transaction1, layer1, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(0, 0, 32, 32)); - TransactionUtils::setFrame(transaction2, layer2, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(32, 32, 64, 64)); - - transaction2.merge(std::move(transaction1)).apply(); + transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); + transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -616,16 +564,8 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) { return; } - ui::Size bufferSize = getBufferSize(); - - TransactionUtils::setFrame(transaction1, layer1, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(0, 0, 32, 32)); - TransactionUtils::setFrame(transaction2, layer2, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(32, 32, 64, 64)); - - transaction2.merge(std::move(transaction1)).apply(); + transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); + transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -666,15 +606,8 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateCha return; } - ui::Size bufferSize = getBufferSize(); - - TransactionUtils::setFrame(transaction1, layer1, - Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); - TransactionUtils::setFrame(transaction2, layer2, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(32, 32, 64, 64)); - - transaction2.merge(std::move(transaction1)).apply(); + transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); + transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -728,15 +661,8 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC return; } - ui::Size bufferSize = getBufferSize(); - - TransactionUtils::setFrame(transaction1, layer1, - Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); - TransactionUtils::setFrame(transaction2, layer2, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(32, 32, 64, 64)); - - transaction2.merge(std::move(transaction1)).apply(); + transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); + transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -756,10 +682,7 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC return; } - TransactionUtils::setFrame(transaction2, layer2, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(32, 32, 64, 64)); - transaction2.merge(std::move(transaction1)).apply(); + transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2, ExpectedResult::Buffer::NOT_ACQUIRED); @@ -839,10 +762,7 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { return; } - ui::Size bufferSize = getBufferSize(); - TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(0, 0, 32, 32)); - transaction.apply(); + transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); ExpectedResult expectedResult; expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -861,10 +781,7 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { return; } - TransactionUtils::setFrame(transaction, layer, - Rect(0, 0, bufferSize.width, bufferSize.height), - Rect(0, 0, 32, 32)); - transaction.apply(); + transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); } EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 53d230abe7..7505e6ea9b 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -204,7 +204,11 @@ void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply(); break; case ISurfaceComposerClient::eFXSurfaceBufferState: - Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply(); + Transaction() + .setFrame(layerR, Rect(0, 0, 32, 32)) + .setFrame(layerG, Rect(16, 16, 48, 48)) + .setRelativeLayer(layerG, layerR, 1) + .apply(); break; default: ASSERT_FALSE(true) << "Unsupported layer type"; @@ -256,9 +260,10 @@ void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) break; case ISurfaceComposerClient::eFXSurfaceBufferState: Transaction() - .setPosition(layerG, 8, 8) + .setFrame(layerR, Rect(0, 0, 32, 32)) + .setFrame(layerG, Rect(8, 8, 40, 40)) .setRelativeLayer(layerG, layerR, 3) - .setPosition(layerB, 16, 16) + .setFrame(layerB, Rect(16, 16, 48, 48)) .setLayer(layerB, mLayerZBase + 2) .apply(); break; @@ -383,6 +388,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState Transaction() .setTransparentRegionHint(layer, Region(top)) .setBuffer(layer, buffer) + .setFrame(layer, Rect(0, 0, 32, 32)) .apply(); { SCOPED_TRACE("top transparent"); @@ -441,7 +447,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_Buffe // check that transparent region hint is bound by the layer size Transaction() .setTransparentRegionHint(layerTransparent, Region(mDisplayRect)) - .setPosition(layerR, 16, 16) + .setFrame(layerR, Rect(16, 16, 48, 48)) .setLayer(layerR, mLayerZBase + 1) .apply(); ASSERT_NO_FATAL_FAILURE( @@ -471,7 +477,8 @@ void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) { Transaction() .setAlpha(layer1, 0.25f) .setAlpha(layer2, 0.75f) - .setPosition(layer2, 16, 0) + .setFrame(layer1, Rect(0, 0, 32, 32)) + .setFrame(layer2, Rect(16, 0, 48, 32)) .setLayer(layer2, mLayerZBase + 1) .apply(); break; @@ -566,7 +573,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height)); expectedColor = fillColor; } - Transaction().setCrop(layer, Rect(0, 0, width, height)).apply(); + Transaction().setFrame(layer, Rect(0, 0, width, height)).apply(); break; default: GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper"; @@ -842,39 +849,42 @@ TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE)); - Transaction().setPosition(layer, 32, 32).setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).apply(); + Transaction() + .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f) + .setFrame(layer, Rect(0, 0, 32, 32)) + .apply(); { SCOPED_TRACE("IDENTITY"); - getScreenCapture()->expectQuadrant(Rect(32, 32, 64, 64), Color::RED, Color::GREEN, + getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE, Color::WHITE); } Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply(); { SCOPED_TRACE("FLIP_H"); - getScreenCapture()->expectQuadrant(Rect(0, 32, 32, 64), Color::GREEN, Color::RED, - Color::WHITE, Color::BLUE); + getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, + Color::BLUE, Color::WHITE); } Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply(); { SCOPED_TRACE("FLIP_V"); - getScreenCapture()->expectQuadrant(Rect(32, 0, 64, 32), Color::BLUE, Color::WHITE, - Color::RED, Color::GREEN); + getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, + Color::BLUE, Color::WHITE); } Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply(); { SCOPED_TRACE("ROT_90"); - getScreenCapture()->expectQuadrant(Rect(0, 32, 32, 64), Color::BLUE, Color::RED, - Color::WHITE, Color::GREEN); + getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, + Color::BLUE, Color::WHITE); } Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply(); { SCOPED_TRACE("SCALE"); - getScreenCapture()->expectQuadrant(Rect(32, 32, 96, 96), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE, 1 /* tolerance */); + getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, + Color::BLUE, Color::WHITE); } } @@ -945,8 +955,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) { Transaction().setCrop(layer, crop).apply(); auto shot = getScreenCapture(); - shot->expectColor(crop, Color::RED); - shot->expectBorder(crop, Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) { @@ -976,13 +986,13 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) { { SCOPED_TRACE("empty rect"); Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); + getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); } { SCOPED_TRACE("negative rect"); Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); + getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); } } @@ -1006,6 +1016,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED); + Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply(); + Transaction().setBuffer(layer, buffer).apply(); // Partially out of bounds in the negative (upper left) direction @@ -1013,8 +1025,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("out of bounds, negative (upper left) direction"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 16), Color::BLUE); - shot->expectBorder(Rect(0, 0, 32, 16), Color::BLACK); + shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE); + shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); } // Partially out of bounds in the positive (lower right) direction @@ -1022,8 +1034,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("out of bounds, positive (lower right) direction"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 16, 32, 64), Color::RED); - shot->expectBorder(Rect(0, 16, 32, 64), Color::BLACK); + shot->expectColor(Rect(0, 0, 64, 64), Color::RED); + shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); } // Fully out of buffer space bounds @@ -1031,7 +1043,9 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("Fully out of bounds"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 64, 64), Color::BLACK); + shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE); + shot->expectColor(Rect(0, 16, 64, 64), Color::RED); + shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); } } @@ -1054,11 +1068,12 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + const Rect frame(32, 32, 64, 64); const Rect crop(8, 8, 24, 24); - Transaction().setPosition(layer, 32, 32).setCrop(layer, crop).apply(); + Transaction().setFrame(layer, frame).setCrop(layer, crop).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(40, 40, 56, 56), Color::RED); - shot->expectBorder(Rect(40, 40, 56, 56), Color::BLACK); + shot->expectColor(frame, Color::RED); + shot->expectBorder(frame, Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) { @@ -1106,10 +1121,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); const Rect frame(8, 8, 24, 24); - Transaction t; - TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), frame); - t.apply(); - + Transaction().setFrame(layer, frame).apply(); auto shot = getScreenCapture(); shot->expectColor(frame, Color::RED); shot->expectBorder(frame, Color::BLACK); @@ -1121,23 +1133,16 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); - Transaction t; { SCOPED_TRACE("empty rect"); - TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), Rect(8, 8, 8, 8)); - t.apply(); - + Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply(); getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); } { SCOPED_TRACE("negative rect"); - TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), Rect(8, 8, 0, 0)); - t.apply(); - - auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 8, 8), Color::RED); - shot->expectBorder(Rect(0, 0, 8, 8), Color::BLACK); + Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply(); + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); } } @@ -1147,10 +1152,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10)); - // A layer with a buffer will have a computed size that matches the buffer size. + // A parentless layer will default to a frame with the same size as the buffer auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 10, 10), Color::RED); - shot->expectBorder(Rect(0, 0, 10, 10), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) { @@ -1158,16 +1163,17 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) { ASSERT_NO_FATAL_FAILURE( parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); + Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply(); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); Transaction().reparent(child, parent).apply(); - // A layer with a buffer will have a computed size that matches the buffer size. + // A layer will default to the frame of its parent auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 10, 10), Color::BLUE); + shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1177,14 +1183,14 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); Transaction().reparent(child, parent).apply(); - // A layer with a buffer will have a computed size that matches the buffer size. + // A layer will default to the frame of its parent auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 10, 10), Color::BLUE); + shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1193,10 +1199,11 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) { ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + Transaction().setFrame(layer, Rect(0, 0, 32, 32)).apply(); std::this_thread::sleep_for(500ms); - Transaction().setPosition(layer, 16, 16).apply(); + Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply(); auto shot = getScreenCapture(); shot->expectColor(Rect(16, 16, 48, 48), Color::RED); @@ -1208,20 +1215,18 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) { ASSERT_NO_FATAL_FAILURE( parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); Transaction().reparent(child, parent).apply(); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); + Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply(); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); - Rect childDst(0, 16, 32, 32); - Transaction t; - TransactionUtils::setFrame(t, child, Rect(0, 0, 10, 10), childDst); - t.apply(); + Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply(); auto shot = getScreenCapture(); shot->expectColor(Rect(0, 0, 32, 16), Color::RED); - shot->expectColor(childDst, Color::BLUE); + shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1233,8 +1238,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::RED); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { @@ -1247,8 +1252,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 1"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::RED); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32)); @@ -1256,8 +1261,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 2"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); @@ -1265,8 +1270,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 3"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::RED); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } } @@ -1281,6 +1286,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64)); + Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply(); { SCOPED_TRACE("set layer 1 buffer red"); auto shot = getScreenCapture(); @@ -1289,6 +1295,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32)); + Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply(); { SCOPED_TRACE("set layer 2 buffer blue"); auto shot = getScreenCapture(); @@ -1343,8 +1350,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) { Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, 32, 32), color); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } idx++; } @@ -1376,8 +1383,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_Buffer Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, 32, 32), color); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } idx++; } @@ -1409,8 +1416,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferSt Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, 32, 32), color); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } if (idx == 0) { buffers[0].clear(); @@ -1428,6 +1435,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) { Color::BLUE, Color::WHITE)); Transaction() + .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90) .apply(); @@ -1444,6 +1452,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) { Color::BLUE, Color::WHITE)); Transaction() + .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H) .apply(); @@ -1460,6 +1469,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) { Color::BLUE, Color::WHITE)); Transaction() + .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V) .apply(); @@ -1508,8 +1518,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) { Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::RED); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) { @@ -1524,8 +1534,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) { Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::RED); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) { @@ -1542,8 +1552,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) { Transaction().setBuffer(layer, buffer).setHdrMetadata(layer, hdrMetadata).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::RED); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) { @@ -1560,8 +1570,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) Transaction().setBuffer(layer, buffer).setSurfaceDamageRegion(layer, region).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::RED); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) { @@ -1576,8 +1586,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) { Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::RED); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) { diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 0bc8fe7aa0..87c7b7d829 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -244,11 +244,6 @@ protected: return bufferGenerator.get(outBuffer, outFence); } - static ui::Size getBufferSize() { - static BufferGenerator bufferGenerator; - return bufferGenerator.getSize(); - } - sp mClient; bool deviceSupportsBlurs() { diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index edf55ea6ef..ac5e297e43 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -196,7 +196,17 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size)); - Transaction().setCornerRadius(layer, cornerRadius).apply(); + if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { + Transaction() + .setCornerRadius(layer, cornerRadius) + .setCrop(layer, Rect(0, 0, size, size)) + .apply(); + } else { + Transaction() + .setCornerRadius(layer, cornerRadius) + .setFrame(layer, Rect(0, 0, size, size)) + .apply(); + } { const uint8_t bottom = size - 1; const uint8_t right = size - 1; @@ -224,13 +234,19 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) { ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); - Transaction() - .setCornerRadius(parent, cornerRadius) - .reparent(child, parent) - .setPosition(child, 0, size) - // Rotate by half PI - .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f) - .apply(); + auto transaction = Transaction() + .setCornerRadius(parent, cornerRadius) + .setCrop(parent, Rect(0, 0, size, size)) + .reparent(child, parent) + .setPosition(child, 0, size) + // Rotate by half PI + .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f); + if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { + transaction.setCrop(parent, Rect(0, 0, size, size)); + } else { + transaction.setFrame(parent, Rect(0, 0, size, size)); + } + transaction.apply(); { const uint8_t bottom = size - 1; @@ -259,12 +275,21 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) { ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2)); - Transaction() - .setCornerRadius(parent, cornerRadius) - .reparent(child, parent) - .setPosition(child, 0, size / 2) - .apply(); - + if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { + Transaction() + .setCornerRadius(parent, cornerRadius) + .setCrop(parent, Rect(0, 0, size, size)) + .reparent(child, parent) + .setPosition(child, 0, size / 2) + .apply(); + } else { + Transaction() + .setCornerRadius(parent, cornerRadius) + .setFrame(parent, Rect(0, 0, size, size)) + .reparent(child, parent) + .setFrame(child, Rect(0, size / 2, size, size)) + .apply(); + } { const uint8_t bottom = size - 1; const uint8_t right = size - 1; @@ -306,9 +331,12 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { Transaction() .setLayer(greenLayer, mLayerZBase) + .setFrame(leftLayer, {0, 0, canvasSize * 2, canvasSize * 2}) .setLayer(leftLayer, mLayerZBase + 1) + .setFrame(leftLayer, leftRect) .setLayer(rightLayer, mLayerZBase + 2) .setPosition(rightLayer, rightRect.left, rightRect.top) + .setFrame(rightLayer, rightRect) .apply(); { @@ -324,6 +352,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { .setLayer(blurLayer, mLayerZBase + 3) .setBackgroundBlurRadius(blurLayer, blurRadius) .setCrop(blurLayer, blurRect) + .setFrame(blurLayer, blurRect) .setSize(blurLayer, blurRect.getWidth(), blurRect.getHeight()) .setAlpha(blurLayer, 0.0f) .apply(); @@ -406,8 +435,10 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurAffectedByParentA Transaction() .setLayer(left, mLayerZBase + 1) + .setFrame(left, {0, 0, size, size}) .setLayer(right, mLayerZBase + 2) .setPosition(right, size, 0) + .setFrame(right, {size, 0, size * 2, size}) .apply(); { @@ -426,6 +457,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurAffectedByParentA .setAlpha(blurParent, 0.5) .setLayer(blur, mLayerZBase + 4) .setBackgroundBlurRadius(blur, size) // set the blur radius to the size of one rect + .setFrame(blur, {0, 0, size * 2, size}) .reparent(blur, blurParent) .apply(); diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index ccf434d63a..613b21ef04 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -195,7 +195,7 @@ TEST_F(MirrorLayerTest, MirrorBufferLayer) { createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState, mChildLayer.get()); fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200); - Transaction().show(bufferStateLayer).apply(); + Transaction().setFrame(bufferStateLayer, Rect(0, 0, 200, 200)).show(bufferStateLayer).apply(); { SCOPED_TRACE("Initial Mirror BufferStateLayer"); diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h index 8c448e2f96..3cbfed98f5 100644 --- a/services/surfaceflinger/tests/utils/TransactionUtils.h +++ b/services/surfaceflinger/tests/utils/TransactionUtils.h @@ -126,7 +126,7 @@ public: const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4; for (int32_t i = 0; i < width; i++) { const uint8_t expected[4] = {color.r, color.g, color.b, color.a}; - ASSERT_TRUE(std::equal(src, src + 4, expected, colorCompare)) + EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare)) << "pixel @ (" << x + i << ", " << y + j << "): " << "expected (" << color << "), " << "got (" << Color{src[0], src[1], src[2], src[3]} << ")"; @@ -161,22 +161,6 @@ public: ASSERT_EQ(NO_ERROR, s->unlockAndPost()); } } - - static void setFrame(Transaction& t, const sp& sc, Rect source, Rect dest, - int32_t transform = 0) { - uint32_t sourceWidth = source.getWidth(); - uint32_t sourceHeight = source.getHeight(); - - if (transform & ui::Transform::ROT_90) { - std::swap(sourceWidth, sourceHeight); - } - - float dsdx = dest.getWidth() / static_cast(sourceWidth); - float dsdy = dest.getHeight() / static_cast(sourceHeight); - - t.setMatrix(sc, dsdx, 0, 0, dsdy); - t.setPosition(sc, dest.left, dest.top); - } }; enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY }; -- cgit v1.2.3-59-g8ed1b From a5aedbd7ffaf42b7f287b587035018b42d61a41c Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Fri, 9 Apr 2021 13:37:33 +0000 Subject: Revert^2 "Remove setFrame from BufferStateLayer" 1014c4bf14f5c250b78d7e917fb59aaa9b0d9b0a Change-Id: I4c1cbc2b40e4f5f68bd5e6dcbe6c77405ad155b0 --- libs/gui/BLASTBufferQueue.cpp | 29 +++- libs/gui/LayerState.cpp | 4 - libs/gui/SurfaceComposerClient.cpp | 14 -- libs/gui/include/gui/BLASTBufferQueue.h | 32 +++- libs/gui/include/gui/LayerState.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 1 - libs/gui/tests/BLASTBufferQueue_test.cpp | 34 ++-- services/surfaceflinger/BufferStateLayer.cpp | 98 +++++------- services/surfaceflinger/BufferStateLayer.h | 10 +- services/surfaceflinger/Layer.cpp | 4 +- services/surfaceflinger/Layer.h | 1 - services/surfaceflinger/RefreshRateOverlay.cpp | 8 +- services/surfaceflinger/SurfaceFlinger.cpp | 3 - services/surfaceflinger/tests/BufferGenerator.cpp | 14 +- services/surfaceflinger/tests/BufferGenerator.h | 2 + services/surfaceflinger/tests/EffectLayer_test.cpp | 1 - services/surfaceflinger/tests/IPC_test.cpp | 1 - .../surfaceflinger/tests/LayerCallback_test.cpp | 131 +++++++++++++--- .../tests/LayerRenderTypeTransaction_test.cpp | 174 ++++++++++----------- .../surfaceflinger/tests/LayerTransactionTest.h | 5 + .../LayerTypeAndRenderTypeTransaction_test.cpp | 60 ++----- services/surfaceflinger/tests/MirrorLayer_test.cpp | 2 +- .../surfaceflinger/tests/utils/TransactionUtils.h | 18 ++- 23 files changed, 353 insertions(+), 295 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index bcdd06b6c8..e5afd408a9 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -204,13 +204,16 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, if (mRequestedSize != newSize) { mRequestedSize.set(newSize); mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height); - if (mLastBufferScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { + if (mLastBufferInfo.scalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { // If the buffer supports scaling, update the frame immediately since the client may // want to scale the existing buffer to the new size. mSize = mRequestedSize; - t.setFrame(mSurfaceControl, - {0, 0, static_cast(mSize.width), - static_cast(mSize.height)}); + // We only need to update the scale if we've received at least one buffer. The reason + // for this is the scale is calculated based on the requested size and buffer size. + // If there's no buffer, the scale will always be 1. + if (mLastBufferInfo.hasBuffer) { + setMatrix(&t, mLastBufferInfo); + } applyTransaction = true; } } @@ -374,8 +377,10 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); - mLastBufferScalingMode = bufferItem.mScalingMode; mLastAcquiredFrameNumber = bufferItem.mFrameNumber; + mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(), + bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, + bufferItem.mScalingMode); auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp(this) /* callbackContext */, @@ -388,8 +393,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); - t->setFrame(mSurfaceControl, - {0, 0, static_cast(mSize.width), static_cast(mSize.height)}); + setMatrix(t, mLastBufferInfo); t->setCrop(mSurfaceControl, computeCrop(bufferItem)); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); @@ -515,6 +519,17 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { return mSize != bufferSize; } +void BLASTBufferQueue::setMatrix(SurfaceComposerClient::Transaction* t, + const BufferInfo& bufferInfo) { + uint32_t bufWidth = bufferInfo.width; + uint32_t bufHeight = bufferInfo.height; + + float dsdx = mSize.width / static_cast(bufWidth); + float dsdy = mSize.height / static_cast(bufHeight); + + t->setMatrix(mSurfaceControl, dsdx, 0, 0, dsdy); +} + void BLASTBufferQueue::setTransactionCompleteCallback( uint64_t frameNumber, std::function&& transactionCompleteCallback) { std::lock_guard _lock{mMutex}; diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 5b213ad5c3..809438534c 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -455,10 +455,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eCropChanged; crop = other.crop; } - if (other.what & eFrameChanged) { - what |= eFrameChanged; - orientedDisplaySpaceRect = other.orientedDisplaySpaceRect; - } if (other.what & eBufferChanged) { what |= eBufferChanged; buffer = other.buffer; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index e01a5aee32..9ce094aa77 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1232,20 +1232,6 @@ SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp& sc, const Rect& frame) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eFrameChanged; - s->orientedDisplaySpaceRect = frame; - - registerSurfaceControlForCallback(sc); - return *this; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( const sp& sc, const sp& buffer, ReleaseBufferCallback callback) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index fbd16f4ea2..a48f95ae73 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -142,6 +142,33 @@ private: ui::Size mRequestedSize GUARDED_BY(mMutex); int32_t mFormat GUARDED_BY(mMutex); + struct BufferInfo { + bool hasBuffer = false; + uint32_t width; + uint32_t height; + uint32_t transform; + // This is used to check if we should update the blast layer size immediately or wait until + // we get the next buffer. This will support scenarios where the layer can change sizes + // and the buffer will scale to fit the new size. + uint32_t scalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; + + void update(bool hasBuffer, uint32_t width, uint32_t height, uint32_t transform, + uint32_t scalingMode) { + this->hasBuffer = hasBuffer; + this->width = width; + this->height = height; + this->transform = transform; + this->scalingMode = scalingMode; + } + }; + + // Last acquired buffer's info. This is used to calculate the correct scale when size change is + // requested. We need to use the old buffer's info to determine what scale we need to apply to + // ensure the correct size. + BufferInfo mLastBufferInfo GUARDED_BY(mMutex); + void setMatrix(SurfaceComposerClient::Transaction* t, const BufferInfo& bufferInfo) + REQUIRES(mMutex); + uint32_t mTransformHint GUARDED_BY(mMutex); sp mConsumer; @@ -159,11 +186,6 @@ private: std::queue mNextFrameTimelineInfoQueue GUARDED_BY(mMutex); - // Last acquired buffer's scaling mode. This is used to check if we should update the blast - // layer size immediately or wait until we get the next buffer. This will support scenarios - // where the layer can change sizes and the buffer will scale to fit the new size. - uint32_t mLastBufferScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; - // Tracks the last acquired frame number uint64_t mLastAcquiredFrameNumber GUARDED_BY(mMutex) = 0; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 65d771053b..41a022f90e 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -105,7 +105,7 @@ struct layer_state_t { eHasListenerCallbacksChanged = 0x20000000, eInputInfoChanged = 0x40000000, eCornerRadiusChanged = 0x80000000, - eFrameChanged = 0x1'00000000, + /* was eFrameChanged, now available 0x1'00000000, */ eCachedBufferChanged = 0x2'00000000, eBackgroundColorChanged = 0x4'00000000, eMetadataChanged = 0x8'00000000, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 2487961426..1590b10a00 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -473,7 +473,6 @@ public: Transaction& setTransform(const sp& sc, uint32_t transform); Transaction& setTransformToDisplayInverse(const sp& sc, bool transformToDisplayInverse); - Transaction& setFrame(const sp& sc, const Rect& frame); Transaction& setBuffer(const sp& sc, const sp& buffer, ReleaseBufferCallback callback = nullptr); Transaction& setCachedBuffer(const sp& sc, int32_t bufferId); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index fe48d88376..9b1f0db83b 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -140,7 +140,6 @@ protected: /*parent*/ nullptr); t.setLayerStack(mSurfaceControl, 0) .setLayer(mSurfaceControl, std::numeric_limits::max()) - .setFrame(mSurfaceControl, Rect(resolution)) .show(mSurfaceControl) .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) .apply(); @@ -218,13 +217,13 @@ protected: col >= region.left - border && col < region.right + border; } if (!outsideRegion && inRegion) { - EXPECT_GE(epsilon, abs(r - *(pixel))); - EXPECT_GE(epsilon, abs(g - *(pixel + 1))); - EXPECT_GE(epsilon, abs(b - *(pixel + 2))); + ASSERT_GE(epsilon, abs(r - *(pixel))); + ASSERT_GE(epsilon, abs(g - *(pixel + 1))); + ASSERT_GE(epsilon, abs(b - *(pixel + 2))); } else if (outsideRegion && !inRegion) { - EXPECT_GE(epsilon, abs(r - *(pixel))); - EXPECT_GE(epsilon, abs(g - *(pixel + 1))); - EXPECT_GE(epsilon, abs(b - *(pixel + 2))); + ASSERT_GE(epsilon, abs(r - *(pixel))); + ASSERT_GE(epsilon, abs(g - *(pixel + 1))); + ASSERT_GE(epsilon, abs(b - *(pixel + 2))); } ASSERT_EQ(false, ::testing::Test::HasFailure()); } @@ -466,7 +465,8 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + checkScreenCapture(r, g, b, + {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); } TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { @@ -523,13 +523,15 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + Rect bounds; + bounds.left = finalCropSideLength / 2; + bounds.top = 0; + bounds.right = bounds.left + finalCropSideLength; + bounds.bottom = finalCropSideLength; + + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, bounds)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, - {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength})); - ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(0, 0, 0, - {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength}, - /*border*/ 0, /*outsideRegion*/ true)); + checkScreenCapture(0, 0, 0, bounds, /*border*/ 0, /*outsideRegion*/ true)); } class TestProducerListener : public BnProducerListener { @@ -596,7 +598,6 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { t.setLayerStack(bgSurface, 0) .show(bgSurface) .setDataspace(bgSurface, ui::Dataspace::V0_SRGB) - .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setLayer(bgSurface, std::numeric_limits::max() - 1) .apply(); @@ -619,7 +620,8 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + checkScreenCapture(r, g, b, + {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); } class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 48a0be2c45..ed826a0100 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -278,9 +278,8 @@ bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) { return stateUpdateAvailable; } -// Crop that applies to the window -Rect BufferStateLayer::getCrop(const Layer::State& /*s*/) const { - return Rect::INVALID_RECT; +Rect BufferStateLayer::getCrop(const Layer::State& s) const { + return s.crop; } bool BufferStateLayer::setTransform(uint32_t transform) { @@ -301,57 +300,53 @@ bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInver } bool BufferStateLayer::setCrop(const Rect& crop) { - Rect c = crop; - if (c.left < 0) { - c.left = 0; - } - if (c.top < 0) { - c.top = 0; - } - // If the width and/or height are < 0, make it [0, 0, -1, -1] so the equality comparision below - // treats all invalid rectangles the same. - if (!c.isValid()) { - c.makeInvalid(); - } + if (mCurrentState.crop == crop) return false; + mCurrentState.sequence++; + mCurrentState.crop = crop; - if (mCurrentState.crop == c) return false; - mCurrentState.crop = c; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } -bool BufferStateLayer::setFrame(const Rect& frame) { - int x = frame.left; - int y = frame.top; - int w = frame.getWidth(); - int h = frame.getHeight(); - - if (x < 0) { - x = 0; - w = frame.right; +bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix, + bool allowNonRectPreservingTransforms) { + if (mCurrentState.transform.dsdx() == matrix.dsdx && + mCurrentState.transform.dtdy() == matrix.dtdy && + mCurrentState.transform.dtdx() == matrix.dtdx && + mCurrentState.transform.dsdy() == matrix.dsdy) { + return false; } - if (y < 0) { - y = 0; - h = frame.bottom; - } + ui::Transform t; + t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y && - mCurrentState.width == w && mCurrentState.height == h) { + if (!allowNonRectPreservingTransforms && !t.preserveRects()) { + ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER nor " + "ROTATE_SURFACE_FLINGER ignored"); return false; } - if (!frame.isValid()) { - x = y = w = h = 0; + mCurrentState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); + + mCurrentState.sequence++; + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); + + return true; +} + +bool BufferStateLayer::setPosition(float x, float y) { + if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) { + return false; } + mCurrentState.transform.set(x, y); - mCurrentState.width = w; - mCurrentState.height = h; mCurrentState.sequence++; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); + return true; } @@ -428,6 +423,10 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const spmFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime, FrameTracer::FrameEvent::QUEUE); } + + mCurrentState.width = mCurrentState.buffer->width; + mCurrentState.height = mCurrentState.buffer->height; + return true; } @@ -858,33 +857,6 @@ sp BufferStateLayer::createClone() { return layer; } -Layer::RoundedCornerState BufferStateLayer::getRoundedCornerState() const { - const auto& p = mDrawingParent.promote(); - if (p != nullptr) { - RoundedCornerState parentState = p->getRoundedCornerState(); - if (parentState.radius > 0) { - ui::Transform t = getActiveTransform(getDrawingState()); - t = t.inverse(); - parentState.cropRect = t.transform(parentState.cropRect); - // The rounded corners shader only accepts 1 corner radius for performance reasons, - // but a transform matrix can define horizontal and vertical scales. - // Let's take the average between both of them and pass into the shader, practically we - // never do this type of transformation on windows anyway. - parentState.radius *= (t[0][0] + t[1][1]) / 2.0f; - return parentState; - } - } - const float radius = getDrawingState().cornerRadius; - const State& s(getDrawingState()); - if (radius <= 0 || (getActiveWidth(s) == UINT32_MAX && getActiveHeight(s) == UINT32_MAX)) - return RoundedCornerState(); - return RoundedCornerState(FloatRect(static_cast(s.transform.tx()), - static_cast(s.transform.ty()), - static_cast(s.transform.tx() + s.width), - static_cast(s.transform.ty() + s.height)), - radius); -} - bool BufferStateLayer::bufferNeedsFiltering() const { const State& s(getDrawingState()); if (!s.buffer) { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 3878f50776..8ce3e1f55b 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -66,7 +66,6 @@ public: bool setTransform(uint32_t transform) override; bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; - bool setFrame(const Rect& frame) override; bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, @@ -81,15 +80,13 @@ public: bool setTransactionCompletedListeners(const std::vector>& handles) override; bool addFrameEvent(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime) override; + bool setPosition(float /*x*/, float /*y*/) override; + bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, + bool /*allowNonRectPreservingTransforms*/); // Override to ignore legacy layer state properties that are not used by BufferStateLayer bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } - bool setPosition(float /*x*/, float /*y*/) override { return false; } bool setTransparentRegionHint(const Region& transparent) override; - bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, - bool /*allowNonRectPreservingTransforms*/) override { - return false; - } void deferTransactionUntil_legacy(const sp& /*barrierHandle*/, uint64_t /*frameNumber*/) override {} void deferTransactionUntil_legacy(const sp& /*barrierLayer*/, @@ -97,7 +94,6 @@ public: Rect getBufferSize(const State& s) const override; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; - Layer::RoundedCornerState getRoundedCornerState() const override; void setAutoRefresh(bool autoRefresh) override; // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 94fd62fa7a..6038658ee6 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2287,8 +2287,8 @@ Layer::RoundedCornerState Layer::getRoundedCornerState() const { } } const float radius = getDrawingState().cornerRadius; - return radius > 0 && getCrop(getDrawingState()).isValid() - ? RoundedCornerState(getCrop(getDrawingState()).toFloatRect(), radius) + return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid() + ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius) : RoundedCornerState(); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 3a45c949a4..5528a8190f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -412,7 +412,6 @@ public: // Used only to set BufferStateLayer state virtual bool setTransform(uint32_t /*transform*/) { return false; }; virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; }; - virtual bool setFrame(const Rect& /*frame*/) { return false; }; virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 1d00cc38f2..7a3e433660 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -231,8 +231,14 @@ const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uin void RefreshRateOverlay::setViewport(ui::Size viewport) { Rect frame((3 * viewport.width) >> 4, viewport.height >> 5); frame.offsetBy(viewport.width >> 5, viewport.height >> 4); - mLayer->setFrame(frame); + layer_state_t::matrix22_t matrix; + matrix.dsdx = frame.getWidth() / static_cast(SevenSegmentDrawer::getWidth()); + matrix.dtdx = 0; + matrix.dtdy = 0; + matrix.dsdy = frame.getHeight() / static_cast(SevenSegmentDrawer::getHeight()); + mLayer->setMatrix(matrix, true); + mLayer->setPosition(frame.left, frame.top); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 825834bb4f..8a8ccb91c0 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4033,9 +4033,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (what & layer_state_t::eCropChanged) { if (layer->setCrop(s.crop)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eFrameChanged) { - if (layer->setFrame(s.orientedDisplaySpaceRect)) flags |= eTraversalNeeded; - } if (what & layer_state_t::eAcquireFenceChanged) { if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded; } diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp index 03f8e1afba..47a150dd35 100644 --- a/services/surfaceflinger/tests/BufferGenerator.cpp +++ b/services/surfaceflinger/tests/BufferGenerator.cpp @@ -296,12 +296,12 @@ private: BufferGenerator::BufferGenerator() : mSurfaceManager(new SurfaceManager), mEglManager(new EglManager), mProgram(new Program) { - const float width = 1000.0; - const float height = 1000.0; + mBufferSize.set(1000.0, 1000.0); auto setBufferWithContext = std::bind(setBuffer, std::placeholders::_1, std::placeholders::_2, this); - mSurfaceManager->initialize(width, height, HAL_PIXEL_FORMAT_RGBA_8888, setBufferWithContext); + mSurfaceManager->initialize(mBufferSize.width, mBufferSize.height, HAL_PIXEL_FORMAT_RGBA_8888, + setBufferWithContext); if (!mEglManager->initialize(mSurfaceManager->getSurface())) return; @@ -309,7 +309,9 @@ BufferGenerator::BufferGenerator() if (!mProgram->initialize(VERTEX_SHADER, FRAGMENT_SHADER)) return; mProgram->use(); - mProgram->bindVec4(0, vec4{width, height, 1.0f / width, 1.0f / height}); + mProgram->bindVec4(0, + vec4{mBufferSize.width, mBufferSize.height, 1.0f / mBufferSize.width, + 1.0f / mBufferSize.height}); mProgram->bindVec3(2, &SPHERICAL_HARMONICS[0], 4); glEnableVertexAttribArray(0); @@ -372,6 +374,10 @@ status_t BufferGenerator::get(sp* outBuffer, sp* outFence) return NO_ERROR; } +ui::Size BufferGenerator::getSize() { + return mBufferSize; +} + // static void BufferGenerator::setBuffer(const sp& buffer, int32_t fence, void* bufferGenerator) { diff --git a/services/surfaceflinger/tests/BufferGenerator.h b/services/surfaceflinger/tests/BufferGenerator.h index a3ffe86572..f7d548b6bf 100644 --- a/services/surfaceflinger/tests/BufferGenerator.h +++ b/services/surfaceflinger/tests/BufferGenerator.h @@ -37,6 +37,7 @@ public: /* Static callback that sets the fence on a particular instance */ static void setBuffer(const sp& buffer, int32_t fence, void* fenceGenerator); + ui::Size getSize(); private: bool mInitialized = false; @@ -53,6 +54,7 @@ private: using Epoch = std::chrono::time_point; Epoch mEpoch = std::chrono::steady_clock::now(); + ui::Size mBufferSize; }; } // namespace android diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp index f470eda7d3..af00ec7fc9 100644 --- a/services/surfaceflinger/tests/EffectLayer_test.cpp +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -149,7 +149,6 @@ TEST_F(EffectLayerTest, BlurEffectLayerIsVisible) { t.reparent(blurLayer, mParentLayer); t.setBackgroundBlurRadius(blurLayer, blurRadius); t.setCrop(blurLayer, blurRect); - t.setFrame(blurLayer, blurRect); t.setAlpha(blurLayer, 0.0f); t.show(blurLayer); }); diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp index a8647c3e50..9fa3d4c417 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -161,7 +161,6 @@ public: Color::RED); transaction->setLayerStack(mSurfaceControl, 0) .setLayer(mSurfaceControl, std::numeric_limits::max()) - .setFrame(mSurfaceControl, Rect(0, 0, width, height)) .setBuffer(mSurfaceControl, gb) .setAcquireFence(mSurfaceControl, fence) .show(mSurfaceControl) diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 158801a705..011ff70409 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -164,7 +164,10 @@ TEST_F(LayerCallbackTest, NoBufferNoColor) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer, @@ -184,7 +187,10 @@ TEST_F(LayerCallbackTest, BufferNoColor) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -203,7 +209,10 @@ TEST_F(LayerCallbackTest, NoBufferColor) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, @@ -238,7 +247,10 @@ TEST_F(LayerCallbackTest, OffScreen) { return; } - transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(-100, -100, 100, 100)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -263,8 +275,15 @@ TEST_F(LayerCallbackTest, MergeBufferNoColor) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -290,8 +309,15 @@ TEST_F(LayerCallbackTest, MergeNoBufferColor) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -318,8 +344,15 @@ TEST_F(LayerCallbackTest, MergeOneBufferOneColor) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1); @@ -405,8 +438,15 @@ TEST_F(LayerCallbackTest, Merge_DifferentClients) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -491,7 +531,11 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) { } } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED @@ -523,8 +567,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -564,8 +616,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -606,8 +666,15 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateCha return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -661,8 +728,15 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -682,7 +756,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC return; } - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + transaction2.merge(std::move(transaction1)).apply(); expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2, ExpectedResult::Buffer::NOT_ACQUIRED); @@ -762,7 +839,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expectedResult; expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -781,7 +861,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + TransactionUtils::setFrame(transaction, layer, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); } EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 7505e6ea9b..53d230abe7 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -204,11 +204,7 @@ void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply(); break; case ISurfaceComposerClient::eFXSurfaceBufferState: - Transaction() - .setFrame(layerR, Rect(0, 0, 32, 32)) - .setFrame(layerG, Rect(16, 16, 48, 48)) - .setRelativeLayer(layerG, layerR, 1) - .apply(); + Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply(); break; default: ASSERT_FALSE(true) << "Unsupported layer type"; @@ -260,10 +256,9 @@ void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) break; case ISurfaceComposerClient::eFXSurfaceBufferState: Transaction() - .setFrame(layerR, Rect(0, 0, 32, 32)) - .setFrame(layerG, Rect(8, 8, 40, 40)) + .setPosition(layerG, 8, 8) .setRelativeLayer(layerG, layerR, 3) - .setFrame(layerB, Rect(16, 16, 48, 48)) + .setPosition(layerB, 16, 16) .setLayer(layerB, mLayerZBase + 2) .apply(); break; @@ -388,7 +383,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState Transaction() .setTransparentRegionHint(layer, Region(top)) .setBuffer(layer, buffer) - .setFrame(layer, Rect(0, 0, 32, 32)) .apply(); { SCOPED_TRACE("top transparent"); @@ -447,7 +441,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_Buffe // check that transparent region hint is bound by the layer size Transaction() .setTransparentRegionHint(layerTransparent, Region(mDisplayRect)) - .setFrame(layerR, Rect(16, 16, 48, 48)) + .setPosition(layerR, 16, 16) .setLayer(layerR, mLayerZBase + 1) .apply(); ASSERT_NO_FATAL_FAILURE( @@ -477,8 +471,7 @@ void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) { Transaction() .setAlpha(layer1, 0.25f) .setAlpha(layer2, 0.75f) - .setFrame(layer1, Rect(0, 0, 32, 32)) - .setFrame(layer2, Rect(16, 0, 48, 32)) + .setPosition(layer2, 16, 0) .setLayer(layer2, mLayerZBase + 1) .apply(); break; @@ -573,7 +566,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height)); expectedColor = fillColor; } - Transaction().setFrame(layer, Rect(0, 0, width, height)).apply(); + Transaction().setCrop(layer, Rect(0, 0, width, height)).apply(); break; default: GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper"; @@ -849,42 +842,39 @@ TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE)); - Transaction() - .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f) - .setFrame(layer, Rect(0, 0, 32, 32)) - .apply(); + Transaction().setPosition(layer, 32, 32).setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).apply(); { SCOPED_TRACE("IDENTITY"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, + getScreenCapture()->expectQuadrant(Rect(32, 32, 64, 64), Color::RED, Color::GREEN, Color::BLUE, Color::WHITE); } Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply(); { SCOPED_TRACE("FLIP_H"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(0, 32, 32, 64), Color::GREEN, Color::RED, + Color::WHITE, Color::BLUE); } Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply(); { SCOPED_TRACE("FLIP_V"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(32, 0, 64, 32), Color::BLUE, Color::WHITE, + Color::RED, Color::GREEN); } Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply(); { SCOPED_TRACE("ROT_90"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(0, 32, 32, 64), Color::BLUE, Color::RED, + Color::WHITE, Color::GREEN); } Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply(); { SCOPED_TRACE("SCALE"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(32, 32, 96, 96), Color::RED, Color::GREEN, + Color::BLUE, Color::WHITE, 1 /* tolerance */); } } @@ -955,8 +945,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) { Transaction().setCrop(layer, crop).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(crop, Color::RED); + shot->expectBorder(crop, Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) { @@ -986,13 +976,13 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) { { SCOPED_TRACE("empty rect"); Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); } { SCOPED_TRACE("negative rect"); Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); } } @@ -1016,8 +1006,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED); - Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply(); - Transaction().setBuffer(layer, buffer).apply(); // Partially out of bounds in the negative (upper left) direction @@ -1025,8 +1013,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("out of bounds, negative (upper left) direction"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE); - shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 16), Color::BLUE); + shot->expectBorder(Rect(0, 0, 32, 16), Color::BLACK); } // Partially out of bounds in the positive (lower right) direction @@ -1034,8 +1022,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("out of bounds, positive (lower right) direction"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 64, 64), Color::RED); - shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); + shot->expectColor(Rect(0, 16, 32, 64), Color::RED); + shot->expectBorder(Rect(0, 16, 32, 64), Color::BLACK); } // Fully out of buffer space bounds @@ -1043,9 +1031,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("Fully out of bounds"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE); - shot->expectColor(Rect(0, 16, 64, 64), Color::RED); - shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); + shot->expectColor(Rect(0, 0, 64, 64), Color::BLACK); } } @@ -1068,12 +1054,11 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); - const Rect frame(32, 32, 64, 64); const Rect crop(8, 8, 24, 24); - Transaction().setFrame(layer, frame).setCrop(layer, crop).apply(); + Transaction().setPosition(layer, 32, 32).setCrop(layer, crop).apply(); auto shot = getScreenCapture(); - shot->expectColor(frame, Color::RED); - shot->expectBorder(frame, Color::BLACK); + shot->expectColor(Rect(40, 40, 56, 56), Color::RED); + shot->expectBorder(Rect(40, 40, 56, 56), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) { @@ -1121,7 +1106,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); const Rect frame(8, 8, 24, 24); - Transaction().setFrame(layer, frame).apply(); + Transaction t; + TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), frame); + t.apply(); + auto shot = getScreenCapture(); shot->expectColor(frame, Color::RED); shot->expectBorder(frame, Color::BLACK); @@ -1133,16 +1121,23 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + Transaction t; { SCOPED_TRACE("empty rect"); - Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply(); + TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), Rect(8, 8, 8, 8)); + t.apply(); + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); } { SCOPED_TRACE("negative rect"); - Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); + TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), Rect(8, 8, 0, 0)); + t.apply(); + + auto shot = getScreenCapture(); + shot->expectColor(Rect(0, 0, 8, 8), Color::RED); + shot->expectBorder(Rect(0, 0, 8, 8), Color::BLACK); } } @@ -1152,10 +1147,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10)); - // A parentless layer will default to a frame with the same size as the buffer + // A layer with a buffer will have a computed size that matches the buffer size. auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 10, 10), Color::RED); + shot->expectBorder(Rect(0, 0, 10, 10), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) { @@ -1163,17 +1158,16 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) { ASSERT_NO_FATAL_FAILURE( parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); - Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply(); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); Transaction().reparent(child, parent).apply(); - // A layer will default to the frame of its parent + // A layer with a buffer will have a computed size that matches the buffer size. auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); + shot->expectColor(Rect(0, 0, 10, 10), Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1183,14 +1177,14 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); Transaction().reparent(child, parent).apply(); - // A layer will default to the frame of its parent + // A layer with a buffer will have a computed size that matches the buffer size. auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); + shot->expectColor(Rect(0, 0, 10, 10), Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1199,11 +1193,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) { ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); - Transaction().setFrame(layer, Rect(0, 0, 32, 32)).apply(); std::this_thread::sleep_for(500ms); - Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply(); + Transaction().setPosition(layer, 16, 16).apply(); auto shot = getScreenCapture(); shot->expectColor(Rect(16, 16, 48, 48), Color::RED); @@ -1215,18 +1208,20 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) { ASSERT_NO_FATAL_FAILURE( parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); Transaction().reparent(child, parent).apply(); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); - Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply(); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); - Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply(); + Rect childDst(0, 16, 32, 32); + Transaction t; + TransactionUtils::setFrame(t, child, Rect(0, 0, 10, 10), childDst); + t.apply(); auto shot = getScreenCapture(); shot->expectColor(Rect(0, 0, 32, 16), Color::RED); - shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE); + shot->expectColor(childDst, Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1238,8 +1233,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { @@ -1252,8 +1247,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 1"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32)); @@ -1261,8 +1256,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 2"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); @@ -1270,8 +1265,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 3"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } } @@ -1286,7 +1281,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64)); - Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply(); { SCOPED_TRACE("set layer 1 buffer red"); auto shot = getScreenCapture(); @@ -1295,7 +1289,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32)); - Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply(); { SCOPED_TRACE("set layer 2 buffer blue"); auto shot = getScreenCapture(); @@ -1350,8 +1343,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) { Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } idx++; } @@ -1383,8 +1376,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_Buffer Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } idx++; } @@ -1416,8 +1409,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferSt Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } if (idx == 0) { buffers[0].clear(); @@ -1435,7 +1428,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) { Color::BLUE, Color::WHITE)); Transaction() - .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90) .apply(); @@ -1452,7 +1444,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) { Color::BLUE, Color::WHITE)); Transaction() - .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H) .apply(); @@ -1469,7 +1460,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) { Color::BLUE, Color::WHITE)); Transaction() - .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V) .apply(); @@ -1518,8 +1508,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) { Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) { @@ -1534,8 +1524,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) { Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) { @@ -1552,8 +1542,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) { Transaction().setBuffer(layer, buffer).setHdrMetadata(layer, hdrMetadata).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) { @@ -1570,8 +1560,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) Transaction().setBuffer(layer, buffer).setSurfaceDamageRegion(layer, region).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) { @@ -1586,8 +1576,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) { Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) { diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 87c7b7d829..0bc8fe7aa0 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -244,6 +244,11 @@ protected: return bufferGenerator.get(outBuffer, outFence); } + static ui::Size getBufferSize() { + static BufferGenerator bufferGenerator; + return bufferGenerator.getSize(); + } + sp mClient; bool deviceSupportsBlurs() { diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index ac5e297e43..edf55ea6ef 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -196,17 +196,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size)); - if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { - Transaction() - .setCornerRadius(layer, cornerRadius) - .setCrop(layer, Rect(0, 0, size, size)) - .apply(); - } else { - Transaction() - .setCornerRadius(layer, cornerRadius) - .setFrame(layer, Rect(0, 0, size, size)) - .apply(); - } + Transaction().setCornerRadius(layer, cornerRadius).apply(); { const uint8_t bottom = size - 1; const uint8_t right = size - 1; @@ -234,19 +224,13 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) { ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); - auto transaction = Transaction() - .setCornerRadius(parent, cornerRadius) - .setCrop(parent, Rect(0, 0, size, size)) - .reparent(child, parent) - .setPosition(child, 0, size) - // Rotate by half PI - .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f); - if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { - transaction.setCrop(parent, Rect(0, 0, size, size)); - } else { - transaction.setFrame(parent, Rect(0, 0, size, size)); - } - transaction.apply(); + Transaction() + .setCornerRadius(parent, cornerRadius) + .reparent(child, parent) + .setPosition(child, 0, size) + // Rotate by half PI + .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f) + .apply(); { const uint8_t bottom = size - 1; @@ -275,21 +259,12 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) { ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2)); - if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { - Transaction() - .setCornerRadius(parent, cornerRadius) - .setCrop(parent, Rect(0, 0, size, size)) - .reparent(child, parent) - .setPosition(child, 0, size / 2) - .apply(); - } else { - Transaction() - .setCornerRadius(parent, cornerRadius) - .setFrame(parent, Rect(0, 0, size, size)) - .reparent(child, parent) - .setFrame(child, Rect(0, size / 2, size, size)) - .apply(); - } + Transaction() + .setCornerRadius(parent, cornerRadius) + .reparent(child, parent) + .setPosition(child, 0, size / 2) + .apply(); + { const uint8_t bottom = size - 1; const uint8_t right = size - 1; @@ -331,12 +306,9 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { Transaction() .setLayer(greenLayer, mLayerZBase) - .setFrame(leftLayer, {0, 0, canvasSize * 2, canvasSize * 2}) .setLayer(leftLayer, mLayerZBase + 1) - .setFrame(leftLayer, leftRect) .setLayer(rightLayer, mLayerZBase + 2) .setPosition(rightLayer, rightRect.left, rightRect.top) - .setFrame(rightLayer, rightRect) .apply(); { @@ -352,7 +324,6 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { .setLayer(blurLayer, mLayerZBase + 3) .setBackgroundBlurRadius(blurLayer, blurRadius) .setCrop(blurLayer, blurRect) - .setFrame(blurLayer, blurRect) .setSize(blurLayer, blurRect.getWidth(), blurRect.getHeight()) .setAlpha(blurLayer, 0.0f) .apply(); @@ -435,10 +406,8 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurAffectedByParentA Transaction() .setLayer(left, mLayerZBase + 1) - .setFrame(left, {0, 0, size, size}) .setLayer(right, mLayerZBase + 2) .setPosition(right, size, 0) - .setFrame(right, {size, 0, size * 2, size}) .apply(); { @@ -457,7 +426,6 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurAffectedByParentA .setAlpha(blurParent, 0.5) .setLayer(blur, mLayerZBase + 4) .setBackgroundBlurRadius(blur, size) // set the blur radius to the size of one rect - .setFrame(blur, {0, 0, size * 2, size}) .reparent(blur, blurParent) .apply(); diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index 613b21ef04..ccf434d63a 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -195,7 +195,7 @@ TEST_F(MirrorLayerTest, MirrorBufferLayer) { createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState, mChildLayer.get()); fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200); - Transaction().setFrame(bufferStateLayer, Rect(0, 0, 200, 200)).show(bufferStateLayer).apply(); + Transaction().show(bufferStateLayer).apply(); { SCOPED_TRACE("Initial Mirror BufferStateLayer"); diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h index 3cbfed98f5..8c448e2f96 100644 --- a/services/surfaceflinger/tests/utils/TransactionUtils.h +++ b/services/surfaceflinger/tests/utils/TransactionUtils.h @@ -126,7 +126,7 @@ public: const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4; for (int32_t i = 0; i < width; i++) { const uint8_t expected[4] = {color.r, color.g, color.b, color.a}; - EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare)) + ASSERT_TRUE(std::equal(src, src + 4, expected, colorCompare)) << "pixel @ (" << x + i << ", " << y + j << "): " << "expected (" << color << "), " << "got (" << Color{src[0], src[1], src[2], src[3]} << ")"; @@ -161,6 +161,22 @@ public: ASSERT_EQ(NO_ERROR, s->unlockAndPost()); } } + + static void setFrame(Transaction& t, const sp& sc, Rect source, Rect dest, + int32_t transform = 0) { + uint32_t sourceWidth = source.getWidth(); + uint32_t sourceHeight = source.getHeight(); + + if (transform & ui::Transform::ROT_90) { + std::swap(sourceWidth, sourceHeight); + } + + float dsdx = dest.getWidth() / static_cast(sourceWidth); + float dsdy = dest.getHeight() / static_cast(sourceHeight); + + t.setMatrix(sc, dsdx, 0, 0, dsdy); + t.setPosition(sc, dest.left, dest.top); + } }; enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY }; -- cgit v1.2.3-59-g8ed1b From 5b3b9146e0e038411fb72e411853d7d79d853ae5 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 22 Feb 2021 12:27:32 -0800 Subject: SurfaceFlinger: Prepare to remove BufferQueueLayer To prepare to remove BufferQueueLayer we port over the public Java API (getSurface) and a few remaining clients (largely tests), by returning a BBQ from getSurface. Bug: 185492007 Test: Existing tests pass Change-Id: I0ec0d765659783e1bdbb3f243ad60e3355cfdf4f --- libs/gui/BLASTBufferQueue.cpp | 6 +- libs/gui/SurfaceComposerClient.cpp | 9 +- libs/gui/SurfaceControl.cpp | 83 +++++++-- libs/gui/include/gui/SurfaceControl.h | 22 ++- libs/gui/tests/BLASTBufferQueue_test.cpp | 118 ------------- services/surfaceflinger/SurfaceFlinger.cpp | 4 - services/surfaceflinger/tests/Credentials_test.cpp | 19 -- .../tests/LayerRenderTypeTransaction_test.cpp | 131 -------------- .../LayerTypeAndRenderTypeTransaction_test.cpp | 6 - services/surfaceflinger/tests/LayerUpdate_test.cpp | 193 --------------------- .../surfaceflinger/tests/ScreenCapture_test.cpp | 41 +++-- .../tests/SurfaceInterceptor_test.cpp | 25 --- .../tests/fakehwc/SFFakeHwc_test.cpp | 152 ---------------- 13 files changed, 117 insertions(+), 692 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index e5afd408a9..bd5edbdd5a 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -161,9 +161,9 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spgetTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); SurfaceComposerClient::Transaction() - .setFlags(surface, layer_state_t::eEnableBackpressure, - layer_state_t::eEnableBackpressure) - .apply(); + .setFlags(surface, layer_state_t::eEnableBackpressure, + layer_state_t::eEnableBackpressure) + .apply(); mNumAcquired = 0; mNumFrameAvailable = 0; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index e6baba6e1d..6d198a105f 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -896,7 +896,7 @@ void SurfaceComposerClient::Transaction::setEarlyWakeupEnd() { } layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp& sc) { - auto handle = sc->getHandle(); + auto handle = sc->getLayerStateHandle(); if (mComposerStates.count(handle) == 0) { // we don't have it, add an initialized layer_state to our list @@ -1147,8 +1147,11 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent mStatus = BAD_INDEX; return *this; } + if (SurfaceControl::isSameSurface(sc, newParent)) { + return *this; + } s->what |= layer_state_t::eReparent; - s->parentSurfaceControlForChild = newParent; + s->parentSurfaceControlForChild = newParent ? newParent->getParentingLayer() : nullptr; registerSurfaceControlForCallback(sc); return *this; @@ -1793,7 +1796,7 @@ status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32 } ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { - *outSurface = new SurfaceControl(this, handle, gbp, id, transformHint); + *outSurface = new SurfaceControl(this, handle, gbp, id, w, h, format, transformHint); } } return err; diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 7e2f8f9d36..37750faa8f 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -49,12 +50,17 @@ namespace android { SurfaceControl::SurfaceControl(const sp& client, const sp& handle, const sp& gbp, int32_t layerId, - uint32_t transform) + uint32_t w, uint32_t h, PixelFormat format, uint32_t transform, + uint32_t flags) : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), mLayerId(layerId), - mTransformHint(transform) {} + mTransformHint(transform), + mWidth(w), + mHeight(h), + mFormat(format), + mCreateFlags(flags) {} SurfaceControl::SurfaceControl(const sp& other) { mClient = other->mClient; @@ -62,6 +68,9 @@ SurfaceControl::SurfaceControl(const sp& other) { mGraphicBufferProducer = other->mGraphicBufferProducer; mTransformHint = other->mTransformHint; mLayerId = other->mLayerId; + mWidth = other->mWidth; + mHeight = other->mHeight; + mCreateFlags = other->mCreateFlags; } SurfaceControl::~SurfaceControl() @@ -70,13 +79,13 @@ SurfaceControl::~SurfaceControl() // happen without delay, since these resources are quite heavy. mClient.clear(); mHandle.clear(); - mGraphicBufferProducer.clear(); + mBbq.clear(); IPCThreadState::self()->flushCommands(); } void SurfaceControl::disconnect() { - if (mGraphicBufferProducer != nullptr) { - mGraphicBufferProducer->disconnect( + if (getIGraphicBufferProducer() != nullptr) { + getIGraphicBufferProducer()->disconnect( BufferQueueCore::CURRENTLY_CONNECTED_API); } } @@ -118,21 +127,28 @@ status_t SurfaceControl::writeSurfaceToParcel( { sp bp; if (control != nullptr) { - bp = control->mGraphicBufferProducer; + bp = control->getIGraphicBufferProducer(); } return parcel->writeStrongBinder(IInterface::asBinder(bp)); } -sp SurfaceControl::generateSurfaceLocked() const +sp SurfaceControl::generateSurfaceLocked() { + uint32_t ignore; + auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow | + ISurfaceComposerClient::eOpaque); + mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat, + flags, mHandle, {}, &ignore); + mBbq = new BLASTBufferQueue("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat); + // This surface is always consumed by SurfaceFlinger, so the // producerControlledByApp value doesn't matter; using false. - mSurfaceData = new Surface(mGraphicBufferProducer, false); + mSurfaceData = mBbq->getSurface(true); return mSurfaceData; } -sp SurfaceControl::getSurface() const +sp SurfaceControl::getSurface() { Mutex::Autolock _l(mLock); if (mSurfaceData == nullptr) { @@ -141,25 +157,42 @@ sp SurfaceControl::getSurface() const return mSurfaceData; } -sp SurfaceControl::createSurface() const +sp SurfaceControl::createSurface() { + return getSurface(); +} + +void SurfaceControl::updateDefaultBufferSize(uint32_t width, uint32_t height) { Mutex::Autolock _l(mLock); - return generateSurfaceLocked(); + mWidth = width; mHeight = height; + if (mBbq) { + mBbq->update(this, width, height, mFormat); + } + } -sp SurfaceControl::getHandle() const +sp SurfaceControl::getLayerStateHandle() const { return mHandle; } +sp SurfaceControl::getHandle() const { + if (mBbqChild != nullptr) { + return mBbqChild->getHandle(); + } + return getLayerStateHandle(); +} + int32_t SurfaceControl::getLayerId() const { return mLayerId; } -sp SurfaceControl::getIGraphicBufferProducer() const +sp SurfaceControl::getIGraphicBufferProducer() { + getSurface(); Mutex::Autolock _l(mLock); - return mGraphicBufferProducer; + + return mBbq->getIGraphicBufferProducer(); } sp SurfaceControl::getClient() const @@ -180,9 +213,11 @@ void SurfaceControl::setTransformHint(uint32_t hint) { status_t SurfaceControl::writeToParcel(Parcel& parcel) { SAFE_PARCEL(parcel.writeStrongBinder, ISurfaceComposerClient::asBinder(mClient->getClient())); SAFE_PARCEL(parcel.writeStrongBinder, mHandle); - SAFE_PARCEL(parcel.writeStrongBinder, IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); SAFE_PARCEL(parcel.writeInt32, mLayerId); SAFE_PARCEL(parcel.writeUint32, mTransformHint); + SAFE_PARCEL(parcel.writeUint32, mWidth); + SAFE_PARCEL(parcel.writeUint32, mHeight); + SAFE_PARCEL(parcel.writeUint32, mFormat); return NO_ERROR; } @@ -191,21 +226,26 @@ status_t SurfaceControl::readFromParcel(const Parcel& parcel, sp* outSurfaceControl) { sp client; sp handle; - sp gbp; int32_t layerId; uint32_t transformHint; + uint32_t width; + uint32_t height; + uint32_t format; SAFE_PARCEL(parcel.readStrongBinder, &client); SAFE_PARCEL(parcel.readStrongBinder, &handle); - SAFE_PARCEL(parcel.readNullableStrongBinder, &gbp); SAFE_PARCEL(parcel.readInt32, &layerId); SAFE_PARCEL(parcel.readUint32, &transformHint); + SAFE_PARCEL(parcel.readUint32, &width); + SAFE_PARCEL(parcel.readUint32, &height); + SAFE_PARCEL(parcel.readUint32, &format); // We aren't the original owner of the surface. *outSurfaceControl = new SurfaceControl(new SurfaceComposerClient( interface_cast(client)), - handle.get(), interface_cast(gbp), layerId, + handle.get(), nullptr, layerId, + width, height, format, transformHint); return NO_ERROR; @@ -233,5 +273,12 @@ status_t SurfaceControl::writeNullableToParcel(Parcel& parcel, return NO_ERROR; } +sp SurfaceControl::getParentingLayer() { + if (mBbqChild != nullptr) { + return mBbqChild; + } + return this; +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 35bdfc155d..9ee4636ae1 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -37,6 +37,7 @@ namespace android { class IGraphicBufferProducer; class Surface; class SurfaceComposerClient; +class BLASTBufferQueue; // --------------------------------------------------------------------------- @@ -70,12 +71,13 @@ public: static status_t writeSurfaceToParcel( const sp& control, Parcel* parcel); - sp getSurface() const; - sp createSurface() const; + sp getSurface(); + sp createSurface(); sp getHandle() const; + sp getLayerStateHandle() const; int32_t getLayerId() const; - sp getIGraphicBufferProducer() const; + sp getIGraphicBufferProducer(); status_t clearLayerFrameStats() const; status_t getLayerFrameStats(FrameStats* outStats) const; @@ -85,12 +87,16 @@ public: uint32_t getTransformHint() const; void setTransformHint(uint32_t hint); + void updateDefaultBufferSize(uint32_t width, uint32_t height); explicit SurfaceControl(const sp& other); SurfaceControl(const sp& client, const sp& handle, const sp& gbp, int32_t layerId, - uint32_t transformHint = 0); + uint32_t width = 0, uint32_t height = 0, PixelFormat format = 0, + uint32_t transformHint = 0, uint32_t flags = 0); + + sp getParentingLayer(); private: // can't be copied @@ -102,7 +108,7 @@ private: ~SurfaceControl(); - sp generateSurfaceLocked() const; + sp generateSurfaceLocked(); status_t validate() const; sp mClient; @@ -110,8 +116,14 @@ private: sp mGraphicBufferProducer; mutable Mutex mLock; mutable sp mSurfaceData; + mutable sp mBbq; + mutable sp mBbqChild; int32_t mLayerId; uint32_t mTransformHint; + uint32_t mWidth; + uint32_t mHeight; + PixelFormat mFormat; + uint32_t mCreateFlags; }; }; // namespace android diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 9b1f0db83b..a44f44fbe6 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -836,26 +836,6 @@ public: if (postedTime) *postedTime = systemTime(); igbProducer->queueBuffer(slot, input, qbOutput); } - - void createBufferQueueProducer(sp* bqIgbp) { - mBufferQueueSurfaceControl = - mClient->createSurface(String8("BqSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceBufferQueue); - ASSERT_NE(nullptr, mBufferQueueSurfaceControl.get()); - Transaction() - .setLayerStack(mBufferQueueSurfaceControl, 0) - .show(mBufferQueueSurfaceControl) - .setDataspace(mBufferQueueSurfaceControl, ui::Dataspace::V0_SRGB) - .setSize(mBufferQueueSurfaceControl, mDisplayWidth, mDisplayHeight) - .setLayer(mBufferQueueSurfaceControl, std::numeric_limits::max()) - .apply(); - - sp bqSurface = mBufferQueueSurfaceControl->getSurface(); - ASSERT_NE(nullptr, bqSurface.get()); - - *bqIgbp = bqSurface->getIGraphicBufferProducer(); - setUpProducer(*bqIgbp); - } sp mBufferQueueSurfaceControl; }; @@ -911,55 +891,6 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) { adapter.waitForCallbacks(); } -// Runs the same Frame Event History test -TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic_BufferQueue) { - sp bqIgbp; - createBufferQueueProducer(&bqIgbp); - - ProducerFrameEventHistory history; - IGraphicBufferProducer::QueueBufferOutput qbOutput; - nsecs_t requestedPresentTimeA = 0; - nsecs_t postedTimeA = 0; - setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true); - history.applyDelta(qbOutput.frameTimestamps); - - FrameEvents* events = nullptr; - events = history.getFrame(1); - ASSERT_NE(nullptr, events); - ASSERT_EQ(1, events->frameNumber); - ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeA); - - // wait for buffer to be presented - std::this_thread::sleep_for(200ms); - - nsecs_t requestedPresentTimeB = 0; - nsecs_t postedTimeB = 0; - setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true); - history.applyDelta(qbOutput.frameTimestamps); - events = history.getFrame(1); - ASSERT_NE(nullptr, events); - - // frame number, requestedPresentTime, and postTime should not have changed - ASSERT_EQ(1, events->frameNumber); - ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeA); - - ASSERT_GE(events->latchTime, postedTimeA); - ASSERT_FALSE(events->hasDequeueReadyInfo()); - - ASSERT_NE(nullptr, events->gpuCompositionDoneFence); - ASSERT_NE(nullptr, events->displayPresentFence); - ASSERT_NE(nullptr, events->releaseFence); - - // we should also have gotten the initial values for the next frame - events = history.getFrame(2); - ASSERT_NE(nullptr, events); - ASSERT_EQ(2, events->frameNumber); - ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeB); -} - TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp igbProducer; @@ -1010,53 +941,4 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) { ASSERT_GE(events->postedTime, postedTimeB); } -TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame_BufferQueue) { - sp bqIgbp; - createBufferQueueProducer(&bqIgbp); - - ProducerFrameEventHistory history; - IGraphicBufferProducer::QueueBufferOutput qbOutput; - nsecs_t requestedPresentTimeA = 0; - nsecs_t postedTimeA = 0; - nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); - setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true, - presentTimeDelay); - history.applyDelta(qbOutput.frameTimestamps); - - FrameEvents* events = nullptr; - events = history.getFrame(1); - ASSERT_NE(nullptr, events); - ASSERT_EQ(1, events->frameNumber); - ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeA); - - // queue another buffer so the first can be dropped - nsecs_t requestedPresentTimeB = 0; - nsecs_t postedTimeB = 0; - setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true); - history.applyDelta(qbOutput.frameTimestamps); - events = history.getFrame(1); - ASSERT_NE(nullptr, events); - - // frame number, requestedPresentTime, and postTime should not have changed - ASSERT_EQ(1, events->frameNumber); - ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeA); - - // a valid latchtime should not be set - ASSERT_FALSE(events->hasLatchInfo()); - ASSERT_FALSE(events->hasDequeueReadyInfo()); - - ASSERT_NE(nullptr, events->gpuCompositionDoneFence); - ASSERT_NE(nullptr, events->displayPresentFence); - ASSERT_NE(nullptr, events->releaseFence); - - // we should also have gotten the initial values for the next frame - events = history.getFrame(2); - ASSERT_NE(nullptr, events); - ASSERT_EQ(2, events->frameNumber); - ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeB); -} - } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 828543f938..ef5048b489 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4160,10 +4160,6 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: - result = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags, - std::move(metadata), format, handle, gbp, &layer); - - break; case ISurfaceComposerClient::eFXSurfaceBufferState: { result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags, std::move(metadata), handle, &layer); diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 6246321fab..fa3f0e7239 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -305,25 +305,6 @@ TEST_F(CredentialsTest, CaptureLayersTest) { /** * The following tests are for methods accessible directly through SurfaceFlinger. */ - -/** - * An app can pass a buffer queue to the media server and ask the media server to decode a DRM video - * to that buffer queue. The media server is the buffer producer in this case. Because the app may create - * its own buffer queue and act as the buffer consumer, the media server wants to be careful to avoid - * sending decoded video frames to the app. This is where authenticateSurfaceTexture call comes in, to check - * the consumer of a buffer queue is SurfaceFlinger. - */ -TEST_F(CredentialsTest, AuthenticateSurfaceTextureTest) { - setupBackgroundSurface(); - sp producer = - mBGSurfaceControl->getSurface()->getIGraphicBufferProducer(); - sp sf(ComposerService::getComposerService()); - - std::function condition = [=]() { return sf->authenticateSurfaceTexture(producer); }; - // Anyone should be able to check if the consumer of the buffer queue is SF. - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true)); -} - TEST_F(CredentialsTest, GetLayerDebugInfo) { setupBackgroundSurface(); sp sf(ComposerService::getComposerService()); diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 53d230abe7..7581cd3af4 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -135,53 +135,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQue } } -TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setPosition is applied immediately by default, with or without resize - // pending - Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply(); - { - SCOPED_TRACE("resize pending"); - auto shot = getScreenCapture(); - const Rect rect(5, 10, 37, 42); - shot->expectColor(rect, Color::RED); - shot->expectBorder(rect, Color::BLACK); - } - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); - { - SCOPED_TRACE("resize applied"); - getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED); - } -} - -TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - Transaction().setSize(layer, 64, 64).apply(); - { - SCOPED_TRACE("resize pending"); - auto shot = getScreenCapture(); - const Rect rect(0, 0, 32, 32); - shot->expectColor(rect, Color::RED); - shot->expectBorder(rect, Color::BLACK); - } - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); - { - SCOPED_TRACE("resize applied"); - auto shot = getScreenCapture(); - const Rect rect(0, 0, 64, 64); - shot->expectColor(rect, Color::RED); - shot->expectBorder(rect, Color::BLACK); - } -} - TEST_P(LayerRenderTypeTransactionTest, CreateLayer_BufferState) { uint32_t transformHint = ui::Transform::ROT_INVALID; sp layer; @@ -606,44 +559,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) { priorColor, bufferFill, alpha, finalColor)); } -TEST_P(LayerRenderTypeTransactionTest, - SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) { - bool priorColor = false; - bool bufferFill = true; - float alpha = 1.0f; - Color finalColor = Color::RED; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, - priorColor, bufferFill, alpha, finalColor)); -} - -TEST_P(LayerRenderTypeTransactionTest, - SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) { - bool priorColor = false; - bool bufferFill = false; - float alpha = 1.0f; - Color finalColor = Color::GREEN; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, - priorColor, bufferFill, alpha, finalColor)); -} - -TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) { - bool priorColor = true; - bool bufferFill = true; - float alpha = 1.0f; - Color finalColor = Color::RED; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, - priorColor, bufferFill, alpha, finalColor)); -} - -TEST_P(LayerRenderTypeTransactionTest, - SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) { - bool priorColor = true; - bool bufferFill = false; - float alpha = 1.0f; - Color finalColor = Color::GREEN; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, - priorColor, bufferFill, alpha, finalColor)); -} TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) { bool priorColor = false; @@ -901,29 +816,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) { shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE); } -TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setMatrix is applied after any pending resize, unlike setPosition - Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply(); - { - SCOPED_TRACE("resize pending"); - auto shot = getScreenCapture(); - const Rect rect(0, 0, 32, 32); - shot->expectColor(rect, Color::RED); - shot->expectBorder(rect, Color::BLACK); - } - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); - { - SCOPED_TRACE("resize applied"); - const Rect rect(0, 0, 128, 128); - getScreenCapture()->expectColor(rect, Color::RED); - } -} - TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); @@ -1076,29 +968,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) { shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK); } -TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setCrop is applied immediately by default, with or without resize pending - Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply(); - { - SCOPED_TRACE("resize pending"); - auto shot = getScreenCapture(); - shot->expectColor(Rect(8, 8, 24, 24), Color::RED); - shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK); - } - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16)); - { - SCOPED_TRACE("resize applied"); - auto shot = getScreenCapture(); - shot->expectColor(Rect(8, 8, 16, 16), Color::RED); - shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK); - } -} - TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) { sp layer; ASSERT_NO_FATAL_FAILURE( diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index edf55ea6ef..2828d61a76 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -51,14 +51,9 @@ INSTANTIATE_TEST_CASE_P( LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest, ::testing::Combine( ::testing::Values( - static_cast(ISurfaceComposerClient::eFXSurfaceBufferQueue), static_cast(ISurfaceComposerClient::eFXSurfaceBufferState)), ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT))); -TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) { - // cannot test robustness against invalid sizes (zero or really huge) -} - TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) { sp layerR; sp layerG; @@ -324,7 +319,6 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { .setLayer(blurLayer, mLayerZBase + 3) .setBackgroundBlurRadius(blurLayer, blurRadius) .setCrop(blurLayer, blurRect) - .setSize(blurLayer, blurRect.getWidth(), blurRect.getHeight()) .setAlpha(blurLayer, 0.0f) .apply(); diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index adb5d58e8c..ee4d367f3d 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -127,15 +127,7 @@ protected: TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); waitForPostedBuffers(); } - void restoreInitialState() { - asTransaction([&](Transaction& t) { - t.setSize(mFGSurfaceControl, 64, 64); - t.setPosition(mFGSurfaceControl, 64, 64); - t.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64)); - }); - EXPECT_INITIAL_STATE("After restoring initial state"); - } std::unique_ptr sc; }; @@ -462,191 +454,6 @@ TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) { } } -TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 0, 0); - t.setPosition(mFGSurfaceControl, 0, 0); - }); - - { - mCapture = screenshot(); - // We've positioned the child in the top left. - mCapture->expectChildColor(0, 0); - // But it's only 10x15. - mCapture->expectFGColor(10, 15); - } - - asTransaction([&](Transaction& t) { - mFGSurfaceControl->getSurface()->setScalingMode( - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - // Resubmit buffer with new scaling mode - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - // We cause scaling by 2. - t.setSize(mFGSurfaceControl, 128, 128); - }); - - { - mCapture = screenshot(); - // We've positioned the child in the top left. - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(10, 10); - mCapture->expectChildColor(19, 29); - // And now it should be scaled all the way to 20x30 - mCapture->expectFGColor(20, 30); - } -} - -// Regression test for b/37673612 -TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 0, 0); - t.setPosition(mFGSurfaceControl, 0, 0); - }); - - { - mCapture = screenshot(); - // We've positioned the child in the top left. - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(9, 14); - // But it's only 10x15. - mCapture->expectFGColor(10, 15); - } - // We set things up as in b/37673612 so that there is a mismatch between the buffer size and - // the WM specified state size. - asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); }); - sp s = mFGSurfaceControl->getSurface(); - auto anw = static_cast(s.get()); - native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); - native_window_set_buffers_dimensions(anw, 64, 128); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - waitForPostedBuffers(); - - { - // The child should still be in the same place and not have any strange scaling as in - // b/37673612. - mCapture = screenshot(); - mCapture->expectChildColor(0, 0); - mCapture->expectFGColor(10, 10); - } -} - -// A child with a buffer transform from its parents should be cropped by its parent bounds. -TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 0, 0); - t.setPosition(mFGSurfaceControl, 0, 0); - t.setSize(mChild, 100, 100); - }); - TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200); - - { - mCapture = screenshot(); - - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(63, 63); - mCapture->expectBGColor(64, 64); - } - - asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); }); - sp s = mFGSurfaceControl->getSurface(); - auto anw = static_cast(s.get()); - // Apply a 90 transform on the buffer. - native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); - native_window_set_buffers_dimensions(anw, 64, 128); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - waitForPostedBuffers(); - - // The child should be cropped by the new parent bounds. - { - mCapture = screenshot(); - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(99, 63); - mCapture->expectFGColor(100, 63); - mCapture->expectBGColor(128, 64); - } -} - -// A child with a scale transform from its parents should be cropped by its parent bounds. -TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 0, 0); - t.setPosition(mFGSurfaceControl, 0, 0); - t.setSize(mChild, 200, 200); - }); - TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200); - - { - mCapture = screenshot(); - - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(63, 63); - mCapture->expectBGColor(64, 64); - } - - asTransaction([&](Transaction& t) { - mFGSurfaceControl->getSurface()->setScalingMode( - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - // Resubmit buffer with new scaling mode - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - // Set a scaling by 2. - t.setSize(mFGSurfaceControl, 128, 128); - }); - - // Child should inherit its parents scale but should be cropped by its parent bounds. - { - mCapture = screenshot(); - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(127, 127); - mCapture->expectBGColor(128, 128); - } -} - -// Regression test for b/127368943 -// Child should ignore the buffer transform but apply parent scale transform. -TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 0, 0); - t.setPosition(mFGSurfaceControl, 0, 0); - }); - - { - mCapture = screenshot(); - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(9, 14); - mCapture->expectFGColor(10, 15); - } - - // Change the size of the foreground to 128 * 64 so we can test rotation as well. - asTransaction([&](Transaction& t) { - mFGSurfaceControl->getSurface()->setScalingMode( - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - // Resubmit buffer with new scaling mode - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - t.setSize(mFGSurfaceControl, 128, 64); - }); - sp s = mFGSurfaceControl->getSurface(); - auto anw = static_cast(s.get()); - // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we - // have an effective scale of 2.0 applied to the buffer along with a rotation transform. - native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); - native_window_set_buffers_dimensions(anw, 32, 64); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - waitForPostedBuffers(); - - // The child should ignore the buffer transform but apply the 2.0 scale from parent. - { - mCapture = screenshot(); - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(19, 29); - mCapture->expectFGColor(20, 30); - } -} - TEST_F(ChildLayerTest, Reparent) { asTransaction([&](Transaction& t) { t.show(mChild); diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index b0753c842e..2e9c10ce5c 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -350,7 +350,10 @@ TEST_F(ScreenCaptureTest, CaptureBoundlessLayerWithoutSourceCropFails) { TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) { sp child = createSurface(mClient, "Child surface", 10, 10, - PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + mFGSurfaceControl.get()); + SurfaceComposerClient::Transaction().show(child).apply(true); sp outBuffer; @@ -361,7 +364,7 @@ TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) { ScreenCaptureResults captureResults; ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(args, captureResults)); - TransactionUtils::fillSurfaceRGBA8(child, Color::RED); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::RED, 32, 32)); SurfaceComposerClient::Transaction().apply(true); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(args, captureResults)); ScreenCapture sc(captureResults.buffer); @@ -432,12 +435,15 @@ TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) { } TEST_F(ScreenCaptureTest, CaptureCrop) { - sp redLayer = createLayer(String8("Red surface"), 60, 60, 0); + sp redLayer = createLayer(String8("Red surface"), 60, 60, + ISurfaceComposerClient::eFXSurfaceBufferState); sp blueLayer = createSurface(mClient, "Blue surface", 30, 30, - PIXEL_FORMAT_RGBA_8888, 0, redLayer.get()); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + redLayer.get()); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(blueLayer, Color::BLUE, 30, 30)); SurfaceComposerClient::Transaction() .setLayer(redLayer, INT32_MAX - 1) @@ -464,12 +470,15 @@ TEST_F(ScreenCaptureTest, CaptureCrop) { } TEST_F(ScreenCaptureTest, CaptureSize) { - sp redLayer = createLayer(String8("Red surface"), 60, 60, 0); + sp redLayer = + createLayer(String8("Red surface"), 60, 60, ISurfaceComposerClient::eFXSurfaceBufferState); sp blueLayer = createSurface(mClient, "Blue surface", 30, 30, - PIXEL_FORMAT_RGBA_8888, 0, redLayer.get()); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + redLayer.get()); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(blueLayer, Color::BLUE, 30, 30)); SurfaceComposerClient::Transaction() .setLayer(redLayer, INT32_MAX - 1) @@ -489,6 +498,7 @@ TEST_F(ScreenCaptureTest, CaptureSize) { captureArgs.frameScaleX = 0.5f; captureArgs.frameScaleY = 0.5f; + sleep(1); ScreenCapture::captureLayers(&mCapture, captureArgs); // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area. @@ -519,14 +529,15 @@ TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { } TEST_F(ScreenCaptureTest, CaputureSecureLayer) { - sp redLayer = createLayer(String8("Red surface"), 60, 60, 0); + sp redLayer = createLayer(String8("Red surface"), 60, 60, + ISurfaceComposerClient::eFXSurfaceBufferState); sp secureLayer = createLayer(String8("Secure surface"), 30, 30, ISurfaceComposerClient::eSecure | - ISurfaceComposerClient::eFXSurfaceBufferQueue, + ISurfaceComposerClient::eFXSurfaceBufferState, redLayer.get()); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(secureLayer, Color::BLUE, 30, 30)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(secureLayer, Color::BLUE, 30, 30)); auto redLayerHandle = redLayer->getHandle(); Transaction() @@ -874,4 +885,4 @@ TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" \ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index af23e2a9cc..ee4e863474 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -921,11 +921,6 @@ TEST_F(SurfaceInterceptorTest, InterceptDisplayDeletionWorks) { ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kDisplayDeletion)); } -TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) { - captureTest(&SurfaceInterceptorTest::nBufferUpdates, - &SurfaceInterceptorTest::bufferUpdatesFound); -} - // If the interceptor is enabled while buffer updates are being pushed, the interceptor should // first create a snapshot of the existing displays and surfaces and then start capturing // the buffer updates @@ -941,26 +936,6 @@ TEST_F(SurfaceInterceptorTest, InterceptWhileBufferUpdatesWorks) { const auto& firstIncrement = capturedTrace.mutable_increment(0); ASSERT_EQ(firstIncrement->increment_case(), Increment::IncrementCase::kDisplayCreation); } - -TEST_F(SurfaceInterceptorTest, InterceptSimultaneousUpdatesWorks) { - enableInterceptor(); - setupBackgroundSurface(); - std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this); - std::thread surfaceUpdates(&SurfaceInterceptorTest::runAllUpdates, this); - runInTransaction(&SurfaceInterceptorTest::surfaceCreation); - bufferUpdates.join(); - surfaceUpdates.join(); - disableInterceptor(); - - Trace capturedTrace; - ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace)); - preProcessTrace(capturedTrace); - - assertAllUpdatesFound(capturedTrace); - ASSERT_TRUE(bufferUpdatesFound(capturedTrace)); - ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation)); -} } - // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index eb31e2eca1..162711d6f5 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -1293,31 +1293,6 @@ protected: EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2))); } - void Test_LayerResize() { - ALOGD("TransactionTest::LayerResize"); - { - TransactionScope ts(*sFakeComposer); - ts.setSize(mFGSurfaceControl, 128, 128); - } - - fillSurfaceRGBA8(mFGSurfaceControl, GREEN); - sFakeComposer->runVSyncAndWait(); - - ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and - // there's no extra frames. - - auto frame1Ref = mBaseFrame; - // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size - // posted. - EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1))); - - auto frame2Ref = frame1Ref; - frame2Ref[FG_LAYER].mSwapCount++; - frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128}; - frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f}; - EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2))); - } - void Test_LayerCrop() { // TODO: Add scaling to confirm that crop happens in buffer space? { @@ -1517,10 +1492,6 @@ TEST_F(TransactionTest_2_1, DISABLED_LayerMove) { Test_LayerMove(); } -TEST_F(TransactionTest_2_1, DISABLED_LayerResize) { - Test_LayerResize(); -} - TEST_F(TransactionTest_2_1, DISABLED_LayerCrop) { Test_LayerCrop(); } @@ -1690,39 +1661,6 @@ protected: EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame())); } - // Regression test for b/37673612 - void Test_ChildrenWithParentBufferTransform() { - { - TransactionScope ts(*Base::sFakeComposer); - ts.show(mChild); - ts.setPosition(mChild, 0, 0); - ts.setPosition(Base::mFGSurfaceControl, 0, 0); - } - - // We set things up as in b/37673612 so that there is a mismatch between the buffer size and - // the WM specified state size. - { - TransactionScope ts(*Base::sFakeComposer); - ts.setSize(Base::mFGSurfaceControl, 128, 64); - } - - sp s = Base::mFGSurfaceControl->getSurface(); - auto anw = static_cast(s.get()); - native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); - native_window_set_buffers_dimensions(anw, 64, 128); - fillSurfaceRGBA8(Base::mFGSurfaceControl, RED); - Base::sFakeComposer->runVSyncAndWait(); - - // The child should still be in the same place and not have any strange scaling as in - // b/37673612. - auto referenceFrame = Base::mBaseFrame; - referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64}; - referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f}; - referenceFrame[Base::FG_LAYER].mSwapCount++; - referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; - EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame())); - } - sp mChild; }; @@ -1748,11 +1686,6 @@ TEST_F(ChildLayerTest_2_1, DISABLED_LayerAlpha) { Test_LayerAlpha(); } -// Regression test for b/37673612 -TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) { - Test_ChildrenWithParentBufferTransform(); -} - template class ChildColorLayerTest : public ChildLayerTest { using Base = ChildLayerTest; @@ -1842,91 +1775,6 @@ TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerAlpha) { TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerZeroAlpha) { Test_LayerZeroAlpha(); } - -template -class LatchingTest : public TransactionTest { - using Base = TransactionTest; - -protected: - void lockAndFillFGBuffer() { fillSurfaceRGBA8(Base::mFGSurfaceControl, RED, false); } - - void unlockFGBuffer() { - sp s = Base::mFGSurfaceControl->getSurface(); - ASSERT_EQ(NO_ERROR, s->unlockAndPost()); - Base::sFakeComposer->runVSyncAndWait(); - } - - void completeFGResize() { - fillSurfaceRGBA8(Base::mFGSurfaceControl, RED); - Base::sFakeComposer->runVSyncAndWait(); - } - void restoreInitialState() { - TransactionScope ts(*Base::sFakeComposer); - ts.setSize(Base::mFGSurfaceControl, 64, 64); - ts.setPosition(Base::mFGSurfaceControl, 64, 64); - ts.setCrop(Base::mFGSurfaceControl, Rect(0, 0, 64, 64)); - } - - void Test_SurfacePositionLatching() { - // By default position can be updated even while - // a resize is pending. - { - TransactionScope ts(*Base::sFakeComposer); - ts.setSize(Base::mFGSurfaceControl, 32, 32); - ts.setPosition(Base::mFGSurfaceControl, 100, 100); - } - - // The size should not have updated as we have not provided a new buffer. - auto referenceFrame1 = Base::mBaseFrame; - referenceFrame1[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64}; - EXPECT_TRUE(framesAreSame(referenceFrame1, Base::sFakeComposer->getLatestFrame())); - - restoreInitialState(); - - completeFGResize(); - - auto referenceFrame2 = Base::mBaseFrame; - referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32}; - referenceFrame2[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f}; - referenceFrame2[Base::FG_LAYER].mSwapCount++; - EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame())); - } - - void Test_CropLatching() { - // Normally the crop applies immediately even while a resize is pending. - { - TransactionScope ts(*Base::sFakeComposer); - ts.setSize(Base::mFGSurfaceControl, 128, 128); - ts.setCrop(Base::mFGSurfaceControl, Rect(0, 0, 63, 63)); - } - - auto referenceFrame1 = Base::mBaseFrame; - referenceFrame1[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63}; - referenceFrame1[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f}; - EXPECT_TRUE(framesAreSame(referenceFrame1, Base::sFakeComposer->getLatestFrame())); - - restoreInitialState(); - - completeFGResize(); - - auto referenceFrame2 = Base::mBaseFrame; - referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63}; - referenceFrame2[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f}; - referenceFrame2[Base::FG_LAYER].mSwapCount++; - EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame())); - } -}; - -using LatchingTest_2_1 = LatchingTest; - -TEST_F(LatchingTest_2_1, DISABLED_SurfacePositionLatching) { - Test_SurfacePositionLatching(); -} - -TEST_F(LatchingTest_2_1, DISABLED_CropLatching) { - Test_CropLatching(); -} - } // namespace int main(int argc, char** argv) { -- cgit v1.2.3-59-g8ed1b From 33100284a8b13743cb617cd5e05ea8d8cdc78482 Mon Sep 17 00:00:00 2001 From: Hongguang Chen Date: Thu, 15 Apr 2021 18:36:05 -0700 Subject: BlastBufferQueue: Update layer size before processing it. We may fail to update mSize if the scaling mode changes from freeze to not-freeze right after the requested size changes. Bug: 178622186 Test: manual and winscope dump Change-Id: Iab4b643c5aee803450d138acc21a8d5da51dbe6a --- libs/gui/BLASTBufferQueue.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index e5afd408a9..476617db48 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -498,6 +498,7 @@ void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { + mSize = mRequestedSize; // Only reject buffers if scaling mode is freeze. return false; } -- cgit v1.2.3-59-g8ed1b From 42026164d1f75b92ee208fc8f772786c737d6b21 Mon Sep 17 00:00:00 2001 From: chaviw Date: Fri, 16 Apr 2021 15:46:12 -0500 Subject: Check SurfaceControl in stats sent to transactionCallback The stats sent to the transactionCallback can contain stats about multiple SurfaceControls. This is because the callback is created for a single transaction, not a single SurfaceControl. Instead, check the stats for the matching SurfaceControl in BBQ. Fixes: 185510248 Test: Rotate device with new shell transition. Doesn't timeout Change-Id: I9d759de3b8b8b5c089c707904f69ebaed56513b6 --- libs/gui/BLASTBufferQueue.cpp | 63 ++++++++++++++++++++++----------- libs/gui/include/gui/BLASTBufferQueue.h | 4 +++ 2 files changed, 46 insertions(+), 21 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 476617db48..571da690a7 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -242,29 +242,49 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const spsetTransformHint(mTransformHint); - mBufferItemConsumer - ->updateFrameTimestamps(stats[0].frameEventStats.frameNumber, - stats[0].frameEventStats.refreshStartTime, - stats[0].frameEventStats.gpuCompositionDoneFence, - stats[0].presentFence, stats[0].previousReleaseFence, - stats[0].frameEventStats.compositorTiming, - stats[0].latchTime, - stats[0].frameEventStats.dequeueReadyTime); - currFrameNumber = stats[0].frameEventStats.frameNumber; - - if (mTransactionCompleteCallback && - currFrameNumber >= mTransactionCompleteFrameNumber) { - if (currFrameNumber > mTransactionCompleteFrameNumber) { - BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64 - " than expected=%" PRIu64, - currFrameNumber, mTransactionCompleteFrameNumber); + if (!mSurfaceControlsWithPendingCallback.empty()) { + sp pendingSC = mSurfaceControlsWithPendingCallback.front(); + mSurfaceControlsWithPendingCallback.pop(); + bool found = false; + for (auto stat : stats) { + if (!SurfaceControl::isSameSurface(pendingSC, stat.surfaceControl)) { + continue; } - transactionCompleteCallback = std::move(mTransactionCompleteCallback); - mTransactionCompleteFrameNumber = 0; + + mTransformHint = stat.transformHint; + mBufferItemConsumer->setTransformHint(mTransformHint); + mBufferItemConsumer + ->updateFrameTimestamps(stat.frameEventStats.frameNumber, + stat.frameEventStats.refreshStartTime, + stat.frameEventStats.gpuCompositionDoneFence, + stat.presentFence, stat.previousReleaseFence, + stat.frameEventStats.compositorTiming, + stat.latchTime, + stat.frameEventStats.dequeueReadyTime); + + currFrameNumber = stat.frameEventStats.frameNumber; + + if (mTransactionCompleteCallback && + currFrameNumber >= mTransactionCompleteFrameNumber) { + if (currFrameNumber > mTransactionCompleteFrameNumber) { + BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64 + " than expected=%" PRIu64, + currFrameNumber, mTransactionCompleteFrameNumber); + } + transactionCompleteCallback = std::move(mTransactionCompleteCallback); + mTransactionCompleteFrameNumber = 0; + } + + found = true; + break; + } + + if (!found) { + BQA_LOGE("Failed to find matching SurfaceControl in transaction callback"); } + } else { + BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was " + "empty."); } decStrong((void*)transactionCallbackThunk); @@ -392,6 +412,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setAcquireFence(mSurfaceControl, bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); + mSurfaceControlsWithPendingCallback.push(mSurfaceControl); setMatrix(t, mLastBufferInfo); t->setCrop(mSurfaceControl, computeCrop(bufferItem)); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index a48f95ae73..8a23223660 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -203,6 +203,10 @@ private: // it for debugging purposes. std::unordered_map mDequeueTimestamps GUARDED_BY(mTimestampMutex); + + // Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a + // callback for them. + std::queue> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex); }; } // namespace android -- cgit v1.2.3-59-g8ed1b From 5cc9ac0ab36848468100353fc31a42cf0753b9e4 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 19 Apr 2021 13:23:38 -0700 Subject: Fix crop scaling with BSL With BQL, each layer had a concept of buffer space and layer space. The caller could set a buffer crop and a layer crop. The buffer crop would be applied in buffer space and the content would be scaled to the buffer size. Then the scaled content would then be scaled again to the layer size (also referred to as the window size). With BSL we do not have a concept of buffer space and layer space. So we should not set a buffer/content crop otherwise this might result in incorrect scaling or cropping. To fix this, in BBQ, when calculating the scale, use the buffer crop provided by the client and in SurfaceFlinger, instead of setting a buffer crop only set the layer crop. The buffer crop/content crop can be cleaned up once BQL is removed. Test: BLASTBufferQueueTest (cropped buffer scales to buffer and window size) Test: 720p content in android tv is not cropped incorrectly Bug: 178622186 Change-Id: I173df901120a43f397f6d623a7e7b93537a508e2 --- libs/gui/BLASTBufferQueue.cpp | 18 ++-- libs/gui/include/gui/BLASTBufferQueue.h | 8 +- libs/gui/tests/BLASTBufferQueue_test.cpp | 146 +++++++++++++++++++++++++-- services/surfaceflinger/BufferStateLayer.cpp | 24 +---- services/surfaceflinger/BufferStateLayer.h | 2 +- 5 files changed, 161 insertions(+), 37 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index e3b59b2584..65c893af99 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -186,6 +186,7 @@ BLASTBufferQueue::~BLASTBufferQueue() { void BLASTBufferQueue::update(const sp& surface, uint32_t width, uint32_t height, int32_t format) { std::unique_lock _lock{mMutex}; + BQA_LOGV("update width=%d height=%d format=%d", width, height, format); if (mFormat != format) { mFormat = format; mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format)); @@ -377,10 +378,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); + Rect crop = computeCrop(bufferItem); mLastAcquiredFrameNumber = bufferItem.mFrameNumber; mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(), bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, - bufferItem.mScalingMode); + bufferItem.mScalingMode, crop); auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp(this) /* callbackContext */, @@ -394,7 +396,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); setMatrix(t, mLastBufferInfo); - t->setCrop(mSurfaceControl, computeCrop(bufferItem)); + t->setCrop(mSurfaceControl, crop); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); if (!bufferItem.mIsAutoTimestamp) { @@ -522,13 +524,15 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { void BLASTBufferQueue::setMatrix(SurfaceComposerClient::Transaction* t, const BufferInfo& bufferInfo) { - uint32_t bufWidth = bufferInfo.width; - uint32_t bufHeight = bufferInfo.height; + uint32_t bufWidth = bufferInfo.crop.getWidth(); + uint32_t bufHeight = bufferInfo.crop.getHeight(); - float dsdx = mSize.width / static_cast(bufWidth); - float dsdy = mSize.height / static_cast(bufHeight); + float sx = mSize.width / static_cast(bufWidth); + float sy = mSize.height / static_cast(bufHeight); - t->setMatrix(mSurfaceControl, dsdx, 0, 0, dsdy); + t->setMatrix(mSurfaceControl, sx, 0, 0, sy); + // Update position based on crop. + t->setPosition(mSurfaceControl, bufferInfo.crop.left * sx * -1, bufferInfo.crop.top * sy * -1); } void BLASTBufferQueue::setTransactionCompleteCallback( diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index a48f95ae73..bfdfd63f16 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -151,14 +151,20 @@ private: // we get the next buffer. This will support scenarios where the layer can change sizes // and the buffer will scale to fit the new size. uint32_t scalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; + Rect crop; void update(bool hasBuffer, uint32_t width, uint32_t height, uint32_t transform, - uint32_t scalingMode) { + uint32_t scalingMode, const Rect& crop) { this->hasBuffer = hasBuffer; this->width = width; this->height = height; this->transform = transform; this->scalingMode = scalingMode; + if (!crop.isEmpty()) { + this->crop = crop; + } else { + this->crop = Rect(width, height); + } } }; diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index a44f44fbe6..5a5da97599 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -522,16 +522,146 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { adapter.waitForCallbacks(); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, + {10, 10, (int32_t)bufferSideLength - 10, + (int32_t)bufferSideLength - 10})); + ASSERT_NO_FATAL_FAILURE( + checkScreenCapture(0, 0, 0, + {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength}, + /*border*/ 0, /*outsideRegion*/ true)); +} - Rect bounds; - bounds.left = finalCropSideLength / 2; - bounds.top = 0; - bounds.right = bounds.left + finalCropSideLength; - bounds.bottom = finalCropSideLength; +TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { + // add black background + auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect); + ASSERT_NE(nullptr, bg.get()); + Transaction t; + t.setLayerStack(bg, 0) + .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) + .setColor(bg, half3{0, 0, 0}) + .setLayer(bg, 0) + .apply(); - ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, bounds)); - ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(0, 0, 0, bounds, /*border*/ 0, /*outsideRegion*/ true)); + Rect windowSize(1000, 1000); + Rect bufferSize(windowSize); + Rect bufferCrop(200, 200, 700, 700); + + BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight()); + sp igbProducer; + setUpProducer(adapter, igbProducer); + int slot; + sp fence; + sp buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, bufferSize.getWidth(), + bufferSize.getHeight(), PIXEL_FORMAT_RGBA_8888, + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + uint32_t* bufData; + buf->lock(static_cast(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast(&bufData)); + // fill buffer with grey + fillBuffer(bufData, bufferSize, buf->getStride(), 127, 127, 127); + + // fill crop area with different colors so we can verify the cropped region has been scaled + // correctly. + fillBuffer(bufData, Rect(200, 200, 450, 450), buf->getStride(), /* rgb */ 255, 0, 0); + fillBuffer(bufData, Rect(200, 451, 450, 700), buf->getStride(), /* rgb */ 0, 255, 0); + fillBuffer(bufData, Rect(451, 200, 700, 450), buf->getStride(), /* rgb */ 0, 0, 255); + fillBuffer(bufData, Rect(451, 451, 700, 700), buf->getStride(), /* rgb */ 255, 0, 0); + buf->unlock(); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, + bufferCrop /* Rect::INVALID_RECT */, + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + + adapter.waitForCallbacks(); + + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + + // Verify cropped region is scaled correctly. + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, {10, 510, 490, 990})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 255, {510, 10, 990, 490})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {510, 510, 990, 990})); + // Verify outside region is black. + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 0, + {0, 0, (int32_t)windowSize.getWidth(), + (int32_t)windowSize.getHeight()}, + /*border*/ 0, /*outsideRegion*/ true)); +} + +TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { + // add black background + auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect); + ASSERT_NE(nullptr, bg.get()); + Transaction t; + t.setLayerStack(bg, 0) + .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) + .setColor(bg, half3{0, 0, 0}) + .setLayer(bg, 0) + .apply(); + + Rect windowSize(1000, 1000); + Rect bufferSize(500, 500); + Rect bufferCrop(100, 100, 350, 350); + + BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight()); + sp igbProducer; + setUpProducer(adapter, igbProducer); + int slot; + sp fence; + sp buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, bufferSize.getWidth(), + bufferSize.getHeight(), PIXEL_FORMAT_RGBA_8888, + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + uint32_t* bufData; + buf->lock(static_cast(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast(&bufData)); + // fill buffer with grey + fillBuffer(bufData, bufferSize, buf->getStride(), 127, 127, 127); + + // fill crop area with different colors so we can verify the cropped region has been scaled + // correctly. + fillBuffer(bufData, Rect(100, 100, 225, 225), buf->getStride(), /* rgb */ 255, 0, 0); + fillBuffer(bufData, Rect(100, 226, 225, 350), buf->getStride(), /* rgb */ 0, 255, 0); + fillBuffer(bufData, Rect(226, 100, 350, 225), buf->getStride(), /* rgb */ 0, 0, 255); + fillBuffer(bufData, Rect(226, 226, 350, 350), buf->getStride(), /* rgb */ 255, 0, 0); + buf->unlock(); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, + bufferCrop /* Rect::INVALID_RECT */, + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + + adapter.waitForCallbacks(); + + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + // Verify cropped region is scaled correctly. + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, {10, 510, 490, 990})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 255, {510, 10, 990, 490})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {510, 510, 990, 990})); + // Verify outside region is black. + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 0, + {0, 0, (int32_t)windowSize.getWidth(), + (int32_t)windowSize.getHeight()}, + /*border*/ 0, /*outsideRegion*/ true)); } class TestProducerListener : public BnProducerListener { diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index ac2edbe717..a2915c903f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -790,7 +790,7 @@ void BufferStateLayer::gatherBufferInfo() { mBufferInfo.mFence = s.acquireFence; mBufferInfo.mTransform = s.bufferTransform; mBufferInfo.mDataspace = translateDataspace(s.dataspace); - mBufferInfo.mCrop = computeCrop(s); + mBufferInfo.mCrop = computeBufferCrop(s); mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion; mBufferInfo.mHdrMetadata = s.hdrMetadata; @@ -803,27 +803,11 @@ uint32_t BufferStateLayer::getEffectiveScalingMode() const { return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; } -Rect BufferStateLayer::computeCrop(const State& s) { - if (s.crop.isEmpty() && s.buffer) { +Rect BufferStateLayer::computeBufferCrop(const State& s) { + if (s.buffer) { return s.buffer->getBuffer()->getBounds(); - } else if (s.buffer) { - Rect crop = s.crop; - crop.left = std::max(crop.left, 0); - crop.top = std::max(crop.top, 0); - uint32_t bufferWidth = s.buffer->getBuffer()->getWidth(); - uint32_t bufferHeight = s.buffer->getBuffer()->getHeight(); - if (bufferHeight <= std::numeric_limits::max() && - bufferWidth <= std::numeric_limits::max()) { - crop.right = std::min(crop.right, static_cast(bufferWidth)); - crop.bottom = std::min(crop.bottom, static_cast(bufferHeight)); - } - if (!crop.isValid()) { - // Crop rect is out of bounds, return whole buffer - return s.buffer->getBuffer()->getBounds(); - } - return crop; } - return s.crop; + return Rect::INVALID_RECT; } sp BufferStateLayer::createClone() { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 4171092b58..af4fcae7ba 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -140,7 +140,7 @@ private: sp createClone() override; // Crop that applies to the buffer - Rect computeCrop(const State& s); + Rect computeBufferCrop(const State& s); bool willPresentCurrentTransaction() const; -- cgit v1.2.3-59-g8ed1b From 567533eca188e287f82d99956c5d6a134b9cf8c7 Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Tue, 4 May 2021 19:31:29 -0700 Subject: BLASTBufferQueue: fix AsyncWorker race condition Address the following scenario: [T1] AsyncProducerListener::onBufferReleased() is called for the first time. [T2] AsyncWorker::mThread is just created and not acquired the mutex yet. [T1] AsyncProducerListener::post() is called and acquired the mutex. [T1] The runnable is queued to mRunnable and mCv is notified. There are no threads waiting for mCv, so this is ignored. [T2] AsyncWorker::mThread acquires the mutex, and wait on mCv. If the client is waiting for the first onBufferReleased callback, it will be stuck indefinitely. Bug: 186630119 Test: atest --iterations 100 android.media.cts.MediaSyncTest Change-Id: I65d98d64233fa8d488788319a4850be4cace48cc --- libs/gui/BLASTBufferQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 3d854c2b92..37fb8448ee 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -666,12 +666,12 @@ private: void run() { std::unique_lock lock(mMutex); while (!mDone) { - mCv.wait(lock); while (!mRunnables.empty()) { std::function runnable = mRunnables.front(); mRunnables.pop_front(); runnable(); } + mCv.wait(lock); } } -- cgit v1.2.3-59-g8ed1b From 82d07c9e4561ec7adc9340207d25b59b7926c3c9 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 10 May 2021 11:36:43 -0700 Subject: BBQSurface: Give client a chance to observe transform hint earlier The client may be observing the transform hint through the Surface.cpp codepath however Surface#mTransformHint will only be updated on queueBuffer. However imagine a scenario like this: 1. transform hint changes on server 2. queue buffer 2. repeat queue buffer 3. callback for queue buffer 1 and 2, updates transform hint on client 4. queue buffer 4 5. Client now observes transform hint 6. Queue buffer 5(!) will finally contain the transform hint. With this change we give the client a chance to observe the tranform hint in this scenario before queue buffer 4. In the case of the ScreenDecorOverlay's which rarely redraw, this seems to fix some persistent pre-rotation issues. Bug: 184842607 Test: Existing tests pass. Change-Id: I34524ee40c6076f497bb0c60af901e9c93798a48 --- libs/gui/BLASTBufferQueue.cpp | 21 +++++++++++++++++++++ libs/gui/Surface.cpp | 4 ++-- libs/gui/include/gui/BLASTBufferQueue.h | 2 ++ libs/gui/include/gui/Surface.h | 3 ++- 4 files changed, 27 insertions(+), 3 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 3d854c2b92..a023067887 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -316,6 +316,11 @@ void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, std::unique_lock _lock{mMutex}; BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId); + if (mSurfaceControl != nullptr) { + mTransformHint = mSurfaceControl->getTransformHint(); + mBufferItemConsumer->setTransformHint(mTransformHint); + } + auto it = mSubmitted.find(graphicBufferId); if (it == mSubmitted.end()) { BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64, @@ -608,6 +613,14 @@ public: status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override { return mBbq->setFrameTimelineInfo(frameTimelineInfo); } + protected: + uint32_t getTransformHint() const override { + if (mStickyTransform == 0 && !transformToDisplayInverse()) { + return mBbq->getLastTransformHint(); + } else { + return 0; + } + } }; // TODO: Can we coalesce this with frame updates? Need to confirm @@ -777,4 +790,12 @@ PixelFormat BLASTBufferQueue::convertBufferFormat(PixelFormat& format) { return convertedFormat; } +uint32_t BLASTBufferQueue::getLastTransformHint() const { + if (mSurfaceControl != nullptr) { + return mSurfaceControl->getTransformHint(); + } else { + return 0; + } +} + } // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 2fc9d47b89..83aaf36a8d 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1288,7 +1288,7 @@ int Surface::query(int what, int* value) const { mUserHeight ? mUserHeight : mDefaultHeight); return NO_ERROR; case NATIVE_WINDOW_TRANSFORM_HINT: - *value = static_cast(mTransformHint); + *value = static_cast(getTransformHint()); return NO_ERROR; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { status_t err = NO_ERROR; @@ -1822,7 +1822,7 @@ int Surface::dispatchGetExtraBufferCount(va_list args) { return getExtraBufferCount(extraBuffers); } -bool Surface::transformToDisplayInverse() { +bool Surface::transformToDisplayInverse() const { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 139dbb7f6b..c4ca399e37 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -103,6 +103,8 @@ public: void setSidebandStream(const sp& stream); + uint32_t getLastTransformHint() const; + virtual ~BLASTBufferQueue(); private: diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index d22bdaaa98..89e1909a45 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -278,7 +278,6 @@ private: int dispatchGetLastQueuedBuffer(va_list args); int dispatchSetFrameTimelineInfo(va_list args); int dispatchGetExtraBufferCount(va_list args); - bool transformToDisplayInverse(); protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); @@ -490,6 +489,8 @@ protected: // mTransformHint is the transform probably applied to buffers of this // window. this is only a hint, actual transform may differ. uint32_t mTransformHint; + virtual uint32_t getTransformHint() const { return mTransformHint; } + bool transformToDisplayInverse() const; // mProducerControlledByApp whether this buffer producer is controlled // by the application -- cgit v1.2.3-59-g8ed1b From 6bdec7d9c62ed47f9fd0e0cb9e59f0cbe48b4bae Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 10 May 2021 15:01:13 -0700 Subject: Remove rotation based scaling In order to simplify some of the geometry logic in BufferStateLayer, and unify with the rest of the layer in SurfaceFlinger we translate the concept of source and dest frame into crop, scale and position. This is currently done on the client side. But if there is buffer rotation transform, we will generate an additional scale, to scale the buffer size to the new orientation. This causes issues with rounded corners because the additional scale stretches the rounded corner incorrectly. And translating the buffer rotation into a rotation matrix affects child layers. This solution only adjusts the buffer size based on the rotation matrix and the scale is generated based on the rotated buffer. This cannot be done in the client side because we do not have the current display orientation to unflip the buffer if the client sets the transformToDisplayInverse flag. In the future the plan is to drive the transform hint and the display orientation down from WM so this calculation can go back to the client. Test: atest SurfaceControlTest ASurfaceControlTest libgui_test SurfaceFlinger_test Test: go/wm-smoke Bug: 185597146, 186191378 Change-Id: Ia566f952f5efe765382434dbc460b4815165f4f5 --- libs/gui/BLASTBufferQueue.cpp | 20 +---- libs/gui/LayerState.cpp | 8 ++ libs/gui/SurfaceComposerClient.cpp | 15 ++++ libs/gui/include/gui/LayerState.h | 3 +- libs/gui/include/gui/SurfaceComposerClient.h | 2 + services/surfaceflinger/BufferStateLayer.cpp | 106 +++++++++++++++++++++------ services/surfaceflinger/BufferStateLayer.h | 6 ++ services/surfaceflinger/Layer.cpp | 63 ++-------------- services/surfaceflinger/Layer.h | 13 +--- services/surfaceflinger/SurfaceFlinger.cpp | 32 ++++---- 10 files changed, 147 insertions(+), 121 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 37fb8448ee..08800f7a85 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -213,7 +213,8 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, // for this is the scale is calculated based on the requested size and buffer size. // If there's no buffer, the scale will always be 1. if (mLastBufferInfo.hasBuffer) { - setMatrix(&t, mLastBufferInfo); + t.setDestinationFrame(mSurfaceControl, + Rect(0, 0, newSize.getWidth(), newSize.getHeight())); } applyTransaction = true; } @@ -416,8 +417,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); mSurfaceControlsWithPendingCallback.push(mSurfaceControl); - setMatrix(t, mLastBufferInfo); - t->setCrop(mSurfaceControl, crop); + t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight())); + t->setBufferCrop(mSurfaceControl, crop); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); if (!bufferItem.mIsAutoTimestamp) { @@ -543,19 +544,6 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { return mSize != bufferSize; } -void BLASTBufferQueue::setMatrix(SurfaceComposerClient::Transaction* t, - const BufferInfo& bufferInfo) { - uint32_t bufWidth = bufferInfo.crop.getWidth(); - uint32_t bufHeight = bufferInfo.crop.getHeight(); - - float sx = mSize.width / static_cast(bufWidth); - float sy = mSize.height / static_cast(bufHeight); - - t->setMatrix(mSurfaceControl, sx, 0, 0, sy); - // Update position based on crop. - t->setPosition(mSurfaceControl, bufferInfo.crop.left * sx * -1, bufferInfo.crop.top * sy * -1); -} - void BLASTBufferQueue::setTransactionCompleteCallback( uint64_t frameNumber, std::function&& transactionCompleteCallback) { std::lock_guard _lock{mMutex}; diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 267db7686a..e65c721ae1 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -64,6 +64,8 @@ layer_state_t::layer_state_t() fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0), autoRefresh(false), + bufferCrop(Rect::INVALID_RECT), + destinationFrame(Rect::INVALID_RECT), releaseBufferListener(nullptr) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; @@ -167,6 +169,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.write, stretchEffect); SAFE_PARCEL(output.write, bufferCrop); + SAFE_PARCEL(output.write, destinationFrame); return NO_ERROR; } @@ -296,6 +299,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.read, stretchEffect); SAFE_PARCEL(input.read, bufferCrop); + SAFE_PARCEL(input.read, destinationFrame); return NO_ERROR; } @@ -543,6 +547,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eBufferCropChanged; bufferCrop = other.bufferCrop; } + if (other.what & eDestinationFrameChanged) { + what |= eDestinationFrameChanged; + destinationFrame = other.destinationFrame; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIu64 " what=0x%" PRIu64, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 11b8ebac81..aa938087e8 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1675,6 +1675,21 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDestinationFrame( + const sp& sc, const Rect& destinationFrame) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eDestinationFrameChanged; + s->destinationFrame = destinationFrame; + + registerSurfaceControlForCallback(sc); + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 3947f22462..16430b324d 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -104,7 +104,7 @@ struct layer_state_t { eHasListenerCallbacksChanged = 0x20000000, eInputInfoChanged = 0x40000000, eCornerRadiusChanged = 0x80000000, - /* was eFrameChanged, now available 0x1'00000000, */ + eDestinationFrameChanged = 0x1'00000000, eCachedBufferChanged = 0x2'00000000, eBackgroundColorChanged = 0x4'00000000, eMetadataChanged = 0x8'00000000, @@ -228,6 +228,7 @@ struct layer_state_t { StretchEffect stretchEffect; Rect bufferCrop; + Rect destinationFrame; // Listens to when the buffer is safe to be released. This is used for blast // layers only. The callback includes a release fence as well as the graphic diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 35757be988..0940e9d178 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -554,6 +554,8 @@ public: const StretchEffect& stretchEffect); Transaction& setBufferCrop(const sp& sc, const Rect& bufferCrop); + Transaction& setDestinationFrame(const sp& sc, + const Rect& destinationFrame); status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 24b35997b9..fcf8299b72 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -295,12 +295,72 @@ bool BufferStateLayer::setBufferCrop(const Rect& bufferCrop) { return true; } +bool BufferStateLayer::setDestinationFrame(const Rect& destinationFrame) { + if (mCurrentState.destinationFrame == destinationFrame) return false; + + mCurrentState.sequence++; + mCurrentState.destinationFrame = destinationFrame; + + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +// Translate destination frame into scale and position. If a destination frame is not set, use the +// provided scale and position +void BufferStateLayer::updateGeometry() { + if (mCurrentState.destinationFrame.isEmpty()) { + // If destination frame is not set, use the requested transform set via + // BufferStateLayer::setPosition and BufferStateLayer::setMatrix. + mCurrentState.transform = mRequestedTransform; + return; + } + + Rect destRect = mCurrentState.destinationFrame; + int32_t destW = destRect.width(); + int32_t destH = destRect.height(); + if (destRect.left < 0) { + destRect.left = 0; + destRect.right = destW; + } + if (destRect.top < 0) { + destRect.top = 0; + destRect.bottom = destH; + } + + if (!mCurrentState.buffer) { + ui::Transform t; + t.set(destRect.left, destRect.top); + mCurrentState.transform = t; + return; + } + + uint32_t bufferWidth = mCurrentState.buffer->getBuffer()->getWidth(); + uint32_t bufferHeight = mCurrentState.buffer->getBuffer()->getHeight(); + // Undo any transformations on the buffer. + if (mCurrentState.bufferTransform & ui::Transform::ROT_90) { + std::swap(bufferWidth, bufferHeight); + } + uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); + if (mCurrentState.transformToDisplayInverse) { + if (invTransform & ui::Transform::ROT_90) { + std::swap(bufferWidth, bufferHeight); + } + } + + float sx = destW / static_cast(bufferWidth); + float sy = destH / static_cast(bufferHeight); + ui::Transform t; + t.set(sx, 0, 0, sy); + t.set(destRect.left, destRect.top); + mCurrentState.transform = t; + return; +} + bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix, bool allowNonRectPreservingTransforms) { - if (mCurrentState.transform.dsdx() == matrix.dsdx && - mCurrentState.transform.dtdy() == matrix.dtdy && - mCurrentState.transform.dtdx() == matrix.dtdx && - mCurrentState.transform.dsdy() == matrix.dsdy) { + if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy && + mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) { return false; } @@ -313,7 +373,7 @@ bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix, return false; } - mCurrentState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); + mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); mCurrentState.sequence++; mCurrentState.modified = true; @@ -323,11 +383,11 @@ bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix, } bool BufferStateLayer::setPosition(float x, float y) { - if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) { + if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) { return false; } - mCurrentState.transform.set(x, y); + mRequestedTransform.set(x, y); mCurrentState.sequence++; mCurrentState.modified = true; @@ -523,35 +583,35 @@ bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) { Rect BufferStateLayer::getBufferSize(const State& s) const { // for buffer state layers we use the display frame size as the buffer size. - if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) { - return Rect(getActiveWidth(s), getActiveHeight(s)); - } if (mBufferInfo.mBuffer == nullptr) { return Rect::INVALID_RECT; } - // if the display frame is not defined, use the parent bounds as the buffer size. - const auto& p = mDrawingParent.promote(); - if (p != nullptr) { - Rect parentBounds = Rect(p->getBounds(Region())); - if (!parentBounds.isEmpty()) { - return parentBounds; + uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); + + // Undo any transformations on the buffer and return the result. + if (mBufferInfo.mTransform & ui::Transform::ROT_90) { + std::swap(bufWidth, bufHeight); + } + + if (getTransformToDisplayInverse()) { + uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); + if (invTransform & ui::Transform::ROT_90) { + std::swap(bufWidth, bufHeight); } } - return Rect::INVALID_RECT; + return Rect(0, 0, bufWidth, bufHeight); } FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) const { - const State& s(getDrawingState()); - // for buffer state layers we use the display frame size as the buffer size. - if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) { - return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s)); + if (mBufferInfo.mBuffer == nullptr) { + return parentBounds; } - // if the display frame is not defined, use the parent bounds as the buffer size. - return parentBounds; + return getBufferSize(getDrawingState()).toFloatRect(); } // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index a273230cc8..2e484524a1 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -86,6 +86,8 @@ public: void setAutoRefresh(bool autoRefresh) override; bool setBufferCrop(const Rect& bufferCrop) override; + bool setDestinationFrame(const Rect& destinationFrame) override; + void updateGeometry() override; // ----------------------------------------------------------------------- @@ -178,6 +180,10 @@ private: // - If the integer decreases in setBuffer or doTransaction, a buffer was dropped std::atomic mPendingBufferTransactions{0}; + // Contains requested position and matrix updates. This will be applied if the client does + // not specify a destination frame. + ui::Transform mRequestedTransform; + // TODO(marissaw): support sticky transform for LEGACY camera mode class HwcSlotGenerator : public ClientCache::ErasedRecipient { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 21c9d74409..def271196d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -133,6 +133,7 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID; mCurrentState.frameTimelineInfo = {}; mCurrentState.postTime = -1; + mCurrentState.destinationFrame.makeInvalid(); if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. @@ -315,55 +316,6 @@ FloatRect Layer::getBounds(const Region& activeTransparentRegion) const { return reduce(mBounds, activeTransparentRegion); } -ui::Transform Layer::getBufferScaleTransform() const { - // If the layer is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g. - // it isFixedSize) then there may be additional scaling not accounted - // for in the layer transform. - if (!isFixedSize() || getBuffer() == nullptr) { - return {}; - } - - // If the layer is a buffer state layer, the active width and height - // could be infinite. In that case, return the effective transform. - const uint32_t activeWidth = getActiveWidth(getDrawingState()); - const uint32_t activeHeight = getActiveHeight(getDrawingState()); - if (activeWidth >= UINT32_MAX && activeHeight >= UINT32_MAX) { - return {}; - } - - int bufferWidth = getBuffer()->getWidth(); - int bufferHeight = getBuffer()->getHeight(); - - if (getBufferTransform() & NATIVE_WINDOW_TRANSFORM_ROT_90) { - std::swap(bufferWidth, bufferHeight); - } - - float sx = activeWidth / static_cast(bufferWidth); - float sy = activeHeight / static_cast(bufferHeight); - - ui::Transform extraParentScaling; - extraParentScaling.set(sx, 0, 0, sy); - return extraParentScaling; -} - -ui::Transform Layer::getTransformWithScale(const ui::Transform& bufferScaleTransform) const { - // We need to mirror this scaling to child surfaces or we will break the contract where WM can - // treat child surfaces as pixels in the parent surface. - if (!isFixedSize() || getBuffer() == nullptr) { - return mEffectiveTransform; - } - return mEffectiveTransform * bufferScaleTransform; -} - -FloatRect Layer::getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const { - // We need the pre scaled layer bounds when computing child bounds to make sure the child is - // cropped to its parent layer after any buffer transform scaling is applied. - if (!isFixedSize() || getBuffer() == nullptr) { - return mBounds; - } - return bufferScaleTransform.inverse().transform(mBounds); -} - void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform, float parentShadowRadius) { const State& s(getDrawingState()); @@ -400,11 +352,8 @@ void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform, // don't pass it to its children. const float childShadowRadius = canDrawShadows() ? 0.f : mEffectiveShadowRadius; - // Add any buffer scaling to the layer's children. - ui::Transform bufferScaleTransform = getBufferScaleTransform(); for (const sp& child : mDrawingChildren) { - child->computeBounds(getBoundsPreScaling(bufferScaleTransform), - getTransformWithScale(bufferScaleTransform), childShadowRadius); + child->computeBounds(mBounds, mEffectiveTransform, childShadowRadius); } } @@ -858,6 +807,11 @@ uint32_t Layer::doTransaction(uint32_t flags) { const State& s(getDrawingState()); State& c(getCurrentState()); + // Translates dest frame into scale and position updates. This helps align geometry calculations + // for BufferStateLayer with other layers. This should ideally happen in the client once client + // has the display orientation details from WM. + updateGeometry(); + if (c.width != s.width || c.height != s.height || !(c.transform == s.transform)) { // invalidate and recompute the visible regions if needed flags |= Layer::eVisibleRegion; @@ -1768,8 +1722,7 @@ ssize_t Layer::removeChild(const sp& layer) { void Layer::setChildrenDrawingParent(const sp& newParent) { for (const sp& child : mDrawingChildren) { child->mDrawingParent = newParent; - child->computeBounds(newParent->mBounds, - newParent->getTransformWithScale(newParent->getBufferScaleTransform()), + child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform, newParent->mEffectiveShadowRadius); } } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 284adbda66..ad4166b969 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -276,6 +276,7 @@ public: StretchEffect stretchEffect; Rect bufferCrop; + Rect destinationFrame; }; /* @@ -646,16 +647,6 @@ public: // Compute bounds for the layer and cache the results. void computeBounds(FloatRect parentBounds, ui::Transform parentTransform, float shadowRadius); - // Returns the buffer scale transform if a scaling mode is set. - ui::Transform getBufferScaleTransform() const; - - // Get effective layer transform, taking into account all its parent transform with any - // scaling if the parent scaling more is not NATIVE_WINDOW_SCALING_MODE_FREEZE. - ui::Transform getTransformWithScale(const ui::Transform& bufferScaleTransform) const; - - // Returns the bounds of the layer without any buffer scaling. - FloatRect getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const; - int32_t getSequence() const override { return sequence; } // For tracing. @@ -885,8 +876,10 @@ public: StretchEffect getStretchEffect() const; virtual bool setBufferCrop(const Rect& /* bufferCrop */) { return false; } + virtual bool setDestinationFrame(const Rect& /* destinationFrame */) { return false; } virtual std::atomic* getPendingBufferCounter() { return nullptr; } virtual std::string getPendingBufferCounterName() { return ""; } + virtual void updateGeometry() {} protected: friend class impl::SurfaceInterceptor; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index beda834f9a..3edbe1da02 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2816,16 +2816,19 @@ void SurfaceFlinger::processDisplayChangesLocked() { } void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { - /* - * Traversal of the children - * (perform the transaction for each of them if needed) - */ + // Commit display transactions + const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; + if (displayTransactionNeeded) { + processDisplayChangesLocked(); + processDisplayHotplugEventsLocked(); + } - if ((transactionFlags & eTraversalNeeded) || mForceTraversal) { - mForceTraversal = false; + // Commit layer transactions. This needs to happen after display transactions are + // committed because some geometry logic relies on display orientation. + if ((transactionFlags & eTraversalNeeded) || mForceTraversal || displayTransactionNeeded) { mCurrentState.traverse([&](Layer* layer) { uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); - if (!trFlags) return; + if (!trFlags && !displayTransactionNeeded) return; const uint32_t flags = layer->doTransaction(0); if (flags & Layer::eVisibleRegion) @@ -2837,15 +2840,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { }); } - /* - * Perform display own transactions if needed - */ - - if (transactionFlags & eDisplayTransactionNeeded) { - processDisplayChangesLocked(); - processDisplayHotplugEventsLocked(); - } - + // Update transform hint if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) { // The transform hint might have changed for some layers // (either because a display has changed, or because a layer @@ -4039,6 +4034,11 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } + if (what & layer_state_t::eDestinationFrameChanged) { + if (layer->setDestinationFrame(s.destinationFrame)) { + flags |= eTraversalNeeded; + } + } // This has to happen after we reparent children because when we reparent to null we remove // child layers from current state and remove its relative z. If the children are reparented in // the same transaction, then we have to make sure we reparent the children first so we do not -- cgit v1.2.3-59-g8ed1b From 97e7cc0ce23e417a2355a4559d43fd9c9ccb4efa Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 7 Jun 2021 10:45:40 -0700 Subject: SF: Pass transformHint with releaseBuffer We want the client to receive the tranformHint as early as possible, in particular prior to beginning rendering of a new frame. Since the releaseBuffer callback may cause the client to begin rendering we should include our most up to date transform hint here. Bug: 184842607 Test: Existing tests pass Change-Id: I61127d78f44b7332ad9ff3cade772fa6b475365f --- libs/gui/BLASTBufferQueue.cpp | 12 +++++++----- libs/gui/ITransactionCompletedListener.cpp | 5 +++-- libs/gui/SurfaceComposerClient.cpp | 8 +++++--- libs/gui/include/gui/BLASTBufferQueue.h | 3 ++- libs/gui/include/gui/ITransactionCompletedListener.h | 3 ++- libs/gui/include/gui/SurfaceComposerClient.h | 6 ++++-- services/surfaceflinger/BufferStateLayer.cpp | 15 ++++++++++----- 7 files changed, 33 insertions(+), 19 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index a2868c6143..b9a293f4c3 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -302,23 +302,25 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp context, uint64_t graphicBufferId, - const sp& releaseFence) { + const sp& releaseFence, uint32_t transformHint) { sp blastBufferQueue = context.promote(); ALOGV("releaseBufferCallbackThunk graphicBufferId=%" PRIu64 " blastBufferQueue=%s", graphicBufferId, blastBufferQueue ? "alive" : "dead"); if (blastBufferQueue) { - blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence); + blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence, transformHint); } } void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, - const sp& releaseFence) { + const sp& releaseFence, + uint32_t transformHint) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId); if (mSurfaceControl != nullptr) { - mTransformHint = mSurfaceControl->getTransformHint(); + mTransformHint = transformHint; + mSurfaceControl->setTransformHint(transformHint); mBufferItemConsumer->setTransformHint(mTransformHint); } @@ -412,7 +414,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp(this) /* callbackContext */, - std::placeholders::_1, std::placeholders::_2); + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback); t->setDataspace(mSurfaceControl, static_cast(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index f74f91e034..63d07ba1fb 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -251,10 +251,11 @@ public: stats); } - void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence) override { + void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence, + uint32_t transformHint) override { callRemoteAsync(Tag::ON_RELEASE_BUFFER, - graphicBufferId, releaseFence); + graphicBufferId, releaseFence, transformHint); } }; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 371454a3de..96104376d1 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -331,7 +331,8 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener callback(surfaceStats.previousBufferId, surfaceStats.previousReleaseFence ? surfaceStats.previousReleaseFence - : Fence::NO_FENCE); + : Fence::NO_FENCE, + surfaceStats.transformHint); } } } @@ -357,7 +358,8 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, - sp releaseFence) { + sp releaseFence, + uint32_t transformHint) { ReleaseBufferCallback callback; { std::scoped_lock lock(mMutex); @@ -367,7 +369,7 @@ void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, ALOGE("Could not call release buffer callback, buffer not found %" PRIu64, graphicBufferId); return; } - callback(graphicBufferId, releaseFence); + callback(graphicBufferId, releaseFence, transformHint); } ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index c4ca399e37..3ab1ee103d 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -89,7 +89,8 @@ public: void transactionCallback(nsecs_t latchTime, const sp& presentFence, const std::vector& stats); - void releaseBufferCallback(uint64_t graphicBufferId, const sp& releaseFence); + void releaseBufferCallback(uint64_t graphicBufferId, const sp& releaseFence, + uint32_t transformHint); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void setTransactionCompleteCallback(uint64_t frameNumber, diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index 2d71194f70..3bfeef1922 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -158,7 +158,8 @@ public: virtual void onTransactionCompleted(ListenerStats stats) = 0; - virtual void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence) = 0; + virtual void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence, + uint32_t transformHint) = 0; }; class BnTransactionCompletedListener : public SafeBnInterface { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 2582882c85..62a782fd3e 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -82,7 +82,8 @@ using TransactionCompletedCallback = std::function& /*presentFence*/, const std::vector& /*stats*/)>; using ReleaseBufferCallback = - std::function& /*releaseFence*/)>; + std::function& /*releaseFence*/, + uint32_t transformHint)>; using SurfaceStatsCallback = std::function releaseFence) override; + void onReleaseBuffer(uint64_t /* graphicsBufferId */, sp releaseFence, + uint32_t transformHint) override; private: ReleaseBufferCallback popReleaseBufferCallbackLocked(uint64_t /* graphicsBufferId */); diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 54daa102ba..0f0f08afc7 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -43,11 +43,13 @@ namespace android { using PresentState = frametimeline::SurfaceFrame::PresentState; namespace { void callReleaseBufferCallback(const sp& listener, - const sp& buffer, const sp& releaseFence) { + const sp& buffer, const sp& releaseFence, + uint32_t transformHint) { if (!listener) { return; } - listener->onReleaseBuffer(buffer->getId(), releaseFence ? releaseFence : Fence::NO_FENCE); + listener->onReleaseBuffer(buffer->getId(), releaseFence ? releaseFence : Fence::NO_FENCE, + transformHint); } } // namespace @@ -72,7 +74,8 @@ BufferStateLayer::~BufferStateLayer() { // issue with the clone layer trying to use the texture. if (mBufferInfo.mBuffer != nullptr && !isClone()) { callReleaseBufferCallback(mDrawingState.releaseBufferListener, - mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence); + mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence, + mTransformHint); } } @@ -427,7 +430,8 @@ bool BufferStateLayer::setBuffer(const std::shared_ptrgetBuffer(), - mCurrentState.acquireFence); + mCurrentState.acquireFence, + mTransformHint); decrementPendingBufferCount(); if (mCurrentState.bufferSurfaceFrameTX != nullptr) { addSurfaceFrameDroppedForBuffer(mCurrentState.bufferSurfaceFrameTX); @@ -946,7 +950,8 @@ void BufferStateLayer::bufferMayChange(const sp& newBuffer) { // then we will drop a buffer and should decrement the pending buffer count and // call any release buffer callbacks if set. callReleaseBufferCallback(mDrawingState.releaseBufferListener, - mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence); + mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence, + mTransformHint); decrementPendingBufferCount(); } } -- cgit v1.2.3-59-g8ed1b From b6aa9a0486bece3a93b4ffcfc76ed32f874a236d Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Wed, 9 Jun 2021 14:23:01 +0800 Subject: Update transform hint from relayout window (2/2) The transform hint is used to prevent allocating a buffer of a different size when a window is rotated. We return the fixed rotation transform and pass it to BLASTBufferQueue so the producer can choose to consume the hint and allocate the buffer with the same size. Bug: 188893403 Bug: 177029197 Test: atest WmTests Test: gfxbenchmark Test: atest libsurfaceflinger_unittest SurfaceFlinger_test Change-Id: I9fee3ab443e5f81d0209c62ad95c6355fa8dacee --- libs/gui/BLASTBufferQueue.cpp | 5 +++++ services/surfaceflinger/SurfaceFlinger.cpp | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index b9a293f4c3..68514cf9af 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -201,6 +201,11 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, applyTransaction = true; } + if (mSurfaceControl != nullptr) { + mTransformHint = mSurfaceControl->getTransformHint(); + mBufferItemConsumer->setTransformHint(mTransformHint); + } + ui::Size newSize(width, height); if (mRequestedSize != newSize) { mRequestedSize.set(newSize); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9cccd69465..db4e881249 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2838,7 +2838,9 @@ void SurfaceFlinger::processDisplayChanged(const wp& displayToken, (currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) { display->setProjection(currentState.orientation, currentState.layerStackSpaceRect, currentState.orientedDisplaySpaceRect); - mDefaultDisplayTransformHint = display->getTransformHint(); + if (display->isPrimary()) { + mDefaultDisplayTransformHint = display->getTransformHint(); + } } if (currentState.width != drawingState.width || currentState.height != drawingState.height) { @@ -6875,6 +6877,8 @@ sp SurfaceFlinger::handleLayerCreatedLocked(const sp& handle, bo parent->addChild(layer); } + layer->updateTransformHint(mDefaultDisplayTransformHint); + if (state->initialProducer != nullptr) { mGraphicBufferProducerList.insert(state->initialProducer); LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > mMaxGraphicBufferProducerListSize, -- cgit v1.2.3-59-g8ed1b From 0bde6b5a9837ab96484c988bb3f148d0b9b3ab4e Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 18 May 2021 13:57:02 -0700 Subject: SF: increase the number of buffers for SurfaceView 3 buffers are not sufficient for most apps to render at high refresh rates. This change increases the maxAcquiredBufferCount on the buffer queue for all surfaces, and removes the hwui-specific extra buffer allocations. All Surfaces connected to SurfaceFlinger will have now enough buffers to account for configured 'debug.sf.late.app.duration' value. Test: Run backpressure based game on 60Hz and 120Hz and collect traces Bug: 188553729 Change-Id: Ib8fda5db3f48c3bfc6fbf07167b4313674512cee --- libs/gui/BLASTBufferQueue.cpp | 10 ++++++++-- libs/gui/Surface.cpp | 15 --------------- libs/gui/SurfaceControl.cpp | 2 +- libs/gui/include/gui/BLASTBufferQueue.h | 2 +- libs/gui/include/gui/Surface.h | 2 -- libs/gui/tests/BLASTBufferQueue_test.cpp | 6 +++++- libs/nativewindow/include/system/window.h | 8 +------- 7 files changed, 16 insertions(+), 29 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index b9a293f4c3..8024482531 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -29,9 +29,10 @@ #include #include #include - #include +#include + #include using namespace std::chrono_literals; @@ -158,6 +159,11 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetDefaultBufferFormat(convertBufferFormat(format)); mBufferItemConsumer->setBlastBufferQueue(this); + int extraBufferCount = 0; + ComposerService::getComposerService()->getExtraBufferCount(&extraBufferCount); + mMaxAcquiredBuffers = 1 + extraBufferCount; + mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); + mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); SurfaceComposerClient::Transaction() @@ -567,7 +573,7 @@ void BLASTBufferQueue::setTransactionCompleteCallback( // includeExtraAcquire is true to include this buffer to the count. Since this depends on the state // of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE. bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const { - int maxAcquiredBuffers = MAX_ACQUIRED_BUFFERS + (includeExtraAcquire ? 2 : 1); + int maxAcquiredBuffers = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1); return mNumAcquired == maxAcquiredBuffers; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e117d1189c..821ec16eb1 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1501,9 +1501,6 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO: res = dispatchSetFrameTimelineInfo(args); break; - case NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT: - res = dispatchGetExtraBufferCount(args); - break; default: res = NAME_NOT_FOUND; break; @@ -1853,14 +1850,6 @@ int Surface::dispatchSetFrameTimelineInfo(va_list args) { return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId}); } -int Surface::dispatchGetExtraBufferCount(va_list args) { - ATRACE_CALL(); - auto extraBuffers = static_cast(va_arg(args, int*)); - - ALOGV("Surface::dispatchGetExtraBufferCount"); - return getExtraBufferCount(extraBuffers); -} - bool Surface::transformToDisplayInverse() const { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; @@ -2632,8 +2621,4 @@ status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInf return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo); } -status_t Surface::getExtraBufferCount(int* extraBuffers) const { - return composerService()->getExtraBufferCount(extraBuffers); -} - }; // namespace android diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index d7c07b9755..6529a4e51c 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -139,7 +139,7 @@ sp SurfaceControl::generateSurfaceLocked() ISurfaceComposerClient::eOpaque); mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat, flags, mHandle, {}, &ignore); - mBbq = new BLASTBufferQueue("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat); + mBbq = sp::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat); // This surface is always consumed by SurfaceFlinger, so the // producerControlledByApp value doesn't matter; using false. diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 3ab1ee103d..d63425e41b 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -132,7 +132,7 @@ private: // BufferQueue internally allows 1 more than // the max to be acquired - static const int MAX_ACQUIRED_BUFFERS = 1; + int32_t mMaxAcquiredBuffers = 1; int32_t mNumFrameAvailable GUARDED_BY(mMutex); int32_t mNumAcquired GUARDED_BY(mMutex); diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 48885ebdbb..7e4143b1f3 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -190,7 +190,6 @@ public: virtual status_t setFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy); virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info); - virtual status_t getExtraBufferCount(int* extraBuffers) const; protected: virtual ~Surface(); @@ -278,7 +277,6 @@ private: int dispatchGetLastQueuedBuffer(va_list args); int dispatchGetLastQueuedBuffer2(va_list args); int dispatchSetFrameTimelineInfo(va_list args); - int dispatchGetExtraBufferCount(va_list args); protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 5a5da97599..06660b8b50 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -394,7 +394,11 @@ TEST_F(BLASTBufferQueueTest, TripleBuffering) { setUpProducer(adapter, igbProducer); std::vector>> allocated; - for (int i = 0; i < 3; i++) { + int minUndequeuedBuffers = 0; + ASSERT_EQ(OK, igbProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers)); + const auto bufferCount = minUndequeuedBuffers + 2; + + for (int i = 0; i < bufferCount; i++) { int slot; sp fence; sp buf; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 935eded983..7f0113500d 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -256,8 +256,7 @@ enum { NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */ NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */ NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO = 48, /* private */ - NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT = 49, /* private */ - NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 50, /* private */ + NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 49, /* private */ // clang-format on }; @@ -1032,11 +1031,6 @@ static inline int native_window_set_frame_timeline_info(struct ANativeWindow* wi frameTimelineVsyncId, inputEventId); } -static inline int native_window_get_extra_buffer_count( - struct ANativeWindow* window, int* extraBuffers) { - return window->perform(window, NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT, extraBuffers); -} - // ------------------------------------------------------------------------------------------------ // Candidates for APEX visibility // These functions are planned to be made stable for APEX modules, but have not -- cgit v1.2.3-59-g8ed1b From 899dcdb63ad9cb81d1987e89be08dc9603aad89b Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 15 Jun 2021 16:56:21 -0700 Subject: SF: change acquired buffers based on the current refresh rate BLASTBufferQueue set the max acquired buffers based on SF vsync configuration (sf.duration and app.duration). This is calculated based on the max supported refresh rate on the device, and it turn is propogated to apps via min_undequeued_buffers to the app could allocate enough buffers for maintaining the pipeline SF expects. This leads to a higher latency when the device is running in a lower refresh rate as there are more buffers on the buffer queue then required. In this change we are holding on the these "extra buffers" and not releasing them back to the buffer queue so the app would use the number of buffers it needs based on the current refresh rate, and to avoid having unnecessary long latency. Bug: 188553729 Test: Run backpressure based game on 60Hz and 120Hz and collect systraces Change-Id: I9d4e6278f0ddd28008ac437ab0576aa79d05166a --- libs/gui/BLASTBufferQueue.cpp | 52 +++++++++++++++------- libs/gui/ISurfaceComposer.cpp | 17 +++---- libs/gui/ITransactionCompletedListener.cpp | 10 +++-- libs/gui/SurfaceComposerClient.cpp | 11 ++--- libs/gui/include/gui/BLASTBufferQueue.h | 11 ++++- libs/gui/include/gui/ISurfaceComposer.h | 21 +++++---- .../include/gui/ITransactionCompletedListener.h | 10 +++-- libs/gui/include/gui/SurfaceComposerClient.h | 4 +- libs/gui/tests/Surface_test.cpp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 21 ++++++--- services/surfaceflinger/Scheduler/Scheduler.cpp | 8 ++-- services/surfaceflinger/SurfaceFlinger.cpp | 37 ++++++++++----- services/surfaceflinger/SurfaceFlinger.h | 10 +++-- .../surfaceflinger/TransactionCallbackInvoker.cpp | 5 ++- .../surfaceflinger/TransactionCallbackInvoker.h | 1 + .../tests/ReleaseBufferCallback_test.cpp | 5 ++- .../tests/unittests/SchedulerTest.cpp | 12 ++--- .../tests/unittests/TestableSurfaceFlinger.h | 6 +-- 18 files changed, 155 insertions(+), 88 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 8024482531..52d3fa33f0 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -159,9 +159,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetDefaultBufferFormat(convertBufferFormat(format)); mBufferItemConsumer->setBlastBufferQueue(this); - int extraBufferCount = 0; - ComposerService::getComposerService()->getExtraBufferCount(&extraBufferCount); - mMaxAcquiredBuffers = 1 + extraBufferCount; + ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); mTransformHint = mSurfaceControl->getTransformHint(); @@ -308,18 +306,20 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp context, uint64_t graphicBufferId, - const sp& releaseFence, uint32_t transformHint) { + const sp& releaseFence, uint32_t transformHint, + uint32_t currentMaxAcquiredBufferCount) { sp blastBufferQueue = context.promote(); ALOGV("releaseBufferCallbackThunk graphicBufferId=%" PRIu64 " blastBufferQueue=%s", graphicBufferId, blastBufferQueue ? "alive" : "dead"); if (blastBufferQueue) { - blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence, transformHint); + blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence, transformHint, + currentMaxAcquiredBufferCount); } } void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, - const sp& releaseFence, - uint32_t transformHint) { + const sp& releaseFence, uint32_t transformHint, + uint32_t currentMaxAcquiredBufferCount) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId); @@ -330,15 +330,36 @@ void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, mBufferItemConsumer->setTransformHint(mTransformHint); } - auto it = mSubmitted.find(graphicBufferId); - if (it == mSubmitted.end()) { - BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64, - graphicBufferId); - return; + // Calculate how many buffers we need to hold before we release them back + // to the buffer queue. This will prevent higher latency when we are running + // on a lower refresh rate than the max supported. We only do that for EGL + // clients as others don't care about latency + const bool isEGL = [&] { + const auto it = mSubmitted.find(graphicBufferId); + return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL; + }(); + + const auto numPendingBuffersToHold = + isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0; + mPendingRelease.emplace_back(ReleasedBuffer{graphicBufferId, releaseFence}); + + // Release all buffers that are beyond the ones that we need to hold + while (mPendingRelease.size() > numPendingBuffersToHold) { + const auto releaseBuffer = mPendingRelease.front(); + mPendingRelease.pop_front(); + auto it = mSubmitted.find(releaseBuffer.bufferId); + if (it == mSubmitted.end()) { + BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64, + graphicBufferId); + return; + } + + mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence); + mSubmitted.erase(it); } - mBufferItemConsumer->releaseBuffer(it->second, releaseFence); - mSubmitted.erase(it); + ATRACE_INT("PendingRelease", mPendingRelease.size()); + mNumAcquired--; processNextBufferLocked(false /* useNextTransaction */); mCallbackCV.notify_all(); @@ -420,7 +441,8 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp(this) /* callbackContext */, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4); t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback); t->setDataspace(mSurfaceControl, static_cast(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 71e18a97c9..0d7795e1ba 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1215,16 +1215,17 @@ public: return reply.readInt32(); } - status_t getExtraBufferCount(int* extraBuffers) const override { + status_t getMaxAcquiredBufferCount(int* buffers) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - status_t err = remote()->transact(BnSurfaceComposer::GET_EXTRA_BUFFER_COUNT, data, &reply); + status_t err = + remote()->transact(BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); if (err != NO_ERROR) { - ALOGE("getExtraBufferCount failed to read data: %s (%d)", strerror(-err), err); + ALOGE("getMaxAcquiredBufferCount failed to read data: %s (%d)", strerror(-err), err); return err; } - return reply.readInt32(extraBuffers); + return reply.readInt32(buffers); } }; @@ -2069,14 +2070,14 @@ status_t BnSurfaceComposer::onTransact( SAFE_PARCEL(reply->writeInt32, priority); return NO_ERROR; } - case GET_EXTRA_BUFFER_COUNT: { + case GET_MAX_ACQUIRED_BUFFER_COUNT: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - int extraBuffers = 0; - int err = getExtraBufferCount(&extraBuffers); + int buffers = 0; + int err = getMaxAcquiredBufferCount(&buffers); if (err != NO_ERROR) { return err; } - SAFE_PARCEL(reply->writeInt32, extraBuffers); + SAFE_PARCEL(reply->writeInt32, buffers); return NO_ERROR; } case OVERRIDE_HDR_TYPES: { diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 63d07ba1fb..17499ecd50 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -119,6 +119,7 @@ status_t SurfaceStats::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeBool, false); } SAFE_PARCEL(output->writeUint32, transformHint); + SAFE_PARCEL(output->writeUint32, currentMaxAcquiredBufferCount); SAFE_PARCEL(output->writeParcelable, eventStats); SAFE_PARCEL(output->writeInt32, static_cast(jankData.size())); for (const auto& data : jankData) { @@ -138,6 +139,7 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) { SAFE_PARCEL(input->read, *previousReleaseFence); } SAFE_PARCEL(input->readUint32, &transformHint); + SAFE_PARCEL(input->readUint32, ¤tMaxAcquiredBufferCount); SAFE_PARCEL(input->readParcelable, &eventStats); int32_t jankData_size = 0; @@ -251,11 +253,13 @@ public: stats); } - void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence, - uint32_t transformHint) override { + void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence, uint32_t transformHint, + uint32_t currentMaxAcquiredBufferCount) override { callRemoteAsync(Tag::ON_RELEASE_BUFFER, - graphicBufferId, releaseFence, transformHint); + graphicBufferId, releaseFence, + transformHint, + currentMaxAcquiredBufferCount); } }; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 660c5bd97d..c69435d328 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -328,7 +328,8 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener surfaceStats.previousReleaseFence ? surfaceStats.previousReleaseFence : Fence::NO_FENCE, - surfaceStats.transformHint); + surfaceStats.transformHint, + surfaceStats.currentMaxAcquiredBufferCount); } } } @@ -364,9 +365,9 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } } -void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, - sp releaseFence, - uint32_t transformHint) { +void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence, + uint32_t transformHint, + uint32_t currentMaxAcquiredBufferCount) { ReleaseBufferCallback callback; { std::scoped_lock lock(mMutex); @@ -376,7 +377,7 @@ void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, ALOGE("Could not call release buffer callback, buffer not found %" PRIu64, graphicBufferId); return; } - callback(graphicBufferId, releaseFence, transformHint); + callback(graphicBufferId, releaseFence, transformHint, currentMaxAcquiredBufferCount); } ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index d63425e41b..0981e760a5 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -90,7 +90,7 @@ public: void transactionCallback(nsecs_t latchTime, const sp& presentFence, const std::vector& stats); void releaseBufferCallback(uint64_t graphicBufferId, const sp& releaseFence, - uint32_t transformHint); + uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void setTransactionCompleteCallback(uint64_t frameNumber, @@ -141,6 +141,15 @@ private: // buffer or the buffer has been presented and a new buffer is ready to be presented. std::unordered_map mSubmitted GUARDED_BY(mMutex); + // Keep a queue of the released buffers instead of immediately releasing + // the buffers back to the buffer queue. This would be controlled by SF + // setting the max acquired buffer count. + struct ReleasedBuffer { + uint64_t bufferId; + sp releaseFence; + }; + std::deque mPendingRelease GUARDED_BY(mMutex); + ui::Size mSize GUARDED_BY(mMutex); ui::Size mRequestedSize GUARDED_BY(mMutex); int32_t mFormat GUARDED_BY(mMutex); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 439d90ad10..2a3f6a43d9 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -537,22 +537,21 @@ public: virtual int getGPUContextPriority() = 0; /** - * Gets the extra buffers a client would need to allocate if it passes - * the Choreographer#getVsyncId with its buffers. - * - * When Choreographer#getVsyncId is passed to SurfaceFlinger, it is used - * as an indication of when to latch the buffer. SurfaceFlinger will make - * sure that it will give the app at least the time configured as the - * 'appDuration' before trying to latch the buffer. + * Gets the number of buffers SurfaceFlinger would need acquire. This number + * would be propagated to the client via MIN_UNDEQUEUED_BUFFERS so that the + * client could allocate enough buffers to match SF expectations of the + * pipeline depth. SurfaceFlinger will make sure that it will give the app at + * least the time configured as the 'appDuration' before trying to latch + * the buffer. * * The total buffers needed for a given configuration is basically the * numbers of vsyncs a single buffer is used across the stack. For the default * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger * and 1 vsync by the display. The extra buffers are calculated as the - * number of additional buffers on top of the 3 buffers already allocated - * by the app. + * number of additional buffers on top of the 2 buffers already present + * in MIN_UNDEQUEUED_BUFFERS. */ - virtual status_t getExtraBufferCount(int* extraBuffers) const = 0; + virtual status_t getMaxAcquiredBufferCount(int* buffers) const = 0; }; // ---------------------------------------------------------------------------- @@ -615,7 +614,7 @@ public: SET_FRAME_TIMELINE_INFO, ADD_TRANSACTION_TRACE_LISTENER, GET_GPU_CONTEXT_PRIORITY, - GET_EXTRA_BUFFER_COUNT, + GET_MAX_ACQUIRED_BUFFER_COUNT, GET_DYNAMIC_DISPLAY_INFO, ADD_FPS_LISTENER, REMOVE_FPS_LISTENER, diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index 3bfeef1922..d286c34ec8 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -101,12 +101,14 @@ public: SurfaceStats() = default; SurfaceStats(const sp& sc, nsecs_t time, const sp& prevReleaseFence, - uint32_t hint, FrameEventHistoryStats frameEventStats, - std::vector jankData, uint64_t previousBufferId) + uint32_t hint, uint32_t currentMaxAcquiredBuffersCount, + FrameEventHistoryStats frameEventStats, std::vector jankData, + uint64_t previousBufferId) : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence), transformHint(hint), + currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount), eventStats(frameEventStats), jankData(std::move(jankData)), previousBufferId(previousBufferId) {} @@ -115,6 +117,7 @@ public: nsecs_t acquireTime = -1; sp previousReleaseFence; uint32_t transformHint = 0; + uint32_t currentMaxAcquiredBufferCount = 0; FrameEventHistoryStats eventStats; std::vector jankData; uint64_t previousBufferId; @@ -159,7 +162,8 @@ public: virtual void onTransactionCompleted(ListenerStats stats) = 0; virtual void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence, - uint32_t transformHint) = 0; + uint32_t transformHint, + uint32_t currentMaxAcquiredBufferCount) = 0; }; class BnTransactionCompletedListener : public SafeBnInterface { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 5aa132cd92..fa91bfa010 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -83,7 +83,7 @@ using TransactionCompletedCallback = const std::vector& /*stats*/)>; using ReleaseBufferCallback = std::function& /*releaseFence*/, - uint32_t transformHint)>; + uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount)>; using SurfaceStatsCallback = std::function releaseFence, - uint32_t transformHint) override; + uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override; private: ReleaseBufferCallback popReleaseBufferCallbackLocked(uint64_t /* graphicsBufferId */); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index b8d34c3160..59b0c04bc3 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -902,7 +902,7 @@ public: int getGPUContextPriority() override { return 0; }; - status_t getExtraBufferCount(int* /*extraBuffers*/) const override { return NO_ERROR; } + status_t getMaxAcquiredBufferCount(int* /*buffers*/) const override { return NO_ERROR; } protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index d68a0e0b47..955c2f88b0 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -44,12 +44,12 @@ using PresentState = frametimeline::SurfaceFrame::PresentState; namespace { void callReleaseBufferCallback(const sp& listener, const sp& buffer, const sp& releaseFence, - uint32_t transformHint) { + uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) { if (!listener) { return; } listener->onReleaseBuffer(buffer->getId(), releaseFence ? releaseFence : Fence::NO_FENCE, - transformHint); + transformHint, currentMaxAcquiredBufferCount); } } // namespace @@ -75,7 +75,9 @@ BufferStateLayer::~BufferStateLayer() { if (mBufferInfo.mBuffer != nullptr && !isClone()) { callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence, - mTransformHint); + mTransformHint, + mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( + mOwnerUid)); } } @@ -199,6 +201,8 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { for (const auto& handle : mDrawingState.callbackHandles) { handle->transformHint = mTransformHint; handle->dequeueReadyTime = dequeueReadyTime; + handle->currentMaxAcquiredBufferCount = + mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); } // If there are multiple transactions in this frame, set the previous id on the earliest @@ -429,9 +433,10 @@ bool BufferStateLayer::setBuffer(const std::shared_ptrgetBuffer(), - mCurrentState.acquireFence, - mTransformHint); + mCurrentState.buffer->getBuffer(), mCurrentState.acquireFence, + mTransformHint, + mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( + mOwnerUid)); decrementPendingBufferCount(); if (mCurrentState.bufferSurfaceFrameTX != nullptr) { addSurfaceFrameDroppedForBuffer(mCurrentState.bufferSurfaceFrameTX); @@ -951,7 +956,9 @@ void BufferStateLayer::bufferMayChange(const sp& newBuffer) { // call any release buffer callbacks if set. callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence, - mTransformHint); + mTransformHint, + mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( + mOwnerUid)); decrementPendingBufferCount(); } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 4b8cbfb621..e0b364020b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -205,6 +205,10 @@ std::unique_ptr Scheduler::makePrimaryDispSyncSource( } std::optional Scheduler::getFrameRateOverride(uid_t uid) const { + if (!mRefreshRateConfigs.supportsFrameRateOverride()) { + return std::nullopt; + } + std::lock_guard lock(mFrameRateOverridesMutex); { const auto iter = mFrameRateOverridesFromBackdoor.find(uid); @@ -224,10 +228,6 @@ std::optional Scheduler::getFrameRateOverride(uid_t uid) const { } bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const { - if (!mRefreshRateConfigs.supportsFrameRateOverride()) { - return true; - } - const auto frameRate = getFrameRateOverride(uid); if (!frameRate.has_value()) { return true; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c1d28b1746..a39ae5819d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5247,7 +5247,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case CAPTURE_DISPLAY: case SET_FRAME_TIMELINE_INFO: case GET_GPU_CONTEXT_PRIORITY: - case GET_EXTRA_BUFFER_COUNT: { + case GET_MAX_ACQUIRED_BUFFER_COUNT: { // This is not sensitive information, so should not require permission control. return OK; } @@ -6800,25 +6800,38 @@ int SurfaceFlinger::getGPUContextPriority() { return getRenderEngine().getContextPriority(); } -int SurfaceFlinger::calculateExtraBufferCount(Fps maxSupportedRefreshRate, - std::chrono::nanoseconds presentLatency) { - auto pipelineDepth = presentLatency.count() / maxSupportedRefreshRate.getPeriodNsecs(); - if (presentLatency.count() % maxSupportedRefreshRate.getPeriodNsecs()) { +int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, + std::chrono::nanoseconds presentLatency) { + auto pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs(); + if (presentLatency.count() % refreshRate.getPeriodNsecs()) { pipelineDepth++; } - return std::max(0ll, pipelineDepth - 2); + return std::max(1ll, pipelineDepth - 1); } -status_t SurfaceFlinger::getExtraBufferCount(int* extraBuffers) const { +status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { const auto maxSupportedRefreshRate = mRefreshRateConfigs->getSupportedRefreshRateRange().max; - const auto vsyncConfig = - mVsyncConfiguration->getConfigsForRefreshRate(maxSupportedRefreshRate).late; - const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration; - - *extraBuffers = calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency); + *buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate); return NO_ERROR; } +int SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const { + const auto refreshRate = [&] { + const auto frameRateOverride = mScheduler->getFrameRateOverride(uid); + if (frameRateOverride.has_value()) { + return frameRateOverride.value(); + } + return mRefreshRateConfigs->getCurrentRefreshRate().getFps(); + }(); + return getMaxAcquiredBufferCountForRefreshRate(refreshRate); +} + +int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const { + const auto vsyncConfig = mVsyncConfiguration->getConfigsForRefreshRate(refreshRate).late; + const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration; + return calculateMaxAcquiredBufferCount(refreshRate, presentLatency); +} + void SurfaceFlinger::TransactionState::traverseStatesWithBuffers( std::function visitor) { for (const auto& state : states) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a3fa8d654f..22d17eb153 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -708,7 +708,7 @@ private: int getGPUContextPriority() override; - status_t getExtraBufferCount(int* extraBuffers) const override; + status_t getMaxAcquiredBufferCount(int* buffers) const override; // Implements IBinder::DeathRecipient. void binderDied(const wp& who) override; @@ -923,6 +923,8 @@ private: size_t getMaxTextureSize() const; size_t getMaxViewportDims() const; + int getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const; + /* * Display and layer stack management */ @@ -1062,6 +1064,7 @@ private: // Calculates the expected present time for this frame. For negative offsets, performs a // correction using the predicted vsync for the next frame instead. + nsecs_t calculateExpectedPresentTime(DisplayStatInfo) const; /* @@ -1177,8 +1180,9 @@ private: std::vector getDisplayColorModes(PhysicalDisplayId displayId) REQUIRES(mStateLock); - static int calculateExtraBufferCount(Fps maxSupportedRefreshRate, - std::chrono::nanoseconds presentLatency); + static int calculateMaxAcquiredBufferCount(Fps refreshRate, + std::chrono::nanoseconds presentLatency); + int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const; sp mStartPropertySetThread; surfaceflinger::Factory& mFactory; diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index 4f4c02be6c..fdf16a797f 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -235,8 +235,9 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp& handle->dequeueReadyTime); transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime, handle->previousReleaseFence, - handle->transformHint, eventStats, jankData, - handle->previousBufferId); + handle->transformHint, + handle->currentMaxAcquiredBufferCount, + eventStats, jankData, handle->previousBufferId); } return NO_ERROR; } diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 184b15103e..444bec646e 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -45,6 +45,7 @@ public: nsecs_t acquireTime = -1; nsecs_t latchTime = -1; uint32_t transformHint = 0; + uint32_t currentMaxAcquiredBufferCount = 0; std::shared_ptr gpuCompositionDoneFence{FenceTime::NO_FENCE}; CompositorTiming compositorTiming; nsecs_t refreshStartTime = 0; diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp index fb7d41c81e..5aa809dc8b 100644 --- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp +++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp @@ -30,7 +30,8 @@ using android::hardware::graphics::common::V1_1::BufferUsage; class ReleaseBufferCallbackHelper { public: static void function(void* callbackContext, uint64_t graphicsBufferId, - const sp& releaseFence) { + const sp& releaseFence, + uint32_t /*currentMaxAcquiredBufferCount*/) { if (!callbackContext) { FAIL() << "failed to get callback context"; } @@ -66,7 +67,7 @@ public: android::ReleaseBufferCallback getCallback() { return std::bind(function, static_cast(this) /* callbackContext */, - std::placeholders::_1, std::placeholders::_2); + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); } std::mutex mMutex; diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 423d0ccbff..f680d802e6 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -210,14 +210,14 @@ TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0); } -TEST_F(SchedulerTest, calculateExtraBufferCount) { - EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 30ms)); - EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(90), 30ms)); - EXPECT_EQ(2, mFlinger.calculateExtraBufferCount(Fps(120), 30ms)); +TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { + EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 30ms)); + EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(90), 30ms)); + EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(Fps(120), 30ms)); - EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(60), 40ms)); + EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 40ms)); - EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 10ms)); + EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 10ms)); } MATCHER(Is120Hz, "") { diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index d78f36cd27..b363146e10 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -391,9 +391,9 @@ public: auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); } - auto calculateExtraBufferCount(Fps maxSupportedRefreshRate, - std::chrono::nanoseconds presentLatency) const { - return SurfaceFlinger::calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency); + auto calculateMaxAcquiredBufferCount(Fps refreshRate, + std::chrono::nanoseconds presentLatency) const { + return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } /* ------------------------------------------------------------------------ -- cgit v1.2.3-59-g8ed1b From de66dc7269e7963db68d46be3128ad2544759917 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 17 Jun 2021 17:54:41 -0700 Subject: Don't update BufferQueue FrameEventStats when a frame is dropped Update BlastBufferQueue to match BQ logic. This change in behaviour was causing a dEQP test failure which relied on actual present timestamps to generate future desired present timestamps. If a buffer was dropped, the actual present timestamp retrieved would be 0 causing cascading failures. Test: atest BLASTFrameEventHistoryTest Test: CtsDeqpTestCases:dEQP-VK.wsi.android.display_timing.fifo#display_timing Bug: 186200443 Change-Id: I9589d6e43c5f6dfbe93702b7c43a8fff8712fe24 --- libs/gui/BLASTBufferQueue.cpp | 21 ++++++----- libs/gui/tests/BLASTBufferQueue_test.cpp | 64 ++++++++++++++++++++++++-------- 2 files changed, 61 insertions(+), 24 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index b9a293f4c3..70d8208acd 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -255,15 +255,18 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const spsetTransformHint(mTransformHint); - mBufferItemConsumer - ->updateFrameTimestamps(stat.frameEventStats.frameNumber, - stat.frameEventStats.refreshStartTime, - stat.frameEventStats.gpuCompositionDoneFence, - stat.presentFence, stat.previousReleaseFence, - stat.frameEventStats.compositorTiming, - stat.latchTime, - stat.frameEventStats.dequeueReadyTime); - + // Update frametime stamps if the frame was latched and presented, indicated by a + // valid latch time. + if (stat.latchTime > 0) { + mBufferItemConsumer + ->updateFrameTimestamps(stat.frameEventStats.frameNumber, + stat.frameEventStats.refreshStartTime, + stat.frameEventStats.gpuCompositionDoneFence, + stat.presentFence, stat.previousReleaseFence, + stat.frameEventStats.compositorTiming, + stat.latchTime, + stat.frameEventStats.dequeueReadyTime); + } currFrameNumber = stat.frameEventStats.frameNumber; if (mTransactionCompleteCallback && diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 5a5da97599..199f6c125c 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -944,21 +944,22 @@ TEST_F(BLASTBufferQueueTransformTest, setTransform_ROT_270) { class BLASTFrameEventHistoryTest : public BLASTBufferQueueTest { public: void setUpAndQueueBuffer(const sp& igbProducer, - nsecs_t* requestedPresentTime, nsecs_t* postedTime, + nsecs_t* outRequestedPresentTime, nsecs_t* postedTime, IGraphicBufferProducer::QueueBufferOutput* qbOutput, - bool getFrameTimestamps, nsecs_t requestedPresentTimeDelay = 0) { + bool getFrameTimestamps, nsecs_t requestedPresentTime = systemTime()) { int slot; sp fence; sp buf; auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); - ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); - ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + if (IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION == ret) { + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + } - nsecs_t requestedTime = systemTime() + requestedPresentTimeDelay; - if (requestedPresentTime) *requestedPresentTime = requestedTime; - IGraphicBufferProducer::QueueBufferInput input(requestedTime, false, HAL_DATASPACE_UNKNOWN, + *outRequestedPresentTime = requestedPresentTime; + IGraphicBufferProducer::QueueBufferInput input(requestedPresentTime, false, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE, /*sticky*/ 0, @@ -1030,9 +1031,11 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) { IGraphicBufferProducer::QueueBufferOutput qbOutput; nsecs_t requestedPresentTimeA = 0; nsecs_t postedTimeA = 0; - nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); + // Present the frame sometime in the future so we can add two frames to the queue so the older + // one will be dropped. + nsecs_t presentTime = systemTime() + std::chrono::nanoseconds(500ms).count(); setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true, - presentTimeDelay); + presentTime); history.applyDelta(qbOutput.frameTimestamps); FrameEvents* events = nullptr; @@ -1045,7 +1048,10 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) { // queue another buffer so the first can be dropped nsecs_t requestedPresentTimeB = 0; nsecs_t postedTimeB = 0; - setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true); + adapter.setTransactionCompleteCallback(2); + presentTime = systemTime() + std::chrono::nanoseconds(1ms).count(); + setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true, + presentTime); history.applyDelta(qbOutput.frameTimestamps); events = history.getFrame(1); ASSERT_NE(nullptr, events); @@ -1055,20 +1061,48 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) { ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); ASSERT_GE(events->postedTime, postedTimeA); - // a valid latchtime should not be set + // a valid latchtime and pre and post composition info should not be set for the dropped frame ASSERT_FALSE(events->hasLatchInfo()); ASSERT_FALSE(events->hasDequeueReadyInfo()); + ASSERT_FALSE(events->hasGpuCompositionDoneInfo()); + ASSERT_FALSE(events->hasDisplayPresentInfo()); + ASSERT_FALSE(events->hasReleaseInfo()); - ASSERT_NE(nullptr, events->gpuCompositionDoneFence); - ASSERT_NE(nullptr, events->displayPresentFence); - ASSERT_NE(nullptr, events->releaseFence); + // wait for the last transaction to be completed. + adapter.waitForCallback(2); - // we should also have gotten the initial values for the next frame + // queue another buffer so we query for frame event deltas + nsecs_t requestedPresentTimeC = 0; + nsecs_t postedTimeC = 0; + setUpAndQueueBuffer(igbProducer, &requestedPresentTimeC, &postedTimeC, &qbOutput, true); + history.applyDelta(qbOutput.frameTimestamps); + + // frame number, requestedPresentTime, and postTime should not have changed + ASSERT_EQ(1, events->frameNumber); + ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); + ASSERT_GE(events->postedTime, postedTimeA); + + // a valid latchtime and pre and post composition info should not be set for the dropped frame + ASSERT_FALSE(events->hasLatchInfo()); + ASSERT_FALSE(events->hasDequeueReadyInfo()); + ASSERT_FALSE(events->hasGpuCompositionDoneInfo()); + ASSERT_FALSE(events->hasDisplayPresentInfo()); + ASSERT_FALSE(events->hasReleaseInfo()); + + // we should also have gotten values for the presented frame events = history.getFrame(2); ASSERT_NE(nullptr, events); ASSERT_EQ(2, events->frameNumber); ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime); ASSERT_GE(events->postedTime, postedTimeB); + ASSERT_GE(events->latchTime, postedTimeB); + ASSERT_GE(events->dequeueReadyTime, events->latchTime); + ASSERT_NE(nullptr, events->gpuCompositionDoneFence); + ASSERT_NE(nullptr, events->displayPresentFence); + ASSERT_NE(nullptr, events->releaseFence); + + // wait for any callbacks that have not been received + adapter.waitForCallbacks(); } } // namespace android -- cgit v1.2.3-59-g8ed1b From 9dfe2b2ec6660e46f3cfdf5865689add82888e75 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 11 Jun 2021 16:48:58 -0700 Subject: BBQ: add a counter for pending buffers Test: Run TouchLatency and collect systraces Fixes: 191512153 Change-Id: I7e1ced0b3994c2f0427feb60bda7af57df595b65 --- libs/gui/BLASTBufferQueue.cpp | 4 +++- libs/gui/include/gui/BLASTBufferQueue.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index a2868c6143..430f971f79 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -150,6 +150,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetName(String8(consumerName.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); @@ -164,7 +165,6 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spreleaseBuffer(it->second, releaseFence); mSubmitted.erase(it); mNumAcquired--; + ATRACE_INT(mPendingBufferTrace.c_str(), mNumFrameAvailable + mNumAcquired); processNextBufferLocked(false /* useNextTransaction */); mCallbackCV.notify_all(); } @@ -499,6 +500,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { } // add to shadow queue mNumFrameAvailable++; + ATRACE_INT(mPendingBufferTrace.c_str(), mNumFrameAvailable + mNumAcquired); BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, toString(nextTransactionSet)); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index c4ca399e37..2ff78e99d0 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -124,6 +124,7 @@ private: static PixelFormat convertBufferFormat(PixelFormat& format); std::string mName; + std::string mPendingBufferTrace; sp mSurfaceControl; std::mutex mMutex; -- cgit v1.2.3-59-g8ed1b From 2a52ca6274f3ca8b9aea8d22c49ca8fcae4b8455 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 24 Jun 2021 13:08:53 -0700 Subject: BlastBufferQueue: Fix acquire counts when holding buffers Update the acquire count when ever we release a buffer otherwise when going from 120hz to 60hz we may release multiple buffers and only decrement the acquire count once. This will prevent the adapter from acquiring all the possible buffers. Also make sure we process the shadow queue every time we release a buffer. Bug: 188553729 Test: Run backpressure based game on 60Hz and 90hz and collect traces Change-Id: I23517ee0fe840a9215f368bd85713ba19dbeb2a3 --- libs/gui/BLASTBufferQueue.cpp | 14 +++++++------- libs/gui/include/gui/BLASTBufferQueue.h | 6 +++++- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 364c939c18..e15e11cc20 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -151,7 +151,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetName(String8(consumerName.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); @@ -361,16 +361,15 @@ void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, graphicBufferId); return; } - + mNumAcquired--; mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence); mSubmitted.erase(it); + processNextBufferLocked(false /* useNextTransaction */); } ATRACE_INT("PendingRelease", mPendingRelease.size()); - - mNumAcquired--; - ATRACE_INT(mPendingBufferTrace.c_str(), mNumFrameAvailable + mNumAcquired); - processNextBufferLocked(false /* useNextTransaction */); + ATRACE_INT(mQueuedBufferTrace.c_str(), + mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); mCallbackCV.notify_all(); } @@ -538,7 +537,8 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { } // add to shadow queue mNumFrameAvailable++; - ATRACE_INT(mPendingBufferTrace.c_str(), mNumFrameAvailable + mNumAcquired); + ATRACE_INT(mQueuedBufferTrace.c_str(), + mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, toString(nextTransactionSet)); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index cb0e65e409..26c7285ab0 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -125,7 +125,11 @@ private: static PixelFormat convertBufferFormat(PixelFormat& format); std::string mName; - std::string mPendingBufferTrace; + // Represents the queued buffer count from buffer queue, + // pre-BLAST. This is mNumFrameAvailable (buffers that queued to blast) + + // mNumAcquired (buffers that queued to SF) mPendingRelease.size() (buffers that are held by + // blast). This counter is read by android studio profiler. + std::string mQueuedBufferTrace; sp mSurfaceControl; std::mutex mMutex; -- cgit v1.2.3-59-g8ed1b From 4ba0c2e2a2e8a4870b4d5055bd765d5514a35ebc Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 24 Jun 2021 11:27:17 -0700 Subject: Blast: Use a unique id to track buffers When buffer queue is configured in shared buffer mode, the client can queue the same buffer over and over again and the consumer can acquire the same buffer repeatedly. BBQ tracks acquired buffers by graphic buffer id and SCC tracks release buffer callbacks by graphic buffer ids. This breaks if a buffer is reused before release. Fix this by using graphic buffer id and framenumber to track acquired buffers and buffer release callbacks. Test: atest CtsDeqpTestCases:dEQP-VK.wsi.android.shared_presentable_image.scale_none.identity.inherit.demand CtsDeqpTestCases:dEQP-VK.wsi.android.colorspace#basic Bug: 191220669 Change-Id: Ibd54df9fa6780c26cd8de769bf9e43163abbed5a --- libs/gui/BLASTBufferQueue.cpp | 40 +++++------ libs/gui/ITransactionCompletedListener.cpp | 24 +++++-- libs/gui/SurfaceComposerClient.cpp | 43 +++++++----- libs/gui/include/gui/BLASTBufferQueue.h | 7 +- .../include/gui/ITransactionCompletedListener.h | 38 +++++++++-- libs/gui/include/gui/LayerState.h | 6 ++ libs/gui/include/gui/SurfaceComposerClient.h | 20 +++--- services/surfaceflinger/BufferLayer.h | 1 + services/surfaceflinger/BufferStateLayer.cpp | 40 +++++------ services/surfaceflinger/BufferStateLayer.h | 9 +-- .../surfaceflinger/TransactionCallbackInvoker.cpp | 3 +- .../surfaceflinger/TransactionCallbackInvoker.h | 2 +- .../tests/ReleaseBufferCallback_test.cpp | 77 ++++++++++++++-------- 13 files changed, 192 insertions(+), 118 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index e15e11cc20..29701168e7 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -132,8 +132,7 @@ void BLASTBufferItemConsumer::onSidebandStreamChanged() { BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp& surface, int width, int height, int32_t format) - : mName(name), - mSurfaceControl(surface), + : mSurfaceControl(surface), mSize(width, height), mRequestedSize(mSize), mFormat(format), @@ -150,6 +149,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp context, uint64_t graphicBufferId, +static void releaseBufferCallbackThunk(wp context, const ReleaseCallbackId& id, const sp& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) { sp blastBufferQueue = context.promote(); - ALOGV("releaseBufferCallbackThunk graphicBufferId=%" PRIu64 " blastBufferQueue=%s", - graphicBufferId, blastBufferQueue ? "alive" : "dead"); if (blastBufferQueue) { - blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence, transformHint, + blastBufferQueue->releaseBufferCallback(id, releaseFence, transformHint, currentMaxAcquiredBufferCount); + } else { + ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str()); } } -void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, +void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, const sp& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; - BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId); + BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str()); if (mSurfaceControl != nullptr) { mTransformHint = transformHint; @@ -343,25 +343,26 @@ void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, // on a lower refresh rate than the max supported. We only do that for EGL // clients as others don't care about latency const bool isEGL = [&] { - const auto it = mSubmitted.find(graphicBufferId); + const auto it = mSubmitted.find(id); return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL; }(); const auto numPendingBuffersToHold = isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0; - mPendingRelease.emplace_back(ReleasedBuffer{graphicBufferId, releaseFence}); + mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence}); // Release all buffers that are beyond the ones that we need to hold while (mPendingRelease.size() > numPendingBuffersToHold) { const auto releaseBuffer = mPendingRelease.front(); mPendingRelease.pop_front(); - auto it = mSubmitted.find(releaseBuffer.bufferId); + auto it = mSubmitted.find(releaseBuffer.callbackId); if (it == mSubmitted.end()) { - BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64, - graphicBufferId); + BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s", + releaseBuffer.callbackId.to_string().c_str()); return; } mNumAcquired--; + BQA_LOGV("released %s", id.to_string().c_str()); mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence); mSubmitted.erase(it); processNextBufferLocked(false /* useNextTransaction */); @@ -428,7 +429,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } mNumAcquired++; - mSubmitted[buffer->getId()] = bufferItem; + mLastAcquiredFrameNumber = bufferItem.mFrameNumber; + ReleaseCallbackId releaseCallbackId(buffer->getId(), mLastAcquiredFrameNumber); + mSubmitted[releaseCallbackId] = bufferItem; bool needsDisconnect = false; mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect); @@ -442,7 +445,6 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { incStrong((void*)transactionCallbackThunk); Rect crop = computeCrop(bufferItem); - mLastAcquiredFrameNumber = bufferItem.mFrameNumber; mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(), bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, bufferItem.mScalingMode, crop); @@ -451,7 +453,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { std::bind(releaseBufferCallbackThunk, wp(this) /* callbackContext */, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); - t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback); + t->setBuffer(mSurfaceControl, buffer, releaseCallbackId, releaseBufferCallback); t->setDataspace(mSurfaceControl, static_cast(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); @@ -510,11 +512,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d" - " graphicBufferId=%" PRIu64, + " graphicBufferId=%" PRIu64 "%s", mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", - static_cast(mPendingTransactions.size()), - bufferItem.mGraphicBuffer->getId()); + static_cast(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(), + bufferItem.mAutoRefresh ? " mAutoRefresh" : ""); } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 17499ecd50..98e8b548bd 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -125,7 +125,7 @@ status_t SurfaceStats::writeToParcel(Parcel* output) const { for (const auto& data : jankData) { SAFE_PARCEL(output->writeParcelable, data); } - SAFE_PARCEL(output->writeUint64, previousBufferId); + SAFE_PARCEL(output->writeParcelable, previousReleaseCallbackId); return NO_ERROR; } @@ -149,7 +149,7 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) { SAFE_PARCEL(input->readParcelable, &data); jankData.push_back(data); } - SAFE_PARCEL(input->readUint64, &previousBufferId); + SAFE_PARCEL(input->readParcelable, &previousReleaseCallbackId); return NO_ERROR; } @@ -253,11 +253,11 @@ public: stats); } - void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence, uint32_t transformHint, - uint32_t currentMaxAcquiredBufferCount) override { + void onReleaseBuffer(ReleaseCallbackId callbackId, sp releaseFence, + uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override { callRemoteAsync(Tag::ON_RELEASE_BUFFER, - graphicBufferId, releaseFence, + callbackId, releaseFence, transformHint, currentMaxAcquiredBufferCount); } @@ -308,4 +308,18 @@ status_t CallbackId::readFromParcel(const Parcel* input) { return NO_ERROR; } +status_t ReleaseCallbackId::writeToParcel(Parcel* output) const { + SAFE_PARCEL(output->writeUint64, bufferId); + SAFE_PARCEL(output->writeUint64, framenumber); + return NO_ERROR; +} + +status_t ReleaseCallbackId::readFromParcel(const Parcel* input) { + SAFE_PARCEL(input->readUint64, &bufferId); + SAFE_PARCEL(input->readUint64, &framenumber); + return NO_ERROR; +} + +const ReleaseCallbackId ReleaseCallbackId::INVALID_ID = ReleaseCallbackId(0, 0); + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index fd78309462..6ea070ea2f 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -197,15 +197,16 @@ void TransactionCompletedListener::removeJankListener(const sp } } -void TransactionCompletedListener::setReleaseBufferCallback(uint64_t graphicBufferId, +void TransactionCompletedListener::setReleaseBufferCallback(const ReleaseCallbackId& callbackId, ReleaseBufferCallback listener) { std::scoped_lock lock(mMutex); - mReleaseBufferCallbacks[graphicBufferId] = listener; + mReleaseBufferCallbacks[callbackId] = listener; } -void TransactionCompletedListener::removeReleaseBufferCallback(uint64_t graphicBufferId) { +void TransactionCompletedListener::removeReleaseBufferCallback( + const ReleaseCallbackId& callbackId) { std::scoped_lock lock(mMutex); - mReleaseBufferCallbacks.erase(graphicBufferId); + mReleaseBufferCallbacks.erase(callbackId); } void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, @@ -319,14 +320,15 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener // and call them. This is a performance optimization when we have a transaction // callback and a release buffer callback happening at the same time to avoid an // additional ipc call from the server. - if (surfaceStats.previousBufferId) { + if (surfaceStats.previousReleaseCallbackId != ReleaseCallbackId::INVALID_ID) { ReleaseBufferCallback callback; { std::scoped_lock lock(mMutex); - callback = popReleaseBufferCallbackLocked(surfaceStats.previousBufferId); + callback = popReleaseBufferCallbackLocked( + surfaceStats.previousReleaseCallbackId); } if (callback) { - callback(surfaceStats.previousBufferId, + callback(surfaceStats.previousReleaseCallbackId, surfaceStats.previousReleaseFence ? surfaceStats.previousReleaseFence : Fence::NO_FENCE, @@ -362,25 +364,26 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } } -void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence, - uint32_t transformHint, +void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, + sp releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) { ReleaseBufferCallback callback; { std::scoped_lock lock(mMutex); - callback = popReleaseBufferCallbackLocked(graphicBufferId); + callback = popReleaseBufferCallbackLocked(callbackId); } if (!callback) { - ALOGE("Could not call release buffer callback, buffer not found %" PRIu64, graphicBufferId); + ALOGE("Could not call release buffer callback, buffer not found %s", + callbackId.to_string().c_str()); return; } - callback(graphicBufferId, releaseFence, transformHint, currentMaxAcquiredBufferCount); + callback(callbackId, releaseFence, transformHint, currentMaxAcquiredBufferCount); } ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( - uint64_t graphicBufferId) { + const ReleaseCallbackId& callbackId) { ReleaseBufferCallback callback; - auto itr = mReleaseBufferCallbacks.find(graphicBufferId); + auto itr = mReleaseBufferCallbacks.find(callbackId); if (itr == mReleaseBufferCallbacks.end()) { return nullptr; } @@ -1258,7 +1261,7 @@ SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp& sc, const sp& buffer, + const sp& sc, const sp& buffer, const ReleaseCallbackId& id, ReleaseBufferCallback callback) { layer_state_t* s = getLayerState(sc); if (!s) { @@ -1271,7 +1274,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe if (mIsAutoTimestamp) { mDesiredPresentTime = systemTime(); } - setReleaseBufferCallback(s, callback); + setReleaseBufferCallback(s, id, callback); registerSurfaceControlForCallback(sc); @@ -1286,10 +1289,13 @@ void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state s->what &= ~static_cast(layer_state_t::eReleaseBufferListenerChanged); s->releaseBufferListener = nullptr; - TransactionCompletedListener::getInstance()->removeReleaseBufferCallback(s->buffer->getId()); + auto listener = TransactionCompletedListener::getInstance(); + listener->removeReleaseBufferCallback(s->releaseCallbackId); + s->releaseCallbackId = ReleaseCallbackId::INVALID_ID; } void SurfaceComposerClient::Transaction::setReleaseBufferCallback(layer_state_t* s, + const ReleaseCallbackId& id, ReleaseBufferCallback callback) { if (!callback) { return; @@ -1303,8 +1309,9 @@ void SurfaceComposerClient::Transaction::setReleaseBufferCallback(layer_state_t* s->what |= layer_state_t::eReleaseBufferListenerChanged; s->releaseBufferListener = TransactionCompletedListener::getIInstance(); + s->releaseCallbackId = id; auto listener = TransactionCompletedListener::getInstance(); - listener->setReleaseBufferCallback(s->buffer->getId(), callback); + listener->setReleaseBufferCallback(id, callback); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence( diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 26c7285ab0..0d6a673b02 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -89,7 +89,7 @@ public: void transactionCallback(nsecs_t latchTime, const sp& presentFence, const std::vector& stats); - void releaseBufferCallback(uint64_t graphicBufferId, const sp& releaseFence, + void releaseBufferCallback(const ReleaseCallbackId& id, const sp& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); @@ -144,13 +144,14 @@ private: // Keep a reference to the submitted buffers so we can release when surfaceflinger drops the // buffer or the buffer has been presented and a new buffer is ready to be presented. - std::unordered_map mSubmitted GUARDED_BY(mMutex); + std::unordered_map mSubmitted + GUARDED_BY(mMutex); // Keep a queue of the released buffers instead of immediately releasing // the buffers back to the buffer queue. This would be controlled by SF // setting the max acquired buffer count. struct ReleasedBuffer { - uint64_t bufferId; + ReleaseCallbackId callbackId; sp releaseFence; }; std::deque mPendingRelease GUARDED_BY(mMutex); diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index d286c34ec8..937095c543 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -53,6 +53,36 @@ struct CallbackIdHash { std::size_t operator()(const CallbackId& key) const { return std::hash()(key.id); } }; +class ReleaseCallbackId : public Parcelable { +public: + static const ReleaseCallbackId INVALID_ID; + + uint64_t bufferId; + uint64_t framenumber; + ReleaseCallbackId() {} + ReleaseCallbackId(uint64_t bufferId, uint64_t framenumber) + : bufferId(bufferId), framenumber(framenumber) {} + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + bool operator==(const ReleaseCallbackId& rhs) const { + return bufferId == rhs.bufferId && framenumber == rhs.framenumber; + } + bool operator!=(const ReleaseCallbackId& rhs) const { return !operator==(rhs); } + std::string to_string() const { + if (*this == INVALID_ID) return "INVALID_ID"; + + return "bufferId:" + std::to_string(bufferId) + + " framenumber:" + std::to_string(framenumber); + } +}; + +struct ReleaseBufferCallbackIdHash { + std::size_t operator()(const ReleaseCallbackId& key) const { + return std::hash()(key.bufferId); + } +}; + class FrameEventHistoryStats : public Parcelable { public: status_t writeToParcel(Parcel* output) const override; @@ -103,7 +133,7 @@ public: SurfaceStats(const sp& sc, nsecs_t time, const sp& prevReleaseFence, uint32_t hint, uint32_t currentMaxAcquiredBuffersCount, FrameEventHistoryStats frameEventStats, std::vector jankData, - uint64_t previousBufferId) + ReleaseCallbackId previousReleaseCallbackId) : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence), @@ -111,7 +141,7 @@ public: currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount), eventStats(frameEventStats), jankData(std::move(jankData)), - previousBufferId(previousBufferId) {} + previousReleaseCallbackId(previousReleaseCallbackId) {} sp surfaceControl; nsecs_t acquireTime = -1; @@ -120,7 +150,7 @@ public: uint32_t currentMaxAcquiredBufferCount = 0; FrameEventHistoryStats eventStats; std::vector jankData; - uint64_t previousBufferId; + ReleaseCallbackId previousReleaseCallbackId; }; class TransactionStats : public Parcelable { @@ -161,7 +191,7 @@ public: virtual void onTransactionCompleted(ListenerStats stats) = 0; - virtual void onReleaseBuffer(uint64_t graphicBufferId, sp releaseFence, + virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) = 0; }; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 16430b324d..8ac1e5d9e9 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -234,6 +234,12 @@ struct layer_state_t { // layers only. The callback includes a release fence as well as the graphic // buffer id to identify the buffer. sp releaseBufferListener; + + // Keeps track of the release callback id associated with the listener. This + // is not sent to the server since the id can be reconstructed there. This + // is used to remove the old callback from the client process map if it is + // overwritten by another setBuffer call. + ReleaseCallbackId releaseCallbackId; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 13994fd9eb..c2963b58df 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -82,7 +82,7 @@ using TransactionCompletedCallback = std::function& /*presentFence*/, const std::vector& /*stats*/)>; using ReleaseBufferCallback = - std::function& /*releaseFence*/, + std::function& /*releaseFence*/, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount)>; using SurfaceStatsCallback = @@ -397,8 +397,9 @@ public: void cacheBuffers(); void registerSurfaceControlForCallback(const sp& sc); - void setReleaseBufferCallback(layer_state_t* state, ReleaseBufferCallback callback); - void removeReleaseBufferCallback(layer_state_t* state); + void setReleaseBufferCallback(layer_state_t*, const ReleaseCallbackId&, + ReleaseBufferCallback); + void removeReleaseBufferCallback(layer_state_t*); public: Transaction(); @@ -470,6 +471,7 @@ public: Transaction& setTransformToDisplayInverse(const sp& sc, bool transformToDisplayInverse); Transaction& setBuffer(const sp& sc, const sp& buffer, + const ReleaseCallbackId& id = ReleaseCallbackId::INVALID_ID, ReleaseBufferCallback callback = nullptr); Transaction& setCachedBuffer(const sp& sc, int32_t bufferId); Transaction& setAcquireFence(const sp& sc, const sp& fence); @@ -678,7 +680,7 @@ class TransactionCompletedListener : public BnTransactionCompletedListener { std::unordered_map mCallbacks GUARDED_BY(mMutex); std::multimap, sp> mJankListeners GUARDED_BY(mMutex); - std::unordered_map + std::unordered_map mReleaseBufferCallbacks GUARDED_BY(mMutex); // This is protected by mSurfaceStatsListenerMutex, but GUARDED_BY isn't supported for @@ -717,16 +719,16 @@ public: SurfaceStatsCallback listener); void removeSurfaceStatsListener(void* context, void* cookie); - void setReleaseBufferCallback(uint64_t /* graphicsBufferId */, ReleaseBufferCallback); - void removeReleaseBufferCallback(uint64_t /* graphicsBufferId */); + void setReleaseBufferCallback(const ReleaseCallbackId&, ReleaseBufferCallback); + void removeReleaseBufferCallback(const ReleaseCallbackId&); // BnTransactionCompletedListener overrides void onTransactionCompleted(ListenerStats stats) override; - void onReleaseBuffer(uint64_t /* graphicsBufferId */, sp releaseFence, - uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override; + void onReleaseBuffer(ReleaseCallbackId, sp releaseFence, uint32_t transformHint, + uint32_t currentMaxAcquiredBufferCount) override; private: - ReleaseBufferCallback popReleaseBufferCallbackLocked(uint64_t /* graphicsBufferId */); + ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&); }; } // namespace android diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index cd3d80e809..760c8b9f3c 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -133,6 +133,7 @@ protected: bool mTransformToDisplayInverse{false}; std::shared_ptr mBuffer; + uint64_t mFrameNumber; int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; bool mFrameLatencyNeeded{false}; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 6b5cf04536..8cf0d66a08 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -44,25 +44,18 @@ namespace android { using PresentState = frametimeline::SurfaceFrame::PresentState; namespace { void callReleaseBufferCallback(const sp& listener, - const sp& buffer, const sp& releaseFence, - uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) { + const sp& buffer, uint64_t framenumber, + const sp& releaseFence, uint32_t transformHint, + uint32_t currentMaxAcquiredBufferCount) { if (!listener) { return; } - listener->onReleaseBuffer(buffer->getId(), releaseFence ? releaseFence : Fence::NO_FENCE, - transformHint, currentMaxAcquiredBufferCount); + listener->onReleaseBuffer({buffer->getId(), framenumber}, + releaseFence ? releaseFence : Fence::NO_FENCE, transformHint, + currentMaxAcquiredBufferCount); } } // namespace -// clang-format off -const std::array BufferStateLayer::IDENTITY_MATRIX{ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 -}; -// clang-format on - BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) : BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) { mDrawingState.dataspace = ui::Dataspace::V0_SRGB; @@ -75,8 +68,8 @@ BufferStateLayer::~BufferStateLayer() { // issue with the clone layer trying to use the texture. if (mBufferInfo.mBuffer != nullptr && !isClone()) { callReleaseBufferCallback(mDrawingState.releaseBufferListener, - mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence, - mTransformHint, + mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber, + mBufferInfo.mFence, mTransformHint, mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( mOwnerUid)); } @@ -87,7 +80,7 @@ status_t BufferStateLayer::addReleaseFence(const sp& ch, if (ch == nullptr) { return OK; } - ch->previousBufferId = mPreviousBufferId; + ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; if (!ch->previousReleaseFence.get()) { ch->previousReleaseFence = fence; return OK; @@ -214,7 +207,7 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { // see BufferStateLayer::onLayerDisplayed. for (auto& handle : mDrawingState.callbackHandles) { if (handle->releasePreviousBuffer) { - handle->previousBufferId = mPreviousBufferId; + handle->previousReleaseCallbackId = mPreviousReleaseCallbackId; break; } } @@ -438,8 +431,8 @@ bool BufferStateLayer::setBuffer(const std::shared_ptrgetBuffer(), mDrawingState.acquireFence, - mTransformHint, + mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, + mDrawingState.acquireFence, mTransformHint, mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( mOwnerUid)); decrementPendingBufferCount(); @@ -684,7 +677,7 @@ uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const * DeferTransactionUntil -> frameNumber = 2 * Random other stuff * } - * Now imagine getHeadFrameNumber returned mDrawingState.mFrameNumber (or mCurrentFrameNumber). + * Now imagine mFrameNumber returned mDrawingState.frameNumber (or mCurrentFrameNumber). * Prior to doTransaction SurfaceFlinger will call notifyAvailableFrames, but because we * haven't swapped mDrawingState to mDrawingState yet we will think the sync point * is not ready. So we will return false from applyPendingState and not swap @@ -792,9 +785,10 @@ status_t BufferStateLayer::updateActiveBuffer() { decrementPendingBufferCount(); } - mPreviousBufferId = getCurrentBufferId(); + mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber}; mBufferInfo.mBuffer = s.buffer; mBufferInfo.mFence = s.acquireFence; + mBufferInfo.mFrameNumber = s.frameNumber; return NO_ERROR; } @@ -969,8 +963,8 @@ void BufferStateLayer::bufferMayChange(const sp& newBuffer) { // then we will drop a buffer and should decrement the pending buffer count and // call any release buffer callbacks if set. callReleaseBufferCallback(mDrawingState.releaseBufferListener, - mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence, - mTransformHint, + mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, + mDrawingState.acquireFence, mTransformHint, mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( mOwnerUid)); decrementPendingBufferCount(); diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 27470182bf..e5674785af 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -143,15 +143,8 @@ private: bool bufferNeedsFiltering() const override; - static const std::array IDENTITY_MATRIX; - - std::unique_ptr mTextureImage; - - mutable uint64_t mFrameNumber{0}; - uint64_t mFrameCounter{0}; - sp mPreviousReleaseFence; - uint64_t mPreviousBufferId = 0; + ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; uint64_t mPreviousReleasedFrameNumber = 0; bool mReleasePreviousBuffer = false; diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index fdf16a797f..6af69f0ef2 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -237,7 +237,8 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp& handle->previousReleaseFence, handle->transformHint, handle->currentMaxAcquiredBufferCount, - eventStats, jankData, handle->previousBufferId); + eventStats, jankData, + handle->previousReleaseCallbackId); } return NO_ERROR; } diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 444bec646e..6f4d812ec5 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -51,7 +51,7 @@ public: nsecs_t refreshStartTime = 0; nsecs_t dequeueReadyTime = 0; uint64_t frameNumber = 0; - uint64_t previousBufferId = 0; + ReleaseCallbackId previousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; }; class TransactionCallbackInvoker { diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp index 5aa809dc8b..579a26ebf4 100644 --- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp +++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp @@ -29,7 +29,7 @@ using android::hardware::graphics::common::V1_1::BufferUsage; // b/181132765 - disabled until cuttlefish failures are investigated class ReleaseBufferCallbackHelper { public: - static void function(void* callbackContext, uint64_t graphicsBufferId, + static void function(void* callbackContext, ReleaseCallbackId callbackId, const sp& releaseFence, uint32_t /*currentMaxAcquiredBufferCount*/) { if (!callbackContext) { @@ -38,11 +38,11 @@ public: ReleaseBufferCallbackHelper* helper = static_cast(callbackContext); std::lock_guard lock(helper->mMutex); - helper->mCallbackDataQueue.emplace(graphicsBufferId, releaseFence); + helper->mCallbackDataQueue.emplace(callbackId, releaseFence); helper->mConditionVariable.notify_all(); } - void getCallbackData(uint64_t* bufferId) { + void getCallbackData(ReleaseCallbackId* callbackId) { std::unique_lock lock(mMutex); if (mCallbackDataQueue.empty()) { if (!mConditionVariable.wait_for(lock, std::chrono::seconds(3), @@ -53,7 +53,7 @@ public: auto callbackData = mCallbackDataQueue.front(); mCallbackDataQueue.pop(); - *bufferId = callbackData.first; + *callbackId = callbackData.first; } void verifyNoCallbacks() { @@ -72,7 +72,7 @@ public: std::mutex mMutex; std::condition_variable mConditionVariable; - std::queue>> mCallbackDataQueue; + std::queue>> mCallbackDataQueue; }; class ReleaseBufferCallbackTest : public LayerTransactionTest { @@ -82,10 +82,11 @@ public: } static void submitBuffer(const sp& layer, sp buffer, - sp fence, CallbackHelper& callback, + sp fence, CallbackHelper& callback, const ReleaseCallbackId& id, ReleaseBufferCallbackHelper& releaseCallback) { Transaction t; - t.setBuffer(layer, buffer, releaseCallback.getCallback()); + t.setFrameNumber(layer, id.framenumber); + t.setBuffer(layer, buffer, id, releaseCallback.getCallback()); t.setAcquireFence(layer, fence); t.addTransactionCompletedCallback(callback.function, callback.getContext()); t.apply(); @@ -98,10 +99,10 @@ public: } static void waitForReleaseBufferCallback(ReleaseBufferCallbackHelper& releaseCallback, - uint64_t expectedReleaseBufferId) { - uint64_t actualReleaseBufferId; + const ReleaseCallbackId& expectedCallbackId) { + ReleaseCallbackId actualReleaseBufferId; releaseCallback.getCallbackData(&actualReleaseBufferId); - EXPECT_EQ(expectedReleaseBufferId, actualReleaseBufferId); + EXPECT_EQ(expectedCallbackId, actualReleaseBufferId); releaseCallback.verifyNoCallbacks(); } static ReleaseBufferCallbackHelper* getReleaseBufferCallbackHelper() { @@ -116,6 +117,10 @@ public: BufferUsage::COMPOSER_OVERLAY, "test"); } + static uint64_t generateFrameNumber() { + static uint64_t sFrameNumber = 0; + return ++sFrameNumber; + } }; TEST_F(ReleaseBufferCallbackTest, DISABLED_PresentBuffer) { @@ -125,7 +130,9 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_PresentBuffer) { // If a buffer is being presented, we should not emit a release callback. sp firstBuffer = getBuffer(); - submitBuffer(layer, firstBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber()); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, transactionCallback, firstBufferCallbackId, + *releaseCallback); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, ExpectedResult::Buffer::NOT_ACQUIRED); @@ -143,13 +150,15 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_PresentBuffer) { // If a presented buffer is replaced, we should emit a release callback for the // previously presented buffer. sp secondBuffer = getBuffer(); - submitBuffer(layer, secondBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); + submitBuffer(layer, secondBuffer, Fence::NO_FENCE, transactionCallback, secondBufferCallbackId, + *releaseCallback); expected = ExpectedResult(); expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, ExpectedResult::Buffer::NOT_ACQUIRED, ExpectedResult::PreviousBuffer::RELEASED); ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); - ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); } TEST_F(ReleaseBufferCallbackTest, DISABLED_OffScreenLayer) { @@ -160,7 +169,9 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_OffScreenLayer) { // If a buffer is being presented, we should not emit a release callback. sp firstBuffer = getBuffer(); - submitBuffer(layer, firstBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber()); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, transactionCallback, firstBufferCallbackId, + *releaseCallback); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, ExpectedResult::Buffer::NOT_ACQUIRED); @@ -184,23 +195,27 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_OffScreenLayer) { // If a presented buffer is replaced, we should emit a release callback for the // previously presented buffer. sp secondBuffer = getBuffer(); - submitBuffer(layer, secondBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); + submitBuffer(layer, secondBuffer, Fence::NO_FENCE, transactionCallback, secondBufferCallbackId, + *releaseCallback); expected = ExpectedResult(); expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, ExpectedResult::Buffer::NOT_ACQUIRED, ExpectedResult::PreviousBuffer::NOT_RELEASED); ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); - ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); // If continue to submit buffer we continue to get release callbacks sp thirdBuffer = getBuffer(); - submitBuffer(layer, thirdBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback); + ReleaseCallbackId thirdBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); + submitBuffer(layer, thirdBuffer, Fence::NO_FENCE, transactionCallback, thirdBufferCallbackId, + *releaseCallback); expected = ExpectedResult(); expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, ExpectedResult::Buffer::NOT_ACQUIRED, ExpectedResult::PreviousBuffer::NOT_RELEASED); ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); - ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, secondBuffer->getId())); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, secondBufferCallbackId)); } TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_layerdestroy) { @@ -210,7 +225,9 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_layerdestroy) { // If a buffer is being presented, we should not emit a release callback. sp firstBuffer = getBuffer(); - submitBuffer(layer, firstBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback); + ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber()); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, *transactionCallback, firstBufferCallbackId, + *releaseCallback); { ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, @@ -225,7 +242,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_layerdestroy) { t.apply(); layer = nullptr; - ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); } // Destroying a never presented layer emits a callback. @@ -242,7 +259,9 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_OffScreenLayerDestroy) // Submitting a buffer does not emit a callback. sp firstBuffer = getBuffer(); - submitBuffer(layer, firstBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback); + ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber()); + submitBuffer(layer, firstBuffer, Fence::NO_FENCE, *transactionCallback, firstBufferCallbackId, + *releaseCallback); { ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, @@ -253,19 +272,21 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_OffScreenLayerDestroy) // Submitting a second buffer will replace the drawing state buffer and emit a callback. sp secondBuffer = getBuffer(); - submitBuffer(layer, secondBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback); + ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); + submitBuffer(layer, secondBuffer, Fence::NO_FENCE, *transactionCallback, secondBufferCallbackId, + *releaseCallback); { ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, ExpectedResult::Buffer::NOT_ACQUIRED); ASSERT_NO_FATAL_FAILURE(waitForCallback(*transactionCallback, expected)); ASSERT_NO_FATAL_FAILURE( - waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); + waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); } // Destroying the offscreen layer emits a callback. layer = nullptr; - ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, secondBuffer->getId())); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, secondBufferCallbackId)); } TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { @@ -275,12 +296,13 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { // If a buffer is being presented, we should not emit a release callback. sp firstBuffer = getBuffer(); + ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber()); // Try to present 100ms in the future nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count(); Transaction t; - t.setBuffer(layer, firstBuffer, releaseCallback->getCallback()); + t.setBuffer(layer, firstBuffer, firstBufferCallbackId, releaseCallback->getCallback()); t.setAcquireFence(layer, Fence::NO_FENCE); t.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()); @@ -295,7 +317,8 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { // Dropping frames in transaction queue emits a callback sp secondBuffer = getBuffer(); - t.setBuffer(layer, secondBuffer, releaseCallback->getCallback()); + ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); + t.setBuffer(layer, secondBuffer, secondBufferCallbackId, releaseCallback->getCallback()); t.setAcquireFence(layer, Fence::NO_FENCE); t.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()); @@ -307,7 +330,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { ExpectedResult::Buffer::NOT_ACQUIRED, ExpectedResult::PreviousBuffer::RELEASED); ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected)); - ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId())); + ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); } } // namespace android -- cgit v1.2.3-59-g8ed1b From 5fa91c276a6f67a33effceee27ef91d2cd935002 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 29 Jun 2021 14:30:48 -0700 Subject: BBQ: Update the transform hint if the SC layer handle does not change We are now passing the transform hint from WM to the client. In BBQ, we were not getting the updated transform hint in some cases because we did not update the SurfaceControl if the layer handle was the same. Fix this by always updating the SC object in BBQ. Test: rotate phone with messages app and check buffer transforms Fixes: 184842607 Change-Id: I83158f810a9820285c84ecfff294689f63ff3113 --- libs/gui/BLASTBufferQueue.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 29701168e7..ac8feaa0c2 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -197,15 +197,18 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, } SurfaceComposerClient::Transaction t; + const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface); bool applyTransaction = false; - if (!SurfaceControl::isSameSurface(mSurfaceControl, surface)) { - mSurfaceControl = surface; - t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, - layer_state_t::eEnableBackpressure); - applyTransaction = true; - } + // Always update the native object even though they might have the same layer handle, so we can + // get the updated transform hint from WM. + mSurfaceControl = surface; if (mSurfaceControl != nullptr) { + if (setBackpressureFlag) { + t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, + layer_state_t::eEnableBackpressure); + applyTransaction = true; + } mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); } @@ -221,7 +224,7 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, // We only need to update the scale if we've received at least one buffer. The reason // for this is the scale is calculated based on the requested size and buffer size. // If there's no buffer, the scale will always be 1. - if (mLastBufferInfo.hasBuffer) { + if (mSurfaceControl != nullptr && mLastBufferInfo.hasBuffer) { t.setDestinationFrame(mSurfaceControl, Rect(0, 0, newSize.getWidth(), newSize.getHeight())); } -- cgit v1.2.3-59-g8ed1b From 9c16128241425c91249379aacc3bca31d04ef12f Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 7 Jul 2021 16:52:34 -0700 Subject: BlastBufferQueue: Keep transform hint in Surface consistent We should only update the transform hint in Surface when connecting to the queue or queuing a buffer. Otherwise, the transform hint value used when dequeuing the buffer will not align with the value queried from the Surface. This inconsistency was causing BBQ to reject buffers and we suspect this was causing an issue where BBQ will remain in this inconsistent state rejecting all buffers until the app changed orientation. Test: rotate device, check for rejected buffers, run through scenario in bug Bug: b/191841127 Change-Id: Id84a3a650ce68878e5638b942249c11558fd29eb Merged-In: Id84a3a650ce68878e5638b942249c11558fd29eb --- libs/gui/BLASTBufferQueue.cpp | 21 +++++++-------- libs/gui/tests/BLASTBufferQueue_test.cpp | 46 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 12 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index ac8feaa0c2..7d57d8b02c 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -171,6 +171,8 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp& surface, uint32_t width, uint32_t height, int32_t format) { std::unique_lock _lock{mMutex}; - BQA_LOGV("update width=%d height=%d format=%d", width, height, format); if (mFormat != format) { mFormat = format; mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format)); @@ -212,6 +213,8 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); } + BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format, + mTransformHint); ui::Size newSize(width, height); if (mRequestedSize != newSize) { @@ -267,6 +270,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const spsetTransformHint(mTransformHint); + BQA_LOGV("updated mTransformHint=%d", mTransformHint); // Update frametime stamps if the frame was latched and presented, indicated by a // valid latch time. if (stat.latchTime > 0) { @@ -339,6 +343,7 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, mTransformHint = transformHint; mSurfaceControl->setTransformHint(transformHint); mBufferItemConsumer->setTransformHint(mTransformHint); + BQA_LOGV("updated mTransformHint=%d", mTransformHint); } // Calculate how many buffers we need to hold before we release them back @@ -422,7 +427,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } if (rejectBuffer(bufferItem)) { - BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d" + BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d " "buffer{size=%dx%d transform=%d}", mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform); @@ -515,11 +520,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d" - " graphicBufferId=%" PRIu64 "%s", + " graphicBufferId=%" PRIu64 "%s transform=%d", mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", static_cast(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(), - bufferItem.mAutoRefresh ? " mAutoRefresh" : ""); + bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform); } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { @@ -646,14 +651,6 @@ public: status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override { return mBbq->setFrameTimelineInfo(frameTimelineInfo); } - protected: - uint32_t getTransformHint() const override { - if (mStickyTransform == 0 && !transformToDisplayInverse()) { - return mBbq->getLastTransformHint(); - } else { - return 0; - } - } }; // TODO: Can we coalesce this with frame updates? Need to confirm diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 6ff67aa7cb..9082d275a2 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -71,6 +71,10 @@ public: return mBlastBufferQueueAdapter->mSurfaceControl; } + sp getSurface() { + return mBlastBufferQueueAdapter->getSurface(false /* includeSurfaceControlHandle */); + } + void waitForCallbacks() { std::unique_lock lock{mBlastBufferQueueAdapter->mMutex}; // Wait until all but one of the submitted buffers have been released. @@ -758,6 +762,48 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); } +TEST_F(BLASTBufferQueueTest, TransformHint) { + // Transform hint is provided to BBQ via the surface control passed by WM + mSurfaceControl->setTransformHint(ui::Transform::ROT_90); + + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp igbProducer = adapter.getIGraphicBufferProducer(); + ASSERT_NE(nullptr, igbProducer.get()); + ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2)); + sp surface = adapter.getSurface(); + + // Before connecting to the surface, we do not get a valid transform hint + int transformHint; + surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint); + ASSERT_EQ(ui::Transform::ROT_0, transformHint); + + ASSERT_EQ(NO_ERROR, + surface->connect(NATIVE_WINDOW_API_CPU, new TestProducerListener(igbProducer))); + + // After connecting to the surface, we should get the correct hint. + surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint); + ASSERT_EQ(ui::Transform::ROT_90, transformHint); + + ANativeWindow_Buffer buffer; + surface->lock(&buffer, nullptr /* inOutDirtyBounds */); + + // Transform hint is updated via callbacks or surface control updates + mSurfaceControl->setTransformHint(ui::Transform::ROT_0); + adapter.update(mSurfaceControl, mDisplayWidth, mDisplayHeight); + + // The hint does not change and matches the value used when dequeueing the buffer. + surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint); + ASSERT_EQ(ui::Transform::ROT_90, transformHint); + + surface->unlockAndPost(); + + // After queuing the buffer, we get the updated transform hint + surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint); + ASSERT_EQ(ui::Transform::ROT_0, transformHint); + + adapter.waitForCallbacks(); +} + class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { public: void test(uint32_t tr) { -- cgit v1.2.3-59-g8ed1b From 084514aadca64e44b49eac584a89fef887fbb30c Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 30 Jul 2021 16:07:42 -0700 Subject: SurfaceView: Synchronize destframe updates with SurfaceView size changes This CL fixes one of the issues with SurfaceView parent frame and content syncing. With BLAST, we have two surface controls each setting a scale. The parent surface control sets a scale based on the requested surface size and the SurfaceView layout size. The BlastBufferQueue surface control scales the buffer to the requested buffer size if the buffer has the appropriate scale mode. The destination frame controls the second scaling and it must be applied with the parent surface scale changes. This cl fixes flickers where the requested fixed surface size changes without any view size changes. This cl allows the caller to pass in a transaction to BLASTBufferQueue#update which is updated with the destination frame changes. This transaction can then be applied with the parent surface changes. This also fixes an issue where destination Frame was being set on every buffer update and when we updated the BlastBufferQueue size. Since buffer transactions can be queued up on the server side, a stale value maybe applied for a few frames causing flickers. Fixes: 194458377 Test: bug repro steps Test: atest SurfaceViewSyncTest#testSurfaceViewSetFixedSize Change-Id: I216586842ff45bfd398659b5cc0c89eaf51394ff --- libs/gui/BLASTBufferQueue.cpp | 25 +++++++++++++++++-------- libs/gui/include/gui/BLASTBufferQueue.h | 3 ++- 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'libs/gui/BLASTBufferQueue.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 7d57d8b02c..56a9683773 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -166,9 +166,10 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spgetTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); SurfaceComposerClient::Transaction() - .setFlags(surface, layer_state_t::eEnableBackpressure, - layer_state_t::eEnableBackpressure) - .apply(); + .setFlags(surface, layer_state_t::eEnableBackpressure, + layer_state_t::eEnableBackpressure) + .setApplyToken(mApplyToken) + .apply(); mNumAcquired = 0; mNumFrameAvailable = 0; BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width, @@ -190,7 +191,7 @@ BLASTBufferQueue::~BLASTBufferQueue() { } void BLASTBufferQueue::update(const sp& surface, uint32_t width, uint32_t height, - int32_t format) { + int32_t format, SurfaceComposerClient::Transaction* outTransaction) { std::unique_lock _lock{mMutex}; if (mFormat != format) { mFormat = format; @@ -227,15 +228,18 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, // We only need to update the scale if we've received at least one buffer. The reason // for this is the scale is calculated based on the requested size and buffer size. // If there's no buffer, the scale will always be 1. + SurfaceComposerClient::Transaction* destFrameTransaction = + (outTransaction) ? outTransaction : &t; if (mSurfaceControl != nullptr && mLastBufferInfo.hasBuffer) { - t.setDestinationFrame(mSurfaceControl, - Rect(0, 0, newSize.getWidth(), newSize.getHeight())); + destFrameTransaction->setDestinationFrame(mSurfaceControl, + Rect(0, 0, newSize.getWidth(), + newSize.getHeight())); } applyTransaction = true; } } if (applyTransaction) { - t.apply(); + t.setApplyToken(mApplyToken).apply(); } } @@ -453,6 +457,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { incStrong((void*)transactionCallbackThunk); Rect crop = computeCrop(bufferItem); + const bool updateDestinationFrame = + bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE || + !mLastBufferInfo.hasBuffer; mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(), bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, bufferItem.mScalingMode, crop); @@ -470,7 +477,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); mSurfaceControlsWithPendingCallback.push(mSurfaceControl); - t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight())); + if (updateDestinationFrame) { + t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight())); + } t->setBufferCrop(mSurfaceControl, crop); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 0d6a673b02..ea9b1c68af 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -96,7 +96,8 @@ public: void setTransactionCompleteCallback(uint64_t frameNumber, std::function&& transactionCompleteCallback); - void update(const sp& surface, uint32_t width, uint32_t height, int32_t format); + void update(const sp& surface, uint32_t width, uint32_t height, int32_t format, + SurfaceComposerClient::Transaction* outTransaction = nullptr); void flushShadowQueue() {} status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); -- cgit v1.2.3-59-g8ed1b