From f72774bf1ce43cf8d275488712a5c2a50d7f5193 Mon Sep 17 00:00:00 2001 From: Pin-chih Lin Date: Tue, 19 Nov 2019 18:26:47 +0800 Subject: [PATCH] codec2: Gralloc blob linear buffer allocator Bug: 143180475 Test: make libcodec2_vndk Change-Id: I55de82ec7029d0759c4cf914ad6c92e170277c78 --- media/codec2/vndk/Android.bp | 1 + media/codec2/vndk/C2AllocatorBlob.cpp | 186 ++++++++++++++++++++ media/codec2/vndk/C2AllocatorGralloc.cpp | 64 +++++++ media/codec2/vndk/include/C2AllocatorBlob.h | 57 ++++++ 4 files changed, 308 insertions(+) create mode 100644 media/codec2/vndk/C2AllocatorBlob.cpp create mode 100644 media/codec2/vndk/include/C2AllocatorBlob.h diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp index 4c529a6f39..e0b3939af6 100644 --- a/media/codec2/vndk/Android.bp +++ b/media/codec2/vndk/Android.bp @@ -16,6 +16,7 @@ cc_library_shared { vendor_available: true, srcs: [ + "C2AllocatorBlob.cpp", "C2AllocatorIon.cpp", "C2AllocatorGralloc.cpp", "C2Buffer.cpp", diff --git a/media/codec2/vndk/C2AllocatorBlob.cpp b/media/codec2/vndk/C2AllocatorBlob.cpp new file mode 100644 index 0000000000..50c9e59af8 --- /dev/null +++ b/media/codec2/vndk/C2AllocatorBlob.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2019 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 "C2AllocatorBlob" + +#include +#include + +#include +#include + +namespace android { + +using ::android::hardware::graphics::common::V1_2::PixelFormat; + +constexpr uint32_t kLinearBufferHeight = 1u; +constexpr uint32_t kLinearBufferFormat = static_cast(PixelFormat::BLOB); + +namespace { + +c2_status_t GetCapacityFromHandle(const C2Handle* const grallocHandle, size_t* capacity) { + uint32_t width, height, format, stride, generation, igbp_slot; + uint64_t usage, igbp_id; + _UnwrapNativeCodec2GrallocMetadata(grallocHandle, &width, &height, &format, &usage, &stride, + &generation, &igbp_id, &igbp_slot); + + if (height != kLinearBufferHeight || format != kLinearBufferFormat) { + return C2_BAD_VALUE; + } + *capacity = width; + return C2_OK; +} + +} // namespace + +// C2AllocationBlob is a wrapper for C2AllocationGralloc allocated by C2AllocatorGralloc. +// C2AllocationBlob::handle() delegates to the backed C2AllocationGralloc::handle(). +class C2AllocationBlob : public C2LinearAllocation { +public: + C2AllocationBlob(std::shared_ptr graphicAllocation, size_t capacity, + C2Allocator::id_t allocatorId); + ~C2AllocationBlob() override; + c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence* fence, + void** addr /* nonnull */) override; + c2_status_t unmap(void* addr, size_t size, C2Fence* fenceFd) override; + + id_t getAllocatorId() const override { return mAllocatorId; } + const C2Handle* handle() const override { return mGraphicAllocation->handle(); } + bool equals(const std::shared_ptr& other) const override { + return other && other->handle() == handle(); + } + +private: + const std::shared_ptr mGraphicAllocation; + const C2Allocator::id_t mAllocatorId; +}; + +C2AllocationBlob::C2AllocationBlob( + std::shared_ptr graphicAllocation, size_t capacity, + C2Allocator::id_t allocatorId) + : C2LinearAllocation(capacity), + mGraphicAllocation(std::move(graphicAllocation)), + mAllocatorId(allocatorId) {} + +C2AllocationBlob::~C2AllocationBlob() {} + +c2_status_t C2AllocationBlob::map(size_t offset, size_t size, C2MemoryUsage usage, + C2Fence* fence, void** addr /* nonnull */) { + C2PlanarLayout layout; + C2Rect rect = C2Rect(size, kLinearBufferHeight).at(offset, 0u); + return mGraphicAllocation->map(rect, usage, fence, &layout, reinterpret_cast(addr)); +} + +c2_status_t C2AllocationBlob::unmap(void* addr, size_t size, C2Fence* fenceFd) { + C2Rect rect(size, kLinearBufferHeight); + return mGraphicAllocation->unmap(reinterpret_cast(&addr), rect, fenceFd); +} + +/* ====================================== BLOB ALLOCATOR ====================================== */ +C2AllocatorBlob::C2AllocatorBlob(id_t id) { + C2MemoryUsage minUsage = {0, 0}; + C2MemoryUsage maxUsage = {C2MemoryUsage::CPU_READ | C2MemoryUsage::READ_PROTECTED, + C2MemoryUsage::CPU_WRITE}; + Traits traits = {"android.allocator.blob", id, LINEAR, minUsage, maxUsage}; + mTraits = std::make_shared(traits); + auto allocatorStore = GetCodec2PlatformAllocatorStore(); + allocatorStore->fetchAllocator(C2PlatformAllocatorStore::GRALLOC, &mC2AllocatorGralloc); + if (!mC2AllocatorGralloc) { + ALOGE("Failed to obtain C2AllocatorGralloc as backed allocator"); + } +} + +C2AllocatorBlob::~C2AllocatorBlob() {} + +c2_status_t C2AllocatorBlob::newLinearAllocation( + uint32_t capacity, C2MemoryUsage usage, std::shared_ptr* allocation) { + if (allocation == nullptr) { + return C2_BAD_VALUE; + } + + allocation->reset(); + + if (!mC2AllocatorGralloc) { + return C2_CORRUPTED; + } + + std::shared_ptr graphicAllocation; + c2_status_t status = mC2AllocatorGralloc->newGraphicAllocation( + capacity, kLinearBufferHeight, kLinearBufferFormat, usage, &graphicAllocation); + if (status != C2_OK) { + ALOGE("Failed newGraphicAllocation"); + return status; + } + + allocation->reset(new C2AllocationBlob(std::move(graphicAllocation), + static_cast(capacity), mTraits->id)); + return C2_OK; +} + +c2_status_t C2AllocatorBlob::priorLinearAllocation( + const C2Handle* handle, std::shared_ptr* allocation) { + if (allocation == nullptr) { + return C2_BAD_VALUE; + } + + allocation->reset(); + + if (!mC2AllocatorGralloc) { + return C2_CORRUPTED; + } + + std::shared_ptr graphicAllocation; + c2_status_t status = mC2AllocatorGralloc->priorGraphicAllocation(handle, &graphicAllocation); + if (status != C2_OK) { + ALOGE("Failed priorGraphicAllocation"); + return status; + } + + const C2Handle* const grallocHandle = graphicAllocation->handle(); + size_t capacity = 0; + status = GetCapacityFromHandle(grallocHandle, &capacity); + if (status != C2_OK) { + ALOGE("Failed to extract capacity from Handle"); + return status; + } + + allocation->reset(new C2AllocationBlob(std::move(graphicAllocation), capacity, mTraits->id)); + return C2_OK; +} + +id_t C2AllocatorBlob::getId() const { + return mTraits->id; +} + +C2String C2AllocatorBlob::getName() const { + return mTraits->name; +} + +std::shared_ptr C2AllocatorBlob::getTraits() const { + return mTraits; +} + +// static +bool C2AllocatorBlob::isValid(const C2Handle* const o) { + size_t capacity; + // Distinguish C2Handle purely allocated by C2AllocatorGralloc, or one allocated through + // C2AllocatorBlob, by checking the handle's height is 1, and its format is + // PixelFormat::BLOB by GetCapacityFromHandle(). + return C2AllocatorGralloc::isValid(o) && GetCapacityFromHandle(o, &capacity) == C2_OK; +} + +} // namespace android diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp index fecbba3de4..78ac35507f 100644 --- a/media/codec2/vndk/C2AllocatorGralloc.cpp +++ b/media/codec2/vndk/C2AllocatorGralloc.cpp @@ -810,6 +810,70 @@ c2_status_t C2AllocationGralloc::map( break; } + case PixelFormat4::BLOB: { + void* pointer = nullptr; + if (mMapper2) { + if (!mMapper2->lock(const_cast(mBuffer), grallocUsage, + {(int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, + (int32_t)rect.height}, + // TODO: fence + hidl_handle(), + [&err, &pointer](const auto& maperr, const auto& mapPointer) { + err = maperr2error(maperr); + if (err == C2_OK) { + pointer = mapPointer; + } + }).isOk()) { + ALOGE("failed transaction: lock(BLOB)"); + return C2_CORRUPTED; + } + } else if (mMapper3) { + if (!mMapper3->lock( + const_cast(mBuffer), + grallocUsage, + { (int32_t)rect.left, (int32_t)rect.top, + (int32_t)rect.width, (int32_t)rect.height }, + // TODO: fence + hidl_handle(), + [&err, &pointer](const auto &maperr, const auto &mapPointer, + int32_t bytesPerPixel, int32_t bytesPerStride) { + err = maperr2error(maperr); + if (err == C2_OK) { + pointer = mapPointer; + } + (void)bytesPerPixel; + (void)bytesPerStride; + }).isOk()) { + ALOGE("failed transaction: lock(BLOB) (@3.0)"); + return C2_CORRUPTED; + } + } else { + if (!mMapper4->lock( + const_cast(mBuffer), + grallocUsage, + { (int32_t)rect.left, (int32_t)rect.top, + (int32_t)rect.width, (int32_t)rect.height }, + // TODO: fence + hidl_handle(), + [&err, &pointer](const auto &maperr, const auto &mapPointer) { + err = maperr2error(maperr); + if (err == C2_OK) { + pointer = mapPointer; + } + }).isOk()) { + ALOGE("failed transaction: lock(BLOB) (@4.0)"); + return C2_CORRUPTED; + } + } + if (err != C2_OK) { + ALOGD("lock failed: %d", err); + return err; + } + + *addr = static_cast(pointer); + break; + } + case PixelFormat4::YCBCR_420_888: // fall-through case PixelFormat4::YV12: diff --git a/media/codec2/vndk/include/C2AllocatorBlob.h b/media/codec2/vndk/include/C2AllocatorBlob.h new file mode 100644 index 0000000000..89ce949cea --- /dev/null +++ b/media/codec2/vndk/include/C2AllocatorBlob.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef STAGEFRIGHT_CODEC2_ALLOCATOR_BLOB_H_ +#define STAGEFRIGHT_CODEC2_ALLOCATOR_BLOB_H_ + +#include + +#include +#include + +namespace android { + +class C2AllocatorBlob : public C2Allocator { +public: + virtual id_t getId() const override; + + virtual C2String getName() const override; + + virtual std::shared_ptr getTraits() const override; + + virtual c2_status_t newLinearAllocation( + uint32_t capacity, C2MemoryUsage usage, + std::shared_ptr *allocation) override; + + virtual c2_status_t priorLinearAllocation( + const C2Handle *handle, + std::shared_ptr *allocation) override; + + C2AllocatorBlob(id_t id); + + virtual ~C2AllocatorBlob() override; + + static bool isValid(const C2Handle* const o); + +private: + std::shared_ptr mTraits; + // Design as C2AllocatorGralloc-backed to unify Gralloc implementations. + std::shared_ptr mC2AllocatorGralloc; +}; + +} // namespace android + +#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_BLOB_H_