codec2: C2VDAComponent: use bufferpool-backed block pool

When there is no surface (byte-buffer mode), C2VDAComponent will use
C2VdaPooledBlockPool for allocating and recycling graphic buffers.

The hack of MockBufferInClient is removed and the dequeue flow of
C2VdaPooledBlockPool is aligned to C2VdaBqBlockPool.

Component is not always holding the reference of C2GraphicBlock now, it is
obtained from block pool and passed to the client after decoding.

Bug: 79239042
Test: CtsMediaTestCases on kevin-arcnext with Codec2.0 enabled
Test: android.media.cts.EncodeDecodeTest#testEncodeDecodeVideoFromBufferToBuffer720p
Test: android.media.cts.EncodeDecodeTest#testEncodeDecodeVideoFromBufferToBufferQCIF
Test: android.media.cts.EncodeDecodeTest#testEncodeDecodeVideoFromBufferToBufferQVGA
Test: android.media.cts.EncodeDecodeTest#testVP8EncodeDecodeVideoFromBufferToBuffer720p
Test: android.media.cts.EncodeDecodeTest#testVP8EncodeDecodeVideoFromBufferToBufferQCIF
Test: android.media.cts.EncodeDecodeTest#testVP8EncodeDecodeVideoFromBufferToBufferQVGA
Change-Id: I31d2caf87ac3b60c46dc642c18cd0d254f628fb2
diff --git a/C2VDAComponent.cpp b/C2VDAComponent.cpp
index 8519994..6839130 100644
--- a/C2VDAComponent.cpp
+++ b/C2VDAComponent.cpp
@@ -14,6 +14,7 @@
 #define __C2_GENERATE_GLOBAL_VARS__
 #include <C2VDAAllocatorStore.h>
 #include <C2VdaBqBlockPool.h>
+#include <C2VdaPooledBlockPool.h>
 #include <C2VDAComponent.h>
 #include <C2VDASupport.h>  // to getParamReflector from vda store
 
@@ -57,14 +58,6 @@
 
 const uint32_t kDpbOutputBufferExtraCount = 3;  // Use the same number as ACodec.
 const int kDequeueRetryDelayUs = 10000;  // Wait time of dequeue buffer retry in microseconds.
-
-// Hack(b/79239042): Max size of mMockBufferQueueInClient.
-// This value is empirically picked from previous CTS try-run. If this value is too big, it may
-// cause VDA deadlock when it requires more buffers to decode and dequeue a new one. On the other
-// hand, too small value may produce wrong display picture because recycling goes faster than
-// rendering.
-const size_t kMockMaxBuffersInClient = 5;
-
 }  // namespace
 
 C2VDAComponent::IntfImpl::IntfImpl(C2String name, const std::shared_ptr<C2ReflectorHelper>& helper)
@@ -147,7 +140,7 @@
                          .build());
 
     C2Allocator::id_t inputAllocators[] = {C2PlatformAllocatorStore::ION};
-    C2Allocator::id_t outputAllocators[] = {C2VDAAllocatorStore::V4L2_BUFFERQUEUE};
+    C2Allocator::id_t outputAllocators[] = {C2VDAAllocatorStore::V4L2_BUFFERPOOL};
 
     addParameter(
             DefineParam(mInputAllocatorIds, C2_PARAMKEY_INPUT_ALLOCATORS)
@@ -190,16 +183,6 @@
         mCodedSize(codedSize),
         mVisibleRect(visibleRect) {}
 
-static uint32_t getSlotFromGraphicBlockHandle(const C2Handle* const handle) {
-    uint32_t width, height, format, stride, igbp_slot, generation;
-    uint64_t usage, igbp_id;
-    _UnwrapNativeCodec2GrallocMetadata(
-            handle, &width, &height, &format, &usage, &stride, &generation, &igbp_id, &igbp_slot);
-    ALOGV("Unwrap Metadata: igbp[%" PRIu64 ", %u] (%u*%u, fmt %#x, usage %" PRIx64 ", stride %u)",
-          igbp_id, igbp_slot, width, height, format, usage, stride);
-    return igbp_slot;
-}
-
 C2VDAComponent::C2VDAComponent(C2String name, c2_node_id_t id,
                                const std::shared_ptr<C2ReflectorHelper>& helper)
       : mIntfImpl(std::make_shared<IntfImpl>(name, helper)),
@@ -210,7 +193,6 @@
         mComponentState(ComponentState::UNINITIALIZED),
         mPendingOutputEOS(false),
         mLastOutputTimestamp(-1),
-        mSurfaceMode(true),
         mCodecProfile(media::VIDEO_CODEC_PROFILE_UNKNOWN),
         mState(State::UNLOADED),
         mWeakThisFactory(this) {
@@ -359,9 +341,10 @@
     reportFinishedWorkIfAny();
 }
 
-void C2VDAComponent::onOutputBufferReturned(uint32_t slotId) {
+void C2VDAComponent::onOutputBufferReturned(std::shared_ptr<C2GraphicBlock> block,
+                                            uint32_t poolId) {
     DCHECK(mTaskRunner->BelongsToCurrentThread());
-    ALOGV("onOutputBufferReturned: slot id=%u", slotId);
+    ALOGV("onOutputBufferReturned: pool id=%u", poolId);
     if (mComponentState == ComponentState::UNINITIALIZED) {
         // Output buffer is returned from client after component is stopped. Just let the buffer be
         // released.
@@ -370,12 +353,13 @@
 
     // TODO(johnylin): when buffer is returned, we should confirm that output format is not changed
     //                 yet. If changed, just let the buffer be released.
-    GraphicBlockInfo* info = getGraphicBlockBySlot(slotId);
+    GraphicBlockInfo* info = getGraphicBlockByPoolId(poolId);
     if (!info) {
         reportError(C2_CORRUPTED);
         return;
     }
     CHECK_EQ(info->mState, GraphicBlockInfo::State::OWNED_BY_CLIENT);
+    info->mGraphicBlock = std::move(block);
     info->mState = GraphicBlockInfo::State::OWNED_BY_COMPONENT;
 
     if (mPendingOutputFormat) {
@@ -403,18 +387,7 @@
     CHECK_EQ(info->mState, GraphicBlockInfo::State::OWNED_BY_ACCELERATOR);
     // Output buffer will be passed to client soon along with mListener->onWorkDone_nb().
     info->mState = GraphicBlockInfo::State::OWNED_BY_CLIENT;
-    if (mSurfaceMode) {
-        mBuffersInClient++;
-    } else {  // byte-buffer mode
-        // Hack(b/79239042)
-        mMockBufferQueueInClient.push_back(info->mSlotId);
-        if (mMockBufferQueueInClient.size() > kMockMaxBuffersInClient) {
-            mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onOutputBufferReturned,
-                                                          ::base::Unretained(this),
-                                                          mMockBufferQueueInClient.front()));
-            mMockBufferQueueInClient.pop_front();
-        }
-    }
+    mBuffersInClient++;
 
     // Attach output buffer to the work corresponded to bitstreamId.
     auto block = info->mGraphicBlock;
@@ -422,6 +395,7 @@
             block->share(C2Rect(mOutputFormat.mVisibleRect.width(),
                                 mOutputFormat.mVisibleRect.height()),
                          C2Fence())));
+    info->mGraphicBlock.reset();
 
     // TODO: this does not work for timestamps as they can wrap around
     int64_t currentTimestamp = ::base::checked_cast<int64_t>(work->input.ordinal.timestamp.peek());
@@ -570,7 +544,6 @@
 
     mGraphicBlocks.clear();
 
-    mMockBufferQueueInClient.clear();  // Hack(b/79239042)
     stopDequeueThread();
 
     mStopDoneEvent->Signal();
@@ -627,14 +600,14 @@
     return &mGraphicBlocks[blockId];
 }
 
-C2VDAComponent::GraphicBlockInfo* C2VDAComponent::getGraphicBlockBySlot(uint32_t slotId) {
+C2VDAComponent::GraphicBlockInfo* C2VDAComponent::getGraphicBlockByPoolId(uint32_t poolId) {
     auto blockIter = std::find_if(mGraphicBlocks.begin(), mGraphicBlocks.end(),
-                                  [slotId](const GraphicBlockInfo& gb) {
-                                      return gb.mSlotId == slotId;
+                                  [poolId](const GraphicBlockInfo& gb) {
+                                      return gb.mPoolId == poolId;
                                   });
 
     if (blockIter == mGraphicBlocks.end()) {
-        ALOGE("getGraphicBlockBySlot failed: slot=%u", slotId);
+        ALOGE("getGraphicBlockByPoolId failed: poolId=%u", poolId);
         return nullptr;
     }
     return &(*blockIter);
@@ -700,7 +673,6 @@
                                                               uint32_t pixelFormat) {
     ALOGV("allocateBuffersFromBlockAllocator(%s, 0x%x)", size.ToString().c_str(), pixelFormat);
 
-    mMockBufferQueueInClient.clear();  // Hack(b/79239042)
     stopDequeueThread();
 
     size_t bufferCount = mOutputFormat.mMinNumBuffers + kDpbOutputBufferExtraCount;
@@ -721,17 +693,16 @@
 
     mGraphicBlocks.clear();
 
-    if (blockPool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+    bool useBufferQueue = blockPool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE;
+    if (useBufferQueue) {
+        ALOGV("Bufferqueue-backed block pool is used.");
         // Set requested buffer count to C2VdaBqBlockPool.
         std::shared_ptr<C2VdaBqBlockPool> bqPool =
                 std::static_pointer_cast<C2VdaBqBlockPool>(blockPool);
         if (bqPool) {
             err = bqPool->requestNewBufferSet(static_cast<int32_t>(bufferCount));
-            if (err == C2_NO_INIT) {
-                ALOGD("No surface in block pool, output is byte-buffer mode...");
-                mSurfaceMode = false;
-            } else if (err != C2_OK) {
-                ALOGE("failed to set buffer count magic to block pool: %d", err);
+            if (err != C2_OK) {
+                ALOGE("failed to request new buffer set to block pool: %d", err);
                 reportError(err);
                 return err;
             }
@@ -740,9 +711,23 @@
             reportError(C2_CORRUPTED);
             return C2_CORRUPTED;
         }
-    } else {  // CCodec falls back to use C2BasicGraphicBlockPool
-        ALOGD("CCodec falls back to use C2BasicGraphicBlockPool...");
-        mSurfaceMode = false;
+    } else {
+        ALOGV("Bufferpool-backed block pool is used.");
+        // Set requested buffer count to C2VdaPooledBlockPool.
+        std::shared_ptr<C2VdaPooledBlockPool> bpPool =
+                std::static_pointer_cast<C2VdaPooledBlockPool>(blockPool);
+        if (bpPool) {
+            err = bpPool->requestNewBufferSet(static_cast<int32_t>(bufferCount));
+            if (err != C2_OK) {
+                ALOGE("failed to request new buffer set to block pool: %d", err);
+                reportError(err);
+                return err;
+            }
+        } else {
+            ALOGE("static_pointer_cast C2VdaPooledBlockPool failed...");
+            reportError(C2_CORRUPTED);
+            return C2_CORRUPTED;
+        }
     }
 
     for (size_t i = 0; i < bufferCount; ++i) {
@@ -755,21 +740,34 @@
             reportError(err);
             return err;
         }
-        appendOutputBuffer(std::move(block));
+        uint32_t poolId;
+        if (useBufferQueue) {
+            err = C2VdaBqBlockPool::getPoolIdFromGraphicBlock(block, &poolId);
+        } else {  // use bufferpool
+            err = C2VdaPooledBlockPool::getPoolIdFromGraphicBlock(block, &poolId);
+        }
+        if (err != C2_OK) {
+            mGraphicBlocks.clear();
+            ALOGE("failed to getPoolIdFromGraphicBlock: %d", err);
+            reportError(err);
+            return err;
+        }
+        appendOutputBuffer(std::move(block), poolId);
     }
     mOutputFormat.mMinNumBuffers = bufferCount;
 
-    if (mSurfaceMode && !startDequeueThread(size, pixelFormat, std::move(blockPool))) {
+    if (!startDequeueThread(size, pixelFormat, std::move(blockPool))) {
         reportError(C2_CORRUPTED);
         return C2_CORRUPTED;
     }
     return C2_OK;
 }
 
-void C2VDAComponent::appendOutputBuffer(std::shared_ptr<C2GraphicBlock> block) {
+void C2VDAComponent::appendOutputBuffer(std::shared_ptr<C2GraphicBlock> block, uint32_t poolId) {
     GraphicBlockInfo info;
     info.mBlockId = static_cast<int32_t>(mGraphicBlocks.size());
     info.mGraphicBlock = std::move(block);
+    info.mPoolId = poolId;
 
     C2ConstGraphicBlock constBlock = info.mGraphicBlock->share(
             C2Rect(info.mGraphicBlock->width(), info.mGraphicBlock->height()), C2Fence());
@@ -830,12 +828,6 @@
     info.mHandle = std::move(passedHandle);
     info.mPlanes = std::move(passedPlanes);
 
-    if (mSurfaceMode) {
-        info.mSlotId = getSlotFromGraphicBlockHandle(info.mGraphicBlock->handle());
-    } else {  // byte-buffer mode
-        info.mSlotId = static_cast<uint32_t>(info.mBlockId);
-    }
-
     mGraphicBlocks.push_back(std::move(info));
 }
 
@@ -1205,9 +1197,20 @@
             continue;  // wait for retry
         }
         if (err == C2_OK) {
-            auto slot = getSlotFromGraphicBlockHandle(block->handle());
-            mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onOutputBufferReturned,
-                                                          ::base::Unretained(this), slot));
+            uint32_t poolId;
+            if (blockPool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+                err = C2VdaBqBlockPool::getPoolIdFromGraphicBlock(block, &poolId);
+            } else {  // bufferpool
+                err = C2VdaPooledBlockPool::getPoolIdFromGraphicBlock(block, &poolId);
+            }
+
+            if (err != C2_OK) {
+                ALOGE("dequeueThreadLoop got error on getPoolIdFromGraphicBlock: %d", err);
+                break;
+            }
+            mTaskRunner->PostTask(FROM_HERE,
+                                  ::base::Bind(&C2VDAComponent::onOutputBufferReturned,
+                                               ::base::Unretained(this), std::move(block), poolId));
             mBuffersInClient--;
         } else {
             ALOGE("dequeueThreadLoop got error: %d", err);