C2BqBuffer: defer GraphicBuffer cache clearing after stop()
Also enable vendors to control the deferring behavior using
int32 property: "debug.codec2.bqpool_dealloc_after_stop"
0 : no deferred clear
any value : deferred clear(only on swcodec)
Bug: 322731059
Change-Id: I92cdb1bfcd7856646cb1baa659bf273344cd6e11
diff --git a/media/codec2/hal/hidl/1.0/utils/Component.cpp b/media/codec2/hal/hidl/1.0/utils/Component.cpp
index 0259d90..62f0e25 100644
--- a/media/codec2/hal/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/Component.cpp
@@ -521,7 +521,18 @@
Return<Status> Component::stop() {
InputBufferManager::unregisterFrameData(mListener);
- return static_cast<Status>(mComponent->stop());
+ Status status = static_cast<Status>(mComponent->stop());
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
+ if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+ std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+ std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
+ bqPool->clearDeferredBlocks();
+ }
+ }
+ }
+ return status;
}
Return<Status> Component::reset() {
diff --git a/media/codec2/hal/hidl/1.1/utils/Component.cpp b/media/codec2/hal/hidl/1.1/utils/Component.cpp
index d34d84e..7f2c4dd 100644
--- a/media/codec2/hal/hidl/1.1/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/Component.cpp
@@ -527,7 +527,18 @@
Return<Status> Component::stop() {
InputBufferManager::unregisterFrameData(mListener);
- return static_cast<Status>(mComponent->stop());
+ Status status = static_cast<Status>(mComponent->stop());
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
+ if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+ std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+ std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
+ bqPool->clearDeferredBlocks();
+ }
+ }
+ }
+ return status;
}
Return<Status> Component::reset() {
diff --git a/media/codec2/hal/hidl/1.2/utils/Component.cpp b/media/codec2/hal/hidl/1.2/utils/Component.cpp
index f78e827..7b0aa9b 100644
--- a/media/codec2/hal/hidl/1.2/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/Component.cpp
@@ -523,7 +523,18 @@
Return<Status> Component::stop() {
InputBufferManager::unregisterFrameData(mListener);
- return static_cast<Status>(mComponent->stop());
+ Status status = static_cast<Status>(mComponent->stop());
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
+ if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+ std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+ std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
+ bqPool->clearDeferredBlocks();
+ }
+ }
+ }
+ return status;
}
Return<Status> Component::reset() {
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index e7fd14f..0987da2 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -478,13 +478,25 @@
class _C2BlockPoolCache {
public:
- _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
+ _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {
+ mBqPoolDeferDeallocAfterStop = false;
+#ifdef __ANDROID_APEX__
+ bool stopHalBeforeSurface = ::android::base::GetBoolProperty(
+ "debug.codec2.stop_hal_before_surface", false);
+ if (!stopHalBeforeSurface) {
+ mBqPoolDeferDeallocAfterStop =
+ ::android::base::GetIntProperty(
+ "debug.codec2.bqpool_dealloc_after_stop", 0) != 0;
+ }
+#endif
+ }
private:
c2_status_t _createBlockPool(
C2PlatformAllocatorDesc &allocatorParam,
std::vector<std::shared_ptr<const C2Component>> components,
C2BlockPool::local_id_t poolId,
+ bool deferDeallocAfterStop,
std::shared_ptr<C2BlockPool> *pool) {
std::shared_ptr<C2AllocatorStore> allocatorStore =
GetCodec2PlatformAllocatorStore();
@@ -548,6 +560,11 @@
if (res == C2_OK) {
std::shared_ptr<C2BlockPool> ptr(
new C2BufferQueueBlockPool(allocator, poolId), deleter);
+ if (deferDeallocAfterStop) {
+ std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+ std::static_pointer_cast<C2BufferQueueBlockPool>(ptr);
+ bqPool->setDeferDeallocationAfterStop();
+ }
*pool = ptr;
mBlockPools[poolId] = ptr;
mComponents[poolId].insert(
@@ -603,7 +620,8 @@
std::vector<std::shared_ptr<const C2Component>> components,
std::shared_ptr<C2BlockPool> *pool) {
std::unique_lock lock(mMutex);
- return _createBlockPool(allocator, components, mBlockPoolSeqId++, pool);
+ return _createBlockPool(allocator, components, mBlockPoolSeqId++,
+ mBqPoolDeferDeallocAfterStop, pool);
}
@@ -638,7 +656,7 @@
C2PlatformAllocatorDesc allocator;
allocator.allocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
return _createBlockPool(
- allocator, {component}, blockPoolId, pool);
+ allocator, {component}, blockPoolId, mBqPoolDeferDeallocAfterStop, pool);
}
return C2_NOT_FOUND;
}
@@ -651,6 +669,8 @@
std::map<C2BlockPool::local_id_t, std::weak_ptr<C2BlockPool>> mBlockPools;
std::map<C2BlockPool::local_id_t, std::vector<std::weak_ptr<const C2Component>>> mComponents;
+
+ bool mBqPoolDeferDeallocAfterStop;
};
static std::unique_ptr<_C2BlockPoolCache> sBlockPoolCache =
diff --git a/media/codec2/vndk/include/C2BqBufferPriv.h b/media/codec2/vndk/include/C2BqBufferPriv.h
index 320b192..1e8dd40 100644
--- a/media/codec2/vndk/include/C2BqBufferPriv.h
+++ b/media/codec2/vndk/include/C2BqBufferPriv.h
@@ -28,6 +28,24 @@
class GraphicBuffer;
} // namespace android
+/**
+ * BufferQueue based BlockPool.
+ *
+ * This creates graphic blocks from BufferQueue. BufferQueue here is HIDL-ized IGBP.
+ * HIDL-ized IGBP enables vendor HAL to call IGBP interfaces via HIDL over process boundary.
+ * HIDL-ized IGBP is called as HGBP. HGBP had been used from multiple places in android,
+ * but now this is the only place HGBP is still used.
+ *
+ * Initially there is no HGBP configured, in the case graphic blocks are allocated
+ * from gralloc directly upon \fetchGraphicBlock() requests.
+ *
+ * HGBP can be configured as null as well, in the case graphic blocks are allocated
+ * from gralloc directly upon \fetchGraphicBlock() requests.
+ *
+ * If a specific HGBP is configured, the HGBP acts as an allocator for creating graphic blocks.
+ *
+ * TODO: add more ducumentation(graphic block life-cycle, waitable object and workaounds)
+ */
class C2BufferQueueBlockPool : public C2BlockPool {
public:
C2BufferQueueBlockPool(const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId);
@@ -77,6 +95,8 @@
* is configured as nullptr, unique id which is bundled in native_handle is zero.
*
* \param producer the IGBP, which will be used to fetch blocks
+ * This could be null, in the case this blockpool will
+ * allocate backed GraphicBuffer via allocator(gralloc).
*/
virtual void configureProducer(const android::sp<HGraphicBufferProducer> &producer);
@@ -89,6 +109,8 @@
* is configured as nullptr, unique id which is bundled in native_handle is zero.
*
* \param producer the IGBP, which will be used to fetch blocks
+ * This could be null, in the case this blockpool will
+ * allocate backed GraphicBuffer via allocator(gralloc).
* \param syncMemory Shared memory for synchronization of allocation & deallocation.
* \param bqId Id of IGBP
* \param generationId Generation Id for rendering output
@@ -110,6 +132,26 @@
*/
virtual void invalidate();
+ /**
+ * Defer deallocation of cached blocks.
+ *
+ * Deallocation of cached blocks will be deferred until
+ * \clearDeferredBlocks() is called. Or a new block allocation is
+ * requested by \fetchGraphicBlock().
+ */
+ void setDeferDeallocationAfterStop();
+
+
+ /**
+ * Clear deferred blocks.
+ *
+ * Deallocation of cached blocks can be deferred by
+ * \setDeferDeallocationAfterStop().
+ * clear(deallocate) those deferred cached blocks explicitly.
+ * Use this interface, if the blockpool could be inactive indefinitely.
+ */
+ void clearDeferredBlocks();
+
private:
const std::shared_ptr<C2Allocator> mAllocator;
const local_id_t mLocalId;
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 48157c8..665f9fc 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -588,11 +588,22 @@
return C2_BAD_VALUE;
}
+ void clearDeferredBlocks_l() {
+ if (mHavingDeallocationDeferred) {
+ mHavingDeallocationDeferred = false;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
+ mBuffersWithDeallocationDeferred[i].clear();
+ }
+ }
+ }
+
public:
Impl(const std::shared_ptr<C2Allocator> &allocator)
: mInit(C2_OK), mProducerId(0), mGeneration(0),
mConsumerUsage(0), mDqFailure(0), mLastDqTs(0),
- mLastDqLogTs(0), mAllocator(allocator), mIgbpValidityToken(std::make_shared<int>(0)) {
+ mLastDqLogTs(0), mAllocator(allocator),
+ mDeferDeallocationAfterStop(false),
+ mHavingDeallocationDeferred(false), mIgbpValidityToken(std::make_shared<int>(0)) {
}
~Impl() {
@@ -634,6 +645,7 @@
}
}
if (mProducerId == 0) {
+ clearDeferredBlocks_l();
std::shared_ptr<C2GraphicAllocation> alloc;
c2_status_t err = mAllocator->newGraphicAllocation(
width, height, format, usage, &alloc);
@@ -692,6 +704,7 @@
uint32_t generation,
uint64_t usage,
bool bqInformation) {
+ bool toNullSurface = false;
std::shared_ptr<C2SurfaceSyncMemory> c2SyncMem;
if (syncHandle) {
if (!producer) {
@@ -714,6 +727,9 @@
mProducerId = producerId;
mGeneration = bqInformation ? generation : 0;
} else {
+ if (mProducer) {
+ toNullSurface = true;
+ }
mProducer = nullptr;
mProducerId = 0;
mGeneration = 0;
@@ -760,6 +776,17 @@
// old buffers should not be cancelled since the associated IGBP
// is no longer valid.
mIgbpValidityToken = std::make_shared<int>(0);
+ if (mDeferDeallocationAfterStop) {
+ if (toNullSurface) {
+ mHavingDeallocationDeferred = true;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
+ mBuffersWithDeallocationDeferred[i] = mBuffers[i];
+ }
+ }
+ }
+ }
+ if (!toNullSurface) {
+ clearDeferredBlocks_l();
}
if (mInvalidated) {
mIgbpValidityToken = std::make_shared<int>(0);
@@ -811,6 +838,16 @@
}
}
+ void setDeferDeallocationAfterStop() {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mDeferDeallocationAfterStop = true;
+ }
+
+ void clearDeferredBlocks() {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ clearDeferredBlocks_l();
+ }
+
private:
friend struct C2BufferQueueBlockPoolData;
@@ -833,6 +870,14 @@
sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS];
std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS];
+ // In order to workaround b/322731059,
+ // deallocating buffers due to stop using the current surface
+ // could be deferred until the component calling stop or a
+ // new allocation being requested.
+ bool mDeferDeallocationAfterStop;
+ bool mHavingDeallocationDeferred;
+ sp<GraphicBuffer> mBuffersWithDeallocationDeferred[NUM_BUFFER_SLOTS];
+
std::mutex mSyncMemMutex;
std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
std::shared_ptr<C2SurfaceSyncMemory> mOldMem;
@@ -1178,3 +1223,15 @@
}
}
+void C2BufferQueueBlockPool::setDeferDeallocationAfterStop() {
+ if (mImpl) {
+ mImpl->setDeferDeallocationAfterStop();
+ }
+}
+
+void C2BufferQueueBlockPool::clearDeferredBlocks() {
+ if (mImpl) {
+ mImpl->clearDeferredBlocks();
+ }
+}
+