media.c2 aidl: Implement IGBA/AHwB based blockpool
Implement IGBA/AHwB based BlockPool(C2IgbaBlockPool).
Also implement IGBA/AHwB based GraphicBlock transfer between HAL and the
client.
Test: m
Bug: 254050314
Change-Id: Ie27a36d071440d807adda00fe1fa9f78ec413834
diff --git a/media/codec2/hal/aidl/BufferTypes.cpp b/media/codec2/hal/aidl/BufferTypes.cpp
index 1cd3555..b1af579 100644
--- a/media/codec2/hal/aidl/BufferTypes.cpp
+++ b/media/codec2/hal/aidl/BufferTypes.cpp
@@ -54,8 +54,10 @@
using ::aidl::android::hardware::media::c2::utils::BufferPoolTypes;
using AidlNativeHandle = ::aidl::android::hardware::common::NativeHandle;
+using AidlHardwareBuffer = ::aidl::android::hardware::HardwareBuffer;
constexpr BaseBlock::Tag NATIVE_BLOCK = BaseBlock::nativeBlock;
+constexpr BaseBlock::Tag HWB_BLOCK = BaseBlock::hwbBlock;
constexpr BaseBlock::Tag POOLED_BLOCK = BaseBlock::pooledBlock;
// BaseBlock -> C2BaseBlock
@@ -97,6 +99,21 @@
}
return false;
}
+ case HWB_BLOCK: {
+ AHardwareBuffer *pBuf =
+ const_cast<AidlHardwareBuffer&>(
+ s.get<HWB_BLOCK>()).release();
+ d->graphic = _C2BlockFactory::CreateGraphicBlock(pBuf);
+ if (pBuf) {
+ AHardwareBuffer_release(pBuf);
+ }
+ if (d->graphic) {
+ d->type = ::android::C2BaseBlock::GRAPHIC;
+ return true;
+ }
+ LOG(ERROR) << "Improper ahwb in BaseBlock::hwbBlock.";
+ return false;
+ }
case POOLED_BLOCK: {
const BufferStatusMessage &bpMessage = s.get<POOLED_BLOCK>();
std::shared_ptr<ClientManager> bp = ClientManager::getInstance();
@@ -188,6 +205,13 @@
}
template<>
+void SetAHardwareBuffer(BaseBlock *block, AHardwareBuffer *ahwb) {
+ AHardwareBuffer_acquire(ahwb);
+ block->set<HWB_BLOCK>(AidlHardwareBuffer());
+ (block->get<HWB_BLOCK>()).reset(ahwb);
+}
+
+template<>
void SetPooledBlock<BufferPoolTypes>(
BaseBlock *baseBlock,
const typename BufferPoolTypes::BufferStatusMessage &pooledBlock) {
@@ -326,6 +350,28 @@
return ::android::objcpy(d, s);
}
+void ReturnOutputBlocksToClientIfNeeded(
+ const std::list<std::unique_ptr<C2Work>>& workList) {
+ for (const std::unique_ptr<C2Work>& work : workList) {
+ if (!work) {
+ continue;
+ }
+ for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
+ if (worklet) {
+ for (const std::shared_ptr<C2Buffer>& buffer : worklet->output.buffers) {
+ if (buffer) {
+ for (const C2ConstGraphicBlock& block : buffer->data().graphicBlocks()) {
+ std::shared_ptr<_C2BlockPoolData> poolData =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ _C2BlockFactory::DisownIgbaBlock(poolData);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
} // namespace utils
} // namespace c2
} // namespace media
diff --git a/media/codec2/hal/aidl/Component.cpp b/media/codec2/hal/aidl/Component.cpp
index 9c21a5b..2e0859b 100644
--- a/media/codec2/hal/aidl/Component.cpp
+++ b/media/codec2/hal/aidl/Component.cpp
@@ -113,26 +113,22 @@
WorkBundle workBundle;
std::shared_ptr<Component> strongComponent = mComponent.lock();
- // TODO
- // beginTransferBufferQueueBlocks(c2workItems, true);
if (!ToAidl(&workBundle, c2workItems, strongComponent ?
&strongComponent->mBufferPoolSender : nullptr)) {
LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
<< "received corrupted work items.";
- // TODO
- // endTransferBufferQueueBlocks(c2workItems, false, true);
return;
}
ScopedAStatus transStatus = listener->onWorkDone(workBundle);
if (!transStatus.isOk()) {
LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
<< "transaction failed.";
- // TODO
- // endTransferBufferQueueBlocks(c2workItems, false, true);
return;
}
- // TODO
- // endTransferBufferQueueBlocks(c2workItems, true, true);
+ // If output blocks are originally owned by the client(not by HAL),
+ // return the ownership to the client. (Since the blocks are
+ // transferred to the client here.)
+ ReturnOutputBlocksToClientIfNeeded(c2workItems);
}
}
@@ -210,15 +206,15 @@
}
}
- // TODO
- // beginTransferBufferQueueBlocks(c2flushedWorks, true);
if (c2res == C2_OK) {
if (!ToAidl(flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
c2res = C2_CORRUPTED;
}
}
- // TODO
- // endTransferBufferQueueBlocks(c2flushedWorks, true, true);
+ // If output blocks are originally owned by the client(not by HAL),
+ // return the ownership to the client. (Since the blocks are
+ // transferred to the client here.)
+ ReturnOutputBlocksToClientIfNeeded(c2flushedWorks);
if (c2res == C2_OK) {
return ScopedAStatus::ok();
}
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h b/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h
index 470863c..87fb855 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/BufferTypes.h
@@ -115,6 +115,12 @@
std::list<std::unique_ptr<C2Work>>* d,
const WorkBundle& s);
+// Return the ownership of output blocks to the client if it is originally
+// created from the client, after C2Work is returned to the client.
+// (e.g. C2BqPool / C2IgbaBlockPool)
+void ReturnOutputBlocksToClientIfNeeded(
+ const std::list<std::unique_ptr<C2Work>>& workList);
+
/**
* Converts a BufferPool status value to c2_status_t.
* \param BufferPool status
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
index 2424f7b..573ded8 100644
--- a/media/codec2/hal/client/GraphicsTracker.cpp
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -20,6 +20,7 @@
#include <private/android/AHardwareBufferHelpers.h>
#include <vndk/hardware_buffer.h>
+#include <C2BlockInternal.h>
#include <codec2/aidl/GraphicsTracker.h>
namespace aidl::android::hardware::media::c2::implementation {
@@ -30,10 +31,23 @@
static constexpr int kMaxDequeueMax = ::android::BufferQueueDefs::NUM_BUFFER_SLOTS - 2;
c2_status_t retrieveAHardwareBufferId(const C2ConstGraphicBlock &blk, uint64_t *bid) {
- // TODO
- (void)blk;
- (void)bid;
- return C2_OK;
+ std::shared_ptr<const _C2BlockPoolData> bpData = _C2BlockFactory::GetGraphicBlockPoolData(blk);
+ if (bpData->getType() != _C2BlockPoolData::TYPE_AHWBUFFER) {
+ return C2_BAD_VALUE;
+ }
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ AHardwareBuffer *pBuf;
+ if (!_C2BlockFactory::GetAHardwareBuffer(bpData, &pBuf)) {
+ return C2_CORRUPTED;
+ }
+ int ret = AHardwareBuffer_getId(pBuf, bid);
+ if (ret != ::android::OK) {
+ return C2_CORRUPTED;
+ }
+ return C2_OK;
+ } else {
+ return C2_OMITTED;
+ }
}
} // anonymous namespace
@@ -44,16 +58,18 @@
if (!buf) {
return;
}
- AHardwareBuffer *pBuf = AHardwareBuffer_from_GraphicBuffer(buf.get());
- int ret = AHardwareBuffer_getId(pBuf, &mId);
- if (ret != ::android::OK) {
- return;
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ AHardwareBuffer *pBuf = AHardwareBuffer_from_GraphicBuffer(buf.get());
+ int ret = AHardwareBuffer_getId(pBuf, &mId);
+ if (ret != ::android::OK) {
+ return;
+ }
+ mUsage = buf->getUsage();
+ AHardwareBuffer_acquire(pBuf);
+ mBuf = pBuf;
+ mFence = fence;
+ mInit = true;
}
- mUsage = buf->getUsage();
- AHardwareBuffer_acquire(pBuf);
- mBuf = pBuf;
- mFence = fence;
- mInit = true;
}
GraphicsTracker::BufferItem::BufferItem(
diff --git a/media/codec2/hal/common/include/codec2/common/BufferTypes.h b/media/codec2/hal/common/include/codec2/common/BufferTypes.h
index 8998a6d..afd2db0 100644
--- a/media/codec2/hal/common/include/codec2/common/BufferTypes.h
+++ b/media/codec2/hal/common/include/codec2/common/BufferTypes.h
@@ -63,6 +63,9 @@
template <typename BaseBlock>
void SetHandle(BaseBlock *baseBlock, const C2Handle *handle);
+template <typename BaseBlock>
+void SetAHardwareBuffer(BaseBlock *baseBlock, AHardwareBuffer *pBuf);
+
template <typename BufferPoolTypes, typename BaseBlock>
void SetPooledBlock(
BaseBlock *baseBlock,
@@ -100,6 +103,31 @@
return true;
}
+// Find or add a HAL BaseBlock object from a given AHardwareBuffer* to a list and an
+// associated map.
+template <typename BaseBlock>
+bool _addBaseBlock(
+ uint32_t* index,
+ AHardwareBuffer* pBuf,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!pBuf) {
+ LOG(ERROR) << "addBaseBlock called on a null AHardwareBuffer.";
+ }
+ auto it = baseBlockIndices->find(pBuf);
+ if (it != baseBlockIndices->end()) {
+ *index = it->second;
+ } else {
+ *index = baseBlocks->size();
+ baseBlockIndices->emplace(pBuf, *index);
+ baseBlocks->emplace_back();
+
+ BaseBlock &dBaseBlock = baseBlocks->back();
+ SetAHardwareBuffer(&dBaseBlock, pBuf);
+ }
+ return true;
+}
+
// Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
// an associated map.
template <typename BufferPoolTypes, typename BaseBlock>
@@ -179,6 +207,15 @@
return _addBaseBlock(
index, handle,
baseBlocks, baseBlockIndices);
+ case _C2BlockPoolData::TYPE_AHWBUFFER:
+ AHardwareBuffer *pBuf;
+ if (!_C2BlockFactory::GetAHardwareBuffer(blockPoolData, &pBuf)) {
+ LOG(ERROR) << "AHardwareBuffer unavailable in a block.";
+ return false;
+ }
+ return _addBaseBlock(
+ index, pBuf,
+ baseBlocks, baseBlockIndices);
default:
LOG(ERROR) << "Unknown C2BlockPoolData type.";
return false;
diff --git a/media/codec2/hal/hidl/1.0/utils/types.cpp b/media/codec2/hal/hidl/1.0/utils/types.cpp
index abe5494..69f664b 100644
--- a/media/codec2/hal/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/types.cpp
@@ -210,6 +210,13 @@
}
template<>
+void SetAHardwareBuffer(BaseBlock *block, AHardwareBuffer *pBuf) {
+ (void) block;
+ (void) pBuf;
+ LOG(FATAL) << "This is not used";
+}
+
+template<>
void SetPooledBlock<BufferPoolTypes>(
BaseBlock *baseBlock,
const typename BufferPoolTypes::BufferStatusMessage &pooledBlock) {
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index a59bd47..bbe228c 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -65,6 +65,7 @@
"C2Store.cpp",
"platform/C2BqBuffer.cpp",
"platform/C2SurfaceSyncObj.cpp",
+ "platform/C2IgbaBuffer.cpp",
"types.cpp",
"util/C2Debug.cpp",
"util/C2InterfaceHelper.cpp",
@@ -99,6 +100,7 @@
"android.hardware.common.fmq-V1-ndk",
"android.hardware.media.bufferpool@2.0",
"android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.c2-V1-ndk",
"libbase",
"libbinder_ndk",
"libcutils",
@@ -154,6 +156,7 @@
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
"android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.c2-V1-ndk",
],
shared_libs: [
diff --git a/media/codec2/vndk/include/C2IgbaBufferPriv.h b/media/codec2/vndk/include/C2IgbaBufferPriv.h
new file mode 100644
index 0000000..a5676b7
--- /dev/null
+++ b/media/codec2/vndk/include/C2IgbaBufferPriv.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 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 <C2Buffer.h>
+
+#include <memory>
+
+namespace aidl::android::hardware::media::c2 {
+ class IGraphicBufferAllocator;
+}
+
+/**
+ * Codec2-AIDL IGraphicBufferAllocator backed C2BlockPool
+ *
+ * Graphic Blocks are created using IGraphicBufferAllocator C2AIDL interface.
+ */
+class C2IgbaBlockPool : public C2BlockPool {
+public:
+ explicit C2IgbaBlockPool(
+ const std::shared_ptr<C2Allocator> &allocator,
+ const std::shared_ptr<
+ ::aidl::android::hardware::media::c2::IGraphicBufferAllocator> &igba,
+ const local_id_t localId);
+
+ virtual ~C2IgbaBlockPool() = default;
+
+ virtual C2Allocator::id_t getAllocatorId() const override {
+ return mAllocator->getId();
+ }
+
+ virtual local_id_t getLocalId() const override {
+ return mLocalId;
+ }
+
+ /* Note: this is blocking due to H/W fence waiting */
+ virtual c2_status_t fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */) override;
+
+ virtual c2_status_t fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
+ C2Fence *fence /* nonnull */) override;
+
+ // Do we need this?
+ void invalidate();
+
+private:
+ c2_status_t _fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ c2_nsecs_t timeoutNs,
+ uint64_t *origId /* nonnull */,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
+ C2Fence *fence /* nonnull */);
+
+ const std::shared_ptr<C2Allocator> mAllocator;
+ const std::shared_ptr<::aidl::android::hardware::media::c2::IGraphicBufferAllocator> mIgba;
+ const local_id_t mLocalId;
+ std::atomic<bool> mValid;
+ C2Fence mWaitFence;
+};
+
+typedef struct AHardwareBuffer AHardwareBuffer;
+
+struct C2IgbaBlockPoolData : public _C2BlockPoolData {
+
+ C2IgbaBlockPoolData(
+ const AHardwareBuffer *buffer,
+ const std::shared_ptr<::aidl::android::hardware::media::c2::IGraphicBufferAllocator>
+ &igba);
+
+ virtual ~C2IgbaBlockPoolData() override;
+
+ virtual type_t getType() const override;
+
+private:
+ friend struct _C2BlockFactory;
+
+ void getAHardwareBuffer(AHardwareBuffer **pBuf) const;
+
+ void disown();
+
+ bool mOwned;
+ const AHardwareBuffer *mBuffer;
+ const std::weak_ptr<::aidl::android::hardware::media::c2::IGraphicBufferAllocator> mIgba;
+};
diff --git a/media/codec2/vndk/include/C2PlatformSupport.h b/media/codec2/vndk/include/C2PlatformSupport.h
index dc82e82..221a799 100644
--- a/media/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/codec2/vndk/include/C2PlatformSupport.h
@@ -86,6 +86,15 @@
BLOB,
/**
+ * ID of C2AIDL IGraphicBufferAllocator backed platform allocator.
+ *
+ * C2Handle layout is not public. Use C2AllocatorAhwb::UnwrapNativeCodec2AhwbHandle
+ * to get the underlying gralloc handle from a C2Handle, and WrapNativeCodec2AhwbHandle
+ * to create a C2Handle from a gralloc handle - for C2Allocator::priorAllocation.
+ */
+ IGBA,
+
+ /**
* ID of indicating the end of platform allocator definition.
*
* \note always put this macro in the last place.
diff --git a/media/codec2/vndk/internal/C2BlockInternal.h b/media/codec2/vndk/internal/C2BlockInternal.h
index 81cdb43..8198ee1 100644
--- a/media/codec2/vndk/internal/C2BlockInternal.h
+++ b/media/codec2/vndk/internal/C2BlockInternal.h
@@ -39,6 +39,8 @@
}
+typedef struct AHardwareBuffer AHardwareBuffer;
+
using bufferpool_BufferPoolData = android::hardware::media::bufferpool::BufferPoolData;
using bufferpool2_BufferPoolData = aidl::android::hardware::media::bufferpool2::BufferPoolData;
@@ -50,6 +52,7 @@
TYPE_BUFFERPOOL = 0,
TYPE_BUFFERQUEUE,
TYPE_BUFFERPOOL2, // AIDL-BufferPool
+ TYPE_AHWBUFFER, // AHardwareBuffer based block
};
virtual type_t getType() const = 0;
@@ -174,6 +177,17 @@
const std::shared_ptr<bufferpool_BufferPoolData> &data);
/**
+ * Create a graphic block from the received AHardwareBuffer.
+ *
+ * \param buffer AHardwareBuffer
+ *
+ * \return shared pointer to the graphic block. nullptr if there was not enough memory to
+ * create this block.
+ */
+ static
+ std::shared_ptr<C2GraphicBlock> CreateGraphicBlock(AHardwareBuffer *buffer);
+
+ /**
* Get bufferpool data from the blockpool data.
*
* \param poolData blockpool data
@@ -433,6 +447,31 @@
static
bool DisplayBlockToBufferQueue(
const std::shared_ptr<_C2BlockPoolData>& poolData);
+
+ /**
+ * Retrieves a AHardwareBuffer from data of a graphic block which was
+ * allocated via IGBA based blockpool. Retrieved AHardwareBuffer handle
+ * does not have the ownership. poolData still has the ownership. Use
+ * AHardwareBuffer_acquire()/AHardwareBuffer_release if independent
+ * life-cycle/ownership is required.
+ *
+ * \param[in] poolData blockpool data.
+ * \param[out] pBuf ptr to AHardwareBuffer
+ *
+ * \return true if AHardwareBuffer was returned to output parameter, false
+ * otherwise.
+ */
+ static
+ bool GetAHardwareBuffer(
+ const std::shared_ptr<const _C2BlockPoolData>& poolData,
+ AHardwareBuffer **pBuf);
+
+ /**
+ * Mark a graphic block is not owned by the current process anymore.
+ * (Use this method after transfer is being completed.)
+ */
+ static void DisownIgbaBlock(
+ const std::shared_ptr<_C2BlockPoolData>& poolData);
};
#endif // ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
diff --git a/media/codec2/vndk/platform/C2IgbaBuffer.cpp b/media/codec2/vndk/platform/C2IgbaBuffer.cpp
new file mode 100644
index 0000000..853d5a3
--- /dev/null
+++ b/media/codec2/vndk/platform/C2IgbaBuffer.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2023 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_NDEBUG 0
+#define LOG_TAG "C2IgbaBuffer"
+#include <android-base/logging.h>
+#include <aidl/android/hardware/media/c2/IGraphicBufferAllocator.h>
+#include <vndk/hardware_buffer.h>
+#include <utils/Log.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2FenceFactory.h>
+#include <C2IgbaBufferPriv.h>
+#include <C2PlatformSupport.h>
+
+using ::android::C2AllocatorAhwb;
+using C2IGBA = ::aidl::android::hardware::media::c2::IGraphicBufferAllocator;
+
+namespace {
+int32_t static inline ToAidl(uint32_t u) {return static_cast<int32_t>(u);}
+int64_t static inline ToAidl(uint64_t u) {return static_cast<int64_t>(u);}
+
+c2_nsecs_t static constexpr kBlockingFetchTimeoutNs = 5000000000LL; // 5 secs
+c2_nsecs_t static constexpr kSyncFenceWaitNs = (1000000000LL / 60LL); // 60 fps frame secs
+
+c2_status_t static CreateGraphicBlockFromAhwb(AHardwareBuffer *ahwb,
+ const std::shared_ptr<C2Allocator> &allocator,
+ const std::shared_ptr<C2IGBA> &igba,
+ std::shared_ptr<C2GraphicBlock> *block) {
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ uint64_t origId = 0;
+ CHECK(AHardwareBuffer_getId(ahwb, &origId) == ::android::OK);
+
+ AHardwareBuffer_Desc desc;
+ AHardwareBuffer_describe(ahwb, &desc);
+ const native_handle_t *handle = AHardwareBuffer_getNativeHandle(ahwb);
+ // cloned handle with wrapped data.(independent lifecycle with Ahwb)
+ C2Handle *c2Handle = android::WrapNativeCodec2AhwbHandle(
+ handle,
+ desc.width,
+ desc.height,
+ desc.format,
+ desc.usage,
+ desc.stride,
+ origId);
+ if (!c2Handle) {
+ return C2_NO_MEMORY;
+ }
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ c2_status_t err = allocator->priorGraphicAllocation(c2Handle, &alloc);
+ if (err != C2_OK) {
+ native_handle_close(c2Handle);
+ native_handle_delete(c2Handle);
+ return err;
+ }
+ std::shared_ptr<C2IgbaBlockPoolData> poolData =
+ std::make_shared<C2IgbaBlockPoolData>(ahwb, igba);
+ *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+ return C2_OK;
+ } else {
+ return C2_OMITTED;
+ }
+}
+
+} // anonymous namespace
+
+C2IgbaBlockPoolData::C2IgbaBlockPoolData(
+ const AHardwareBuffer *buffer,
+ const std::shared_ptr<C2IGBA> &igba) : mOwned(true), mBuffer(buffer), mIgba(igba) {
+ CHECK(mBuffer);
+ AHardwareBuffer_acquire(const_cast<AHardwareBuffer *>(mBuffer));
+}
+
+C2IgbaBlockPoolData::~C2IgbaBlockPoolData() {
+ CHECK(mBuffer);
+ if (mOwned) {
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ auto igba = mIgba.lock();
+ if (igba) {
+ uint64_t origId;
+ CHECK(AHardwareBuffer_getId(mBuffer, &origId) == ::android::OK);
+ bool aidlRet = true;
+ ::ndk::ScopedAStatus status = igba->deallocate(origId, &aidlRet);
+ if (!status.isOk() || !aidlRet) {
+ ALOGW("AHwb destruction notifying failure %d(%d)", status.isOk(), aidlRet);
+ }
+ }
+ }
+ }
+ AHardwareBuffer_release(const_cast<AHardwareBuffer *>(mBuffer));
+}
+
+C2IgbaBlockPoolData::type_t C2IgbaBlockPoolData::getType() const {
+ return TYPE_AHWBUFFER;
+}
+
+void C2IgbaBlockPoolData::getAHardwareBuffer(AHardwareBuffer **pBuf) const {
+ *pBuf = const_cast<AHardwareBuffer *>(mBuffer);
+}
+
+void C2IgbaBlockPoolData::disown() {
+ mOwned = false;
+}
+
+std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(AHardwareBuffer *ahwb) {
+ // TODO: get proper allocator? and synchronization? or allocator-less?
+ static std::shared_ptr<C2AllocatorAhwb> sAllocator = std::make_shared<C2AllocatorAhwb>(0);
+ std::shared_ptr<C2GraphicBlock> block;
+ c2_status_t res = CreateGraphicBlockFromAhwb(
+ ahwb, std::static_pointer_cast<C2Allocator>(sAllocator), nullptr, &block);
+ if (res != C2_OK) {
+ return nullptr;
+ }
+ return block;
+}
+
+bool _C2BlockFactory::GetAHardwareBuffer(
+ const std::shared_ptr<const _C2BlockPoolData>& data,
+ AHardwareBuffer **pBuf) {
+ if (data && data->getType() == _C2BlockPoolData::TYPE_AHWBUFFER) {
+ const std::shared_ptr<const C2IgbaBlockPoolData> poolData =
+ std::static_pointer_cast<const C2IgbaBlockPoolData>(data);
+ poolData->getAHardwareBuffer(pBuf);
+ return true;
+ }
+ return false;
+}
+
+void _C2BlockFactory::DisownIgbaBlock(
+ const std::shared_ptr<_C2BlockPoolData>& data) {
+ if (data && data->getType() == _C2BlockPoolData::TYPE_AHWBUFFER) {
+ const std::shared_ptr<C2IgbaBlockPoolData> poolData =
+ std::static_pointer_cast<C2IgbaBlockPoolData>(data);
+ poolData->disown();
+ }
+}
+
+C2IgbaBlockPool::C2IgbaBlockPool(
+ const std::shared_ptr<C2Allocator> &allocator,
+ const std::shared_ptr<C2IGBA> &igba,
+ const local_id_t localId) : mAllocator(allocator), mIgba(igba), mLocalId(localId) {
+ if (!mIgba) {
+ mValid = false;
+ return;
+ }
+ // TODO: Remove IPC (This is a nested IPC call during c2aidl creatBlockPool().
+ ::ndk::ScopedFileDescriptor fd;
+ ::ndk::ScopedAStatus status = mIgba->getWaitableFd(&fd);
+ if (!status.isOk()) {
+ mValid = false;
+ return;
+ }
+ mWaitFence = _C2FenceFactory::CreatePipeFence(fd.release());
+ if (!mWaitFence.valid()) {
+ mValid = false;
+ return;
+ }
+ mValid = true;
+}
+
+c2_status_t C2IgbaBlockPool::fetchGraphicBlock(
+ uint32_t width, uint32_t height, uint32_t format,
+ C2MemoryUsage usage, std::shared_ptr<C2GraphicBlock> *block) {
+ uint64_t origId;
+ C2Fence fence;
+ c2_status_t res = _fetchGraphicBlock(
+ width, height, format, usage, kBlockingFetchTimeoutNs, &origId, block, &fence);
+
+ if (res == C2_BLOCKING) {
+ return C2_TIMED_OUT;
+ }
+ if (res != C2_OK) {
+ return res;
+ }
+ // TODO: bundle the fence to the block. Are API changes required?
+ res = fence.wait(kSyncFenceWaitNs);
+ if (res != C2_OK) {
+ bool aidlRet = true;
+ ::ndk::ScopedAStatus status = mIgba->deallocate(origId, &aidlRet);
+ ALOGE("Waiting a sync fence failed %d aidl(%d: %d)",
+ res, status.isOk(), aidlRet);
+ }
+ return C2_OK;
+}
+
+c2_status_t C2IgbaBlockPool::fetchGraphicBlock(
+ uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block, C2Fence *fence) {
+ uint64_t origId;
+ return _fetchGraphicBlock(width, height, format, usage, 0LL, &origId, block, fence);
+}
+
+c2_status_t C2IgbaBlockPool::_fetchGraphicBlock(
+ uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+ c2_nsecs_t timeoutNs,
+ uint64_t *origId,
+ std::shared_ptr<C2GraphicBlock> *block,
+ C2Fence *fence) {
+ if (!mValid) {
+ return C2_BAD_STATE;
+ }
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ c2_status_t waitRes = mWaitFence.wait(timeoutNs);
+ switch (waitRes) {
+ case C2_CANCELED: {
+ *fence = mWaitFence;
+ return C2_BLOCKING;
+ }
+ case C2_TIMED_OUT: {
+ *fence = mWaitFence;
+ return C2_BLOCKING;
+ }
+ case C2_OK:
+ break;
+ default: { // C2_BAD_STATE
+ mValid = false;
+ return C2_BAD_STATE;
+ }
+ }
+
+ ::android::C2AndroidMemoryUsage memUsage{usage};
+ C2IGBA::Description desc{
+ ToAidl(width), ToAidl(height), ToAidl(format), ToAidl(memUsage.asGrallocUsage())};
+ C2IGBA::Allocation allocation;
+ ::ndk::ScopedAStatus status = mIgba->allocate(desc, &allocation);
+ if (!status.isOk()) {
+ binder_exception_t ex = status.getExceptionCode();
+ if (ex == EX_SERVICE_SPECIFIC) {
+ c2_status_t err = static_cast<c2_status_t>(status.getServiceSpecificError());
+ if (err == C2_BLOCKING) {
+ *fence = mWaitFence;
+ }
+ return err;
+ } else {
+ ALOGW("igba::allocate transaction failed: %d", ex);
+ return C2_CORRUPTED;
+ }
+ }
+
+ *fence = _C2FenceFactory::CreateSyncFence(allocation.fence.release());
+ AHardwareBuffer *ahwb = allocation.buffer.release(); // This is acquired.
+ CHECK(AHardwareBuffer_getId(ahwb, origId) == ::android::OK);
+ c2_status_t res = CreateGraphicBlockFromAhwb(ahwb, mAllocator, mIgba, block);
+ AHardwareBuffer_release(ahwb);
+ if (res != C2_OK) {
+ bool aidlRet = true;
+ ::ndk::ScopedAStatus status = mIgba->deallocate(*origId, &aidlRet);
+ ALOGE("We got AHWB via AIDL but failed to created C2GraphicBlock err(%d) aidl(%d, %d)",
+ res, status.isOk(), aidlRet);
+ }
+ return res;
+ } else {
+ return C2_OMITTED;
+ }
+}
+
+void C2IgbaBlockPool::invalidate() {
+ mValid = false;
+}