Loading libs/gui/BLASTBufferQueue.cpp +60 −47 Original line number Diff line number Diff line Loading @@ -169,8 +169,6 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont mNumAcquired = 0; mNumFrameAvailable = 0; mPendingReleaseItem.item = BufferItem(); mPendingReleaseItem.releaseFence = nullptr; } BLASTBufferQueue::~BLASTBufferQueue() { Loading Loading @@ -242,7 +240,6 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence std::unique_lock _lock{mMutex}; ATRACE_CALL(); BQA_LOGV("transactionCallback"); mInitialCallbackReceived = true; if (!stats.empty()) { mTransformHint = stats[0].transformHint; Loading @@ -255,38 +252,20 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence 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; } currFrameNumber = stats[0].frameEventStats.frameNumber; if (mSubmitted.empty()) { BQA_LOGE("ERROR: callback with no corresponding submitted buffer item"); if (mTransactionCompleteCallback && currFrameNumber >= mTransactionCompleteFrameNumber) { if (currFrameNumber > mTransactionCompleteFrameNumber) { BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64 " than expected=%" PRIu64, currFrameNumber, mTransactionCompleteFrameNumber); } 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); } Loading @@ -295,15 +274,46 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence } } void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { // Unlike transactionCallbackThunk the release buffer callback does not extend the life of the // BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client. // So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer. // Otherwise, this is a no-op. static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, uint64_t graphicBufferId, const sp<Fence>& releaseFence) { sp<BLASTBufferQueue> 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<Fence>& 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; } Loading Loading @@ -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); Loading @@ -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<BLASTBufferQueue>(this) /* callbackContext */, std::placeholders::_1, std::placeholders::_2); t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback); t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); Loading Loading @@ -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<uint32_t>(mPendingTransactions.size())); bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId()); } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { Loading @@ -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 */); } Loading Loading @@ -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 { Loading libs/gui/ITransactionCompletedListener.cpp +12 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; } Loading @@ -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; } Loading Loading @@ -245,6 +248,12 @@ public: onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED, stats); } void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence) override { callRemoteAsync<decltype( &ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER, graphicBufferId, releaseFence); } }; // Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see Loading @@ -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); } } Loading libs/gui/LayerState.cpp +16 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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<ITransactionCompletedListener>(tmpBinder); } uint32_t numRegions = 0; SAFE_PARCEL(input.readUint32, &numRegions); blurRegions.clear(); Loading Loading @@ -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; Loading libs/gui/SurfaceComposerClient.cpp +83 −1 Original line number Diff line number Diff line Loading @@ -195,6 +195,17 @@ void TransactionCompletedListener::removeJankListener(const sp<JankDataListener> } } void TransactionCompletedListener::setReleaseBufferCallback(uint64_t graphicBufferId, ReleaseBufferCallback listener) { std::scoped_lock<std::mutex> lock(mMutex); mReleaseBufferCallbacks[graphicBufferId] = listener; } void TransactionCompletedListener::removeReleaseBufferCallback(uint64_t graphicBufferId) { std::scoped_lock<std::mutex> lock(mMutex); mReleaseBufferCallbacks.erase(graphicBufferId); } void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) { std::lock_guard<std::mutex> lock(mMutex); Loading Loading @@ -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, Loading @@ -297,6 +322,32 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } } void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence) { ReleaseBufferCallback callback; { std::scoped_lock<std::mutex> 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); Loading Loading @@ -1219,17 +1270,20 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer) { const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& 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); Loading @@ -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<uint64_t>(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<SurfaceControl>& sc, const sp<Fence>& fence) { layer_state_t* s = getLayerState(sc); Loading libs/gui/include/gui/BLASTBufferQueue.h +5 −13 Original line number Diff line number Diff line Loading @@ -89,13 +89,14 @@ public: void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence, const std::vector<SurfaceControlStats>& stats); void releaseBufferCallback(uint64_t graphicBufferId, const sp<Fence>& releaseFence); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void setTransactionCompleteCallback(uint64_t frameNumber, std::function<void(int64_t)>&& transactionCompleteCallback); void update(const sp<SurfaceControl>& 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); Loading Loading @@ -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<Fence> releaseFence; }; std::queue<const BufferItem> 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<uint64_t /* bufferId */, BufferItem> mSubmitted GUARDED_BY(mMutex); ui::Size mSize GUARDED_BY(mMutex); ui::Size mRequestedSize GUARDED_BY(mMutex); Loading @@ -157,9 +152,6 @@ private: std::vector<std::tuple<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>> 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. Loading Loading
libs/gui/BLASTBufferQueue.cpp +60 −47 Original line number Diff line number Diff line Loading @@ -169,8 +169,6 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont mNumAcquired = 0; mNumFrameAvailable = 0; mPendingReleaseItem.item = BufferItem(); mPendingReleaseItem.releaseFence = nullptr; } BLASTBufferQueue::~BLASTBufferQueue() { Loading Loading @@ -242,7 +240,6 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence std::unique_lock _lock{mMutex}; ATRACE_CALL(); BQA_LOGV("transactionCallback"); mInitialCallbackReceived = true; if (!stats.empty()) { mTransformHint = stats[0].transformHint; Loading @@ -255,38 +252,20 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence 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; } currFrameNumber = stats[0].frameEventStats.frameNumber; if (mSubmitted.empty()) { BQA_LOGE("ERROR: callback with no corresponding submitted buffer item"); if (mTransactionCompleteCallback && currFrameNumber >= mTransactionCompleteFrameNumber) { if (currFrameNumber > mTransactionCompleteFrameNumber) { BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64 " than expected=%" PRIu64, currFrameNumber, mTransactionCompleteFrameNumber); } 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); } Loading @@ -295,15 +274,46 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence } } void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { // Unlike transactionCallbackThunk the release buffer callback does not extend the life of the // BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client. // So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer. // Otherwise, this is a no-op. static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, uint64_t graphicBufferId, const sp<Fence>& releaseFence) { sp<BLASTBufferQueue> 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<Fence>& 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; } Loading Loading @@ -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); Loading @@ -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<BLASTBufferQueue>(this) /* callbackContext */, std::placeholders::_1, std::placeholders::_2); t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback); t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); Loading Loading @@ -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<uint32_t>(mPendingTransactions.size())); bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId()); } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { Loading @@ -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 */); } Loading Loading @@ -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 { Loading
libs/gui/ITransactionCompletedListener.cpp +12 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; } Loading @@ -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; } Loading Loading @@ -245,6 +248,12 @@ public: onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED, stats); } void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence) override { callRemoteAsync<decltype( &ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER, graphicBufferId, releaseFence); } }; // Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see Loading @@ -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); } } Loading
libs/gui/LayerState.cpp +16 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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<ITransactionCompletedListener>(tmpBinder); } uint32_t numRegions = 0; SAFE_PARCEL(input.readUint32, &numRegions); blurRegions.clear(); Loading Loading @@ -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; Loading
libs/gui/SurfaceComposerClient.cpp +83 −1 Original line number Diff line number Diff line Loading @@ -195,6 +195,17 @@ void TransactionCompletedListener::removeJankListener(const sp<JankDataListener> } } void TransactionCompletedListener::setReleaseBufferCallback(uint64_t graphicBufferId, ReleaseBufferCallback listener) { std::scoped_lock<std::mutex> lock(mMutex); mReleaseBufferCallbacks[graphicBufferId] = listener; } void TransactionCompletedListener::removeReleaseBufferCallback(uint64_t graphicBufferId) { std::scoped_lock<std::mutex> lock(mMutex); mReleaseBufferCallbacks.erase(graphicBufferId); } void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) { std::lock_guard<std::mutex> lock(mMutex); Loading Loading @@ -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, Loading @@ -297,6 +322,32 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } } void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence) { ReleaseBufferCallback callback; { std::scoped_lock<std::mutex> 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); Loading Loading @@ -1219,17 +1270,20 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer) { const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& 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); Loading @@ -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<uint64_t>(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<SurfaceControl>& sc, const sp<Fence>& fence) { layer_state_t* s = getLayerState(sc); Loading
libs/gui/include/gui/BLASTBufferQueue.h +5 −13 Original line number Diff line number Diff line Loading @@ -89,13 +89,14 @@ public: void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence, const std::vector<SurfaceControlStats>& stats); void releaseBufferCallback(uint64_t graphicBufferId, const sp<Fence>& releaseFence); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void setTransactionCompleteCallback(uint64_t frameNumber, std::function<void(int64_t)>&& transactionCompleteCallback); void update(const sp<SurfaceControl>& 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); Loading Loading @@ -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<Fence> releaseFence; }; std::queue<const BufferItem> 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<uint64_t /* bufferId */, BufferItem> mSubmitted GUARDED_BY(mMutex); ui::Size mSize GUARDED_BY(mMutex); ui::Size mRequestedSize GUARDED_BY(mMutex); Loading @@ -157,9 +152,6 @@ private: std::vector<std::tuple<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>> 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. Loading