Loading libs/gui/BLASTBufferQueue.cpp +14 −18 Original line number Diff line number Diff line Loading @@ -162,6 +162,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers; mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); Loading Loading @@ -325,31 +326,23 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence // 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, const ReleaseCallbackId& id, const sp<Fence>& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) { const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) { sp<BLASTBufferQueue> blastBufferQueue = context.promote(); if (blastBufferQueue) { blastBufferQueue->releaseBufferCallback(id, releaseFence, transformHint, currentMaxAcquiredBufferCount); blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount); } else { ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str()); } } void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) { void BLASTBufferQueue::releaseBufferCallback( const ReleaseCallbackId& id, const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str()); if (mSurfaceControl != nullptr) { 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 // 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 Loading @@ -359,8 +352,12 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL; }(); if (currentMaxAcquiredBufferCount) { mCurrentMaxAcquiredBufferCount = *currentMaxAcquiredBufferCount; } const auto numPendingBuffersToHold = isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0; isEGL ? std::max(0u, mMaxAcquiredBuffers - mCurrentMaxAcquiredBufferCount) : 0; mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence}); // Release all buffers that are beyond the ones that we need to hold Loading @@ -374,7 +371,7 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, return; } mNumAcquired--; BQA_LOGV("released %s", id.to_string().c_str()); BQA_LOGV("released %s", releaseBuffer.callbackId.to_string().c_str()); mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence); mSubmitted.erase(it); processNextBufferLocked(false /* useNextTransaction */); Loading Loading @@ -466,8 +463,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE; t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseCallbackId, releaseBufferCallback); Loading libs/gui/ITransactionCompletedListener.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -254,11 +254,10 @@ public: } void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override { uint32_t currentMaxAcquiredBufferCount) override { callRemoteAsync<decltype( &ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER, callbackId, releaseFence, transformHint, currentMaxAcquiredBufferCount); } }; Loading libs/gui/SurfaceComposerClient.cpp +71 −19 Original line number Diff line number Diff line Loading @@ -214,12 +214,6 @@ void TransactionCompletedListener::setReleaseBufferCallback(const ReleaseCallbac mReleaseBufferCallbacks[callbackId] = listener; } void TransactionCompletedListener::removeReleaseBufferCallback( const ReleaseCallbackId& callbackId) { std::scoped_lock<std::mutex> lock(mMutex); mReleaseBufferCallbacks.erase(callbackId); } void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) { std::scoped_lock<std::recursive_mutex> lock(mSurfaceStatsListenerMutex); Loading Loading @@ -343,7 +337,6 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener surfaceStats.previousReleaseFence ? surfaceStats.previousReleaseFence : Fence::NO_FENCE, surfaceStats.transformHint, surfaceStats.currentMaxAcquiredBufferCount); } } Loading Loading @@ -389,7 +382,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence, uint32_t transformHint, sp<Fence> releaseFence, uint32_t currentMaxAcquiredBufferCount) { ReleaseBufferCallback callback; { Loading @@ -401,7 +394,11 @@ void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, callbackId.to_string().c_str()); return; } callback(callbackId, releaseFence, transformHint, currentMaxAcquiredBufferCount); std::optional<uint32_t> optionalMaxAcquiredBufferCount = currentMaxAcquiredBufferCount == UINT_MAX ? std::nullopt : std::make_optional<uint32_t>(currentMaxAcquiredBufferCount); callback(callbackId, releaseFence, optionalMaxAcquiredBufferCount); } ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( Loading Loading @@ -712,11 +709,34 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const return NO_ERROR; } void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_state_t& state) { if (!(state.what & layer_state_t::eBufferChanged)) { return; } auto listener = state.bufferData.releaseBufferListener; sp<Fence> fence = state.bufferData.acquireFence ? state.bufferData.acquireFence : Fence::NO_FENCE; if (state.bufferData.releaseBufferEndpoint == IInterface::asBinder(TransactionCompletedListener::getIInstance())) { // if the callback is in process, run on a different thread to avoid any lock contigency // issues in the client. SurfaceComposerClient::getDefault() ->mReleaseCallbackThread.addReleaseCallback(state.bufferData.releaseCallbackId, fence); } else { listener->onReleaseBuffer(state.bufferData.releaseCallbackId, fence, UINT_MAX); } } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { for (auto const& [handle, composerState] : other.mComposerStates) { if (mComposerStates.count(handle) == 0) { mComposerStates[handle] = composerState; } else { if (composerState.state.what & layer_state_t::eBufferChanged) { releaseBufferIfOverwriting(mComposerStates[handle].state); } mComposerStates[handle].state.merge(composerState.state); } } Loading Loading @@ -1296,7 +1316,9 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe mStatus = BAD_INDEX; return *this; } removeReleaseBufferCallback(s); releaseBufferIfOverwriting(*s); BufferData bufferData; bufferData.buffer = buffer; if (frameNumber) { Loading @@ -1321,15 +1343,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe return *this; } void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state_t* s) { if (!(s->what & layer_state_t::eBufferChanged)) { return; } auto listener = TransactionCompletedListener::getInstance(); listener->removeReleaseBufferCallback(s->bufferData.releaseCallbackId); } void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData, const ReleaseCallbackId& id, ReleaseBufferCallback callback) { Loading Loading @@ -2210,4 +2223,43 @@ status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, return s->captureLayers(captureArgs, captureListener); } // --------------------------------------------------------------------------------- void ReleaseCallbackThread::addReleaseCallback(const ReleaseCallbackId callbackId, sp<Fence> releaseFence) { std::scoped_lock<std::mutex> lock(mMutex); if (!mStarted) { mThread = std::thread(&ReleaseCallbackThread::threadMain, this); mStarted = true; } mCallbackInfos.emplace(callbackId, std::move(releaseFence)); mReleaseCallbackPending.notify_one(); } void ReleaseCallbackThread::threadMain() { const auto listener = TransactionCompletedListener::getInstance(); std::queue<std::tuple<const ReleaseCallbackId, const sp<Fence>>> callbackInfos; while (true) { { std::unique_lock<std::mutex> lock(mMutex); callbackInfos = std::move(mCallbackInfos); mCallbackInfos = {}; } while (!callbackInfos.empty()) { auto [callbackId, releaseFence] = callbackInfos.front(); listener->onReleaseBuffer(callbackId, std::move(releaseFence), UINT_MAX); callbackInfos.pop(); } { std::unique_lock<std::mutex> lock(mMutex); if (mCallbackInfos.size() == 0) { mReleaseCallbackPending.wait(lock); } } } } } // namespace android libs/gui/include/gui/BLASTBufferQueue.h +3 −1 Original line number Diff line number Diff line Loading @@ -91,7 +91,7 @@ public: void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence, const std::vector<SurfaceControlStats>& stats); void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount); std::optional<uint32_t> currentMaxAcquiredBufferCount); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void applyPendingTransactions(uint64_t frameNumber); Loading Loading @@ -236,6 +236,8 @@ private: // Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a // callback for them. std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex); uint32_t mCurrentMaxAcquiredBufferCount; }; } // namespace android Loading libs/gui/include/gui/ITransactionCompletedListener.h +0 −1 Original line number Diff line number Diff line Loading @@ -192,7 +192,6 @@ public: virtual void onTransactionCompleted(ListenerStats stats) = 0; virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) = 0; }; Loading Loading
libs/gui/BLASTBufferQueue.cpp +14 −18 Original line number Diff line number Diff line Loading @@ -162,6 +162,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers; mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); Loading Loading @@ -325,31 +326,23 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence // 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, const ReleaseCallbackId& id, const sp<Fence>& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) { const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) { sp<BLASTBufferQueue> blastBufferQueue = context.promote(); if (blastBufferQueue) { blastBufferQueue->releaseBufferCallback(id, releaseFence, transformHint, currentMaxAcquiredBufferCount); blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount); } else { ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str()); } } void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) { void BLASTBufferQueue::releaseBufferCallback( const ReleaseCallbackId& id, const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) { ATRACE_CALL(); std::unique_lock _lock{mMutex}; BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str()); if (mSurfaceControl != nullptr) { 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 // 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 Loading @@ -359,8 +352,12 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL; }(); if (currentMaxAcquiredBufferCount) { mCurrentMaxAcquiredBufferCount = *currentMaxAcquiredBufferCount; } const auto numPendingBuffersToHold = isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0; isEGL ? std::max(0u, mMaxAcquiredBuffers - mCurrentMaxAcquiredBufferCount) : 0; mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence}); // Release all buffers that are beyond the ones that we need to hold Loading @@ -374,7 +371,7 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, return; } mNumAcquired--; BQA_LOGV("released %s", id.to_string().c_str()); BQA_LOGV("released %s", releaseBuffer.callbackId.to_string().c_str()); mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence); mSubmitted.erase(it); processNextBufferLocked(false /* useNextTransaction */); Loading Loading @@ -466,8 +463,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE; t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseCallbackId, releaseBufferCallback); Loading
libs/gui/ITransactionCompletedListener.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -254,11 +254,10 @@ public: } void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override { uint32_t currentMaxAcquiredBufferCount) override { callRemoteAsync<decltype( &ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER, callbackId, releaseFence, transformHint, currentMaxAcquiredBufferCount); } }; Loading
libs/gui/SurfaceComposerClient.cpp +71 −19 Original line number Diff line number Diff line Loading @@ -214,12 +214,6 @@ void TransactionCompletedListener::setReleaseBufferCallback(const ReleaseCallbac mReleaseBufferCallbacks[callbackId] = listener; } void TransactionCompletedListener::removeReleaseBufferCallback( const ReleaseCallbackId& callbackId) { std::scoped_lock<std::mutex> lock(mMutex); mReleaseBufferCallbacks.erase(callbackId); } void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) { std::scoped_lock<std::recursive_mutex> lock(mSurfaceStatsListenerMutex); Loading Loading @@ -343,7 +337,6 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener surfaceStats.previousReleaseFence ? surfaceStats.previousReleaseFence : Fence::NO_FENCE, surfaceStats.transformHint, surfaceStats.currentMaxAcquiredBufferCount); } } Loading Loading @@ -389,7 +382,7 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence, uint32_t transformHint, sp<Fence> releaseFence, uint32_t currentMaxAcquiredBufferCount) { ReleaseBufferCallback callback; { Loading @@ -401,7 +394,11 @@ void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, callbackId.to_string().c_str()); return; } callback(callbackId, releaseFence, transformHint, currentMaxAcquiredBufferCount); std::optional<uint32_t> optionalMaxAcquiredBufferCount = currentMaxAcquiredBufferCount == UINT_MAX ? std::nullopt : std::make_optional<uint32_t>(currentMaxAcquiredBufferCount); callback(callbackId, releaseFence, optionalMaxAcquiredBufferCount); } ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( Loading Loading @@ -712,11 +709,34 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const return NO_ERROR; } void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_state_t& state) { if (!(state.what & layer_state_t::eBufferChanged)) { return; } auto listener = state.bufferData.releaseBufferListener; sp<Fence> fence = state.bufferData.acquireFence ? state.bufferData.acquireFence : Fence::NO_FENCE; if (state.bufferData.releaseBufferEndpoint == IInterface::asBinder(TransactionCompletedListener::getIInstance())) { // if the callback is in process, run on a different thread to avoid any lock contigency // issues in the client. SurfaceComposerClient::getDefault() ->mReleaseCallbackThread.addReleaseCallback(state.bufferData.releaseCallbackId, fence); } else { listener->onReleaseBuffer(state.bufferData.releaseCallbackId, fence, UINT_MAX); } } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { for (auto const& [handle, composerState] : other.mComposerStates) { if (mComposerStates.count(handle) == 0) { mComposerStates[handle] = composerState; } else { if (composerState.state.what & layer_state_t::eBufferChanged) { releaseBufferIfOverwriting(mComposerStates[handle].state); } mComposerStates[handle].state.merge(composerState.state); } } Loading Loading @@ -1296,7 +1316,9 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe mStatus = BAD_INDEX; return *this; } removeReleaseBufferCallback(s); releaseBufferIfOverwriting(*s); BufferData bufferData; bufferData.buffer = buffer; if (frameNumber) { Loading @@ -1321,15 +1343,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe return *this; } void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state_t* s) { if (!(s->what & layer_state_t::eBufferChanged)) { return; } auto listener = TransactionCompletedListener::getInstance(); listener->removeReleaseBufferCallback(s->bufferData.releaseCallbackId); } void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData, const ReleaseCallbackId& id, ReleaseBufferCallback callback) { Loading Loading @@ -2210,4 +2223,43 @@ status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, return s->captureLayers(captureArgs, captureListener); } // --------------------------------------------------------------------------------- void ReleaseCallbackThread::addReleaseCallback(const ReleaseCallbackId callbackId, sp<Fence> releaseFence) { std::scoped_lock<std::mutex> lock(mMutex); if (!mStarted) { mThread = std::thread(&ReleaseCallbackThread::threadMain, this); mStarted = true; } mCallbackInfos.emplace(callbackId, std::move(releaseFence)); mReleaseCallbackPending.notify_one(); } void ReleaseCallbackThread::threadMain() { const auto listener = TransactionCompletedListener::getInstance(); std::queue<std::tuple<const ReleaseCallbackId, const sp<Fence>>> callbackInfos; while (true) { { std::unique_lock<std::mutex> lock(mMutex); callbackInfos = std::move(mCallbackInfos); mCallbackInfos = {}; } while (!callbackInfos.empty()) { auto [callbackId, releaseFence] = callbackInfos.front(); listener->onReleaseBuffer(callbackId, std::move(releaseFence), UINT_MAX); callbackInfos.pop(); } { std::unique_lock<std::mutex> lock(mMutex); if (mCallbackInfos.size() == 0) { mReleaseCallbackPending.wait(lock); } } } } } // namespace android
libs/gui/include/gui/BLASTBufferQueue.h +3 −1 Original line number Diff line number Diff line Loading @@ -91,7 +91,7 @@ public: void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence, const std::vector<SurfaceControlStats>& stats); void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount); std::optional<uint32_t> currentMaxAcquiredBufferCount); void setNextTransaction(SurfaceComposerClient::Transaction *t); void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber); void applyPendingTransactions(uint64_t frameNumber); Loading Loading @@ -236,6 +236,8 @@ private: // Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a // callback for them. std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex); uint32_t mCurrentMaxAcquiredBufferCount; }; } // namespace android Loading
libs/gui/include/gui/ITransactionCompletedListener.h +0 −1 Original line number Diff line number Diff line Loading @@ -192,7 +192,6 @@ public: virtual void onTransactionCompleted(ListenerStats stats) = 0; virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) = 0; }; Loading