| /* |
| * Copyright 2022 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include <aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.h> |
| #include <aidl/android/hardware/graphics/common/BufferUsage.h> |
| #include <aidl/android/hardware/graphics/common/PixelFormat.h> |
| #include <aidl/android/hardware/graphics/common/StandardMetadataType.h> |
| #include <android-base/unique_fd.h> |
| #include <android/hardware/graphics/mapper/IMapper.h> |
| #include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h> |
| #include <android/hardware/graphics/mapper/utils/IMapperProvider.h> |
| #include <cutils/native_handle.h> |
| #include <gralloctypes/Gralloc4.h> |
| |
| #include "cros_gralloc/cros_gralloc_driver.h" |
| #include "cros_gralloc/cros_gralloc_handle.h" |
| #include "cros_gralloc/gralloc4/CrosGralloc4Metadata.h" |
| #include "cros_gralloc/gralloc4/CrosGralloc4Utils.h" |
| |
| using namespace ::aidl::android::hardware::graphics::common; |
| using namespace ::android::hardware::graphics::mapper; |
| using ::aidl::android::hardware::graphics::allocator::BufferDescriptorInfo; |
| using ::android::base::unique_fd; |
| |
| #define REQUIRE_DRIVER() \ |
| if (!mDriver) { \ |
| ALOGE("Failed to %s. Driver is uninitialized.", __func__); \ |
| return AIMAPPER_ERROR_NO_RESOURCES; \ |
| } |
| |
| #define VALIDATE_BUFFER_HANDLE(bufferHandle) \ |
| if (!(bufferHandle)) { \ |
| ALOGE("Failed to %s. Null buffer_handle_t.", __func__); \ |
| return AIMAPPER_ERROR_BAD_BUFFER; \ |
| } |
| |
| #define VALIDATE_DRIVER_AND_BUFFER_HANDLE(bufferHandle) \ |
| REQUIRE_DRIVER() \ |
| VALIDATE_BUFFER_HANDLE(bufferHandle) |
| |
| static_assert(CROS_GRALLOC4_METADATA_MAX_NAME_SIZE >= |
| decltype(std::declval<BufferDescriptorInfo>().name){}.size(), |
| "Metadata name storage too small to fit a BufferDescriptorInfo::name"); |
| |
| constexpr const char* STANDARD_METADATA_NAME = |
| "android.hardware.graphics.common.StandardMetadataType"; |
| |
| static bool isStandardMetadata(AIMapper_MetadataType metadataType) { |
| return strcmp(STANDARD_METADATA_NAME, metadataType.name) == 0; |
| } |
| |
| class CrosGrallocMapperV5 final : public vendor::mapper::IMapperV5Impl { |
| private: |
| cros_gralloc_driver* mDriver = cros_gralloc_driver::get_instance(); |
| |
| public: |
| explicit CrosGrallocMapperV5() = default; |
| ~CrosGrallocMapperV5() override = default; |
| |
| AIMapper_Error importBuffer(const native_handle_t* _Nonnull handle, |
| buffer_handle_t _Nullable* _Nonnull outBufferHandle) override; |
| |
| AIMapper_Error freeBuffer(buffer_handle_t _Nonnull buffer) override; |
| |
| AIMapper_Error getTransportSize(buffer_handle_t _Nonnull buffer, uint32_t* _Nonnull outNumFds, |
| uint32_t* _Nonnull outNumInts) override; |
| |
| AIMapper_Error lock(buffer_handle_t _Nonnull buffer, uint64_t cpuUsage, ARect accessRegion, |
| int acquireFence, void* _Nullable* _Nonnull outData) override; |
| |
| AIMapper_Error unlock(buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence) override; |
| |
| AIMapper_Error flushLockedBuffer(buffer_handle_t _Nonnull buffer) override; |
| |
| AIMapper_Error rereadLockedBuffer(buffer_handle_t _Nonnull buffer) override; |
| |
| int32_t getMetadata(buffer_handle_t _Nonnull buffer, AIMapper_MetadataType metadataType, |
| void* _Nonnull outData, size_t outDataSize) override; |
| |
| int32_t getStandardMetadata(buffer_handle_t _Nonnull buffer, int64_t standardMetadataType, |
| void* _Nonnull outData, size_t outDataSize) override; |
| |
| AIMapper_Error setMetadata(buffer_handle_t _Nonnull buffer, AIMapper_MetadataType metadataType, |
| const void* _Nonnull metadata, size_t metadataSize) override; |
| |
| AIMapper_Error setStandardMetadata(buffer_handle_t _Nonnull buffer, |
| int64_t standardMetadataType, const void* _Nonnull metadata, |
| size_t metadataSize) override; |
| |
| AIMapper_Error listSupportedMetadataTypes( |
| const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList, |
| size_t* _Nonnull outNumberOfDescriptions) override; |
| |
| AIMapper_Error dumpBuffer(buffer_handle_t _Nonnull bufferHandle, |
| AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback, |
| void* _Null_unspecified context) override; |
| |
| AIMapper_Error dumpAllBuffers(AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback, |
| AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback, |
| void* _Null_unspecified context) override; |
| |
| AIMapper_Error getReservedRegion(buffer_handle_t _Nonnull buffer, |
| void* _Nullable* _Nonnull outReservedRegion, |
| uint64_t* _Nonnull outReservedSize) override; |
| |
| private: |
| enum class ReservedRegionArea { |
| /* CrosGralloc4Metadata */ |
| MAPPER4_METADATA, |
| |
| /* External user metadata */ |
| USER_METADATA, |
| }; |
| |
| AIMapper_Error getReservedRegionArea(const cros_gralloc_buffer* crosBuffer, |
| ReservedRegionArea area, void** outAddr, |
| uint64_t* outSize); |
| |
| AIMapper_Error getCrosMetadata(const cros_gralloc_buffer* crosBuffer, |
| const CrosGralloc4Metadata** outMetadata); |
| |
| AIMapper_Error getMutableCrosMetadata(cros_gralloc_buffer* crosBuffer, |
| CrosGralloc4Metadata** outMetadata); |
| |
| template <typename F, StandardMetadataType TYPE> |
| int32_t getStandardMetadata(const cros_gralloc_buffer* crosBuffer, F&& provide, |
| StandardMetadata<TYPE>); |
| |
| template <StandardMetadataType TYPE> |
| AIMapper_Error setStandardMetadata(CrosGralloc4Metadata* crosMetadata, |
| typename StandardMetadata<TYPE>::value_type&& value); |
| |
| void dumpBuffer( |
| const cros_gralloc_buffer* crosBuffer, |
| std::function<void(AIMapper_MetadataType, const std::vector<uint8_t>&)> callback); |
| }; |
| |
| AIMapper_Error CrosGrallocMapperV5::importBuffer( |
| const native_handle_t* _Nonnull bufferHandle, |
| buffer_handle_t _Nullable* _Nonnull outBufferHandle) { |
| REQUIRE_DRIVER() |
| |
| if (!bufferHandle || bufferHandle->numFds == 0) { |
| ALOGE("Failed to importBuffer. Bad handle."); |
| return AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| |
| native_handle_t* importedBufferHandle = native_handle_clone(bufferHandle); |
| if (!importedBufferHandle) { |
| ALOGE("Failed to importBuffer. Handle clone failed: %s.", strerror(errno)); |
| return AIMAPPER_ERROR_NO_RESOURCES; |
| } |
| |
| int ret = mDriver->retain(importedBufferHandle); |
| if (ret) { |
| native_handle_close(importedBufferHandle); |
| native_handle_delete(importedBufferHandle); |
| return AIMAPPER_ERROR_NO_RESOURCES; |
| } |
| |
| *outBufferHandle = importedBufferHandle; |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::freeBuffer(buffer_handle_t _Nonnull buffer) { |
| VALIDATE_DRIVER_AND_BUFFER_HANDLE(buffer) |
| |
| int ret = mDriver->release(buffer); |
| if (ret) { |
| return AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| |
| native_handle_close(buffer); |
| native_handle_delete(const_cast<native_handle_t*>(buffer)); |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::getTransportSize(buffer_handle_t _Nonnull bufferHandle, |
| uint32_t* _Nonnull outNumFds, |
| uint32_t* _Nonnull outNumInts) { |
| VALIDATE_DRIVER_AND_BUFFER_HANDLE(bufferHandle) |
| |
| // No local process data is currently stored on the native handle. |
| *outNumFds = bufferHandle->numFds; |
| *outNumInts = bufferHandle->numInts; |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::lock(buffer_handle_t _Nonnull bufferHandle, uint64_t cpuUsage, |
| ARect region, int acquireFenceRawFd, |
| void* _Nullable* _Nonnull outData) { |
| // We take ownership of the FD in all cases, even for errors |
| unique_fd acquireFence(acquireFenceRawFd); |
| VALIDATE_DRIVER_AND_BUFFER_HANDLE(bufferHandle) |
| if (cpuUsage == 0) { |
| ALOGE("Failed to lock. Bad cpu usage: %" PRIu64 ".", cpuUsage); |
| return AIMAPPER_ERROR_BAD_VALUE; |
| } |
| |
| uint32_t mapUsage = cros_gralloc_convert_map_usage(cpuUsage); |
| |
| cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle); |
| if (crosHandle == nullptr) { |
| ALOGE("Failed to lock. Invalid handle."); |
| return AIMAPPER_ERROR_BAD_VALUE; |
| } |
| |
| struct rectangle rect; |
| |
| // An access region of all zeros means the entire buffer. |
| if (region.left == 0 && region.top == 0 && region.right == 0 && region.bottom == 0) { |
| rect = {0, 0, crosHandle->width, crosHandle->height}; |
| } else { |
| if (region.left < 0 || region.top < 0 || region.right <= region.left || |
| region.bottom <= region.top) { |
| ALOGE("Failed to lock. Invalid accessRegion: [%d, %d, %d, %d]", region.left, region.top, |
| region.right, region.bottom); |
| return AIMAPPER_ERROR_BAD_VALUE; |
| } |
| |
| if (region.right > crosHandle->width) { |
| ALOGE("Failed to lock. Invalid region: width greater than buffer width (%d vs %d).", |
| region.right, crosHandle->width); |
| return AIMAPPER_ERROR_BAD_VALUE; |
| } |
| |
| if (region.bottom > crosHandle->height) { |
| ALOGE("Failed to lock. Invalid region: height greater than buffer height (%d vs " |
| "%d).", |
| region.bottom, crosHandle->height); |
| return AIMAPPER_ERROR_BAD_VALUE; |
| } |
| |
| rect = {static_cast<uint32_t>(region.left), static_cast<uint32_t>(region.top), |
| static_cast<uint32_t>(region.right - region.left), |
| static_cast<uint32_t>(region.bottom - region.top)}; |
| } |
| |
| uint8_t* addr[DRV_MAX_PLANES]; |
| int32_t status = mDriver->lock(bufferHandle, acquireFence.get(), |
| /*close_acquire_fence=*/false, &rect, mapUsage, addr); |
| if (status) { |
| return AIMAPPER_ERROR_BAD_VALUE; |
| } |
| |
| *outData = addr[0]; |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::unlock(buffer_handle_t _Nonnull buffer, |
| int* _Nonnull releaseFence) { |
| VALIDATE_DRIVER_AND_BUFFER_HANDLE(buffer) |
| int ret = mDriver->unlock(buffer, releaseFence); |
| if (ret) { |
| ALOGE("Failed to unlock."); |
| return AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::flushLockedBuffer(buffer_handle_t _Nonnull buffer) { |
| VALIDATE_DRIVER_AND_BUFFER_HANDLE(buffer) |
| int ret = mDriver->flush(buffer); |
| if (ret) { |
| ALOGE("Failed to flushLockedBuffer. Flush failed."); |
| return AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::rereadLockedBuffer(buffer_handle_t _Nonnull buffer) { |
| VALIDATE_DRIVER_AND_BUFFER_HANDLE(buffer) |
| int ret = mDriver->invalidate(buffer); |
| if (ret) { |
| ALOGE("Failed to rereadLockedBuffer. Failed to invalidate."); |
| return AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| int32_t CrosGrallocMapperV5::getMetadata(buffer_handle_t _Nonnull buffer, |
| AIMapper_MetadataType metadataType, void* _Nonnull outData, |
| size_t outDataSize) { |
| // We don't have any vendor-specific metadata, so divert to getStandardMetadata after validating |
| // that this is a standard metadata request |
| if (isStandardMetadata(metadataType)) { |
| return getStandardMetadata(buffer, metadataType.value, outData, outDataSize); |
| } |
| return -AIMAPPER_ERROR_UNSUPPORTED; |
| } |
| |
| int32_t CrosGrallocMapperV5::getStandardMetadata(buffer_handle_t _Nonnull bufferHandle, |
| int64_t standardType, void* _Nonnull outData, |
| size_t outDataSize) { |
| // Can't use VALIDATE_DRIVER_AND_BUFFER_HANDLE because we need to negate the error |
| // for this call |
| if (!mDriver) { |
| ALOGE("Failed to %s. Driver is uninitialized.", __func__); |
| return -AIMAPPER_ERROR_NO_RESOURCES; |
| } |
| if (!(bufferHandle)) { |
| ALOGE("Failed to %s. Null buffer_handle_t.", __func__); |
| return -AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| |
| cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle); |
| if (!crosHandle) { |
| ALOGE("Failed to get. Invalid handle."); |
| return -AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| |
| int32_t retValue = -AIMAPPER_ERROR_UNSUPPORTED; |
| mDriver->with_buffer(crosHandle, [&](cros_gralloc_buffer* crosBuffer) { |
| auto provider = [&]<StandardMetadataType T>(auto&& provide) -> int32_t { |
| return getStandardMetadata(crosBuffer, provide, StandardMetadata<T>{}); |
| }; |
| retValue = provideStandardMetadata(static_cast<StandardMetadataType>(standardType), outData, |
| outDataSize, provider); |
| }); |
| return retValue; |
| } |
| |
| template <typename F, StandardMetadataType metadataType> |
| int32_t CrosGrallocMapperV5::getStandardMetadata(const cros_gralloc_buffer* crosBuffer, F&& provide, |
| StandardMetadata<metadataType>) { |
| const CrosGralloc4Metadata* crosMetadata = nullptr; |
| if constexpr (metadataType == StandardMetadataType::BLEND_MODE || |
| metadataType == StandardMetadataType::CTA861_3 || |
| metadataType == StandardMetadataType::DATASPACE || |
| metadataType == StandardMetadataType::NAME || |
| metadataType == StandardMetadataType::SMPTE2086) { |
| AIMapper_Error error = getCrosMetadata(crosBuffer, &crosMetadata); |
| if (error != AIMAPPER_ERROR_NONE) { |
| ALOGE("Failed to get. Failed to get buffer metadata."); |
| return -AIMAPPER_ERROR_NO_RESOURCES; |
| } |
| } |
| if constexpr (metadataType == StandardMetadataType::BUFFER_ID) { |
| return provide(crosBuffer->get_id()); |
| } |
| if constexpr (metadataType == StandardMetadataType::NAME) { |
| return provide(crosMetadata->name); |
| } |
| if constexpr (metadataType == StandardMetadataType::WIDTH) { |
| return provide(crosBuffer->get_width()); |
| } |
| if constexpr (metadataType == StandardMetadataType::STRIDE) { |
| return provide(crosBuffer->get_pixel_stride()); |
| } |
| if constexpr (metadataType == StandardMetadataType::HEIGHT) { |
| return provide(crosBuffer->get_height()); |
| } |
| if constexpr (metadataType == StandardMetadataType::LAYER_COUNT) { |
| return provide(1); |
| } |
| if constexpr (metadataType == StandardMetadataType::PIXEL_FORMAT_REQUESTED) { |
| return provide(static_cast<PixelFormat>(crosBuffer->get_android_format())); |
| } |
| if constexpr (metadataType == StandardMetadataType::PIXEL_FORMAT_FOURCC) { |
| return provide(drv_get_standard_fourcc(crosBuffer->get_format())); |
| } |
| if constexpr (metadataType == StandardMetadataType::PIXEL_FORMAT_MODIFIER) { |
| return provide(crosBuffer->get_format_modifier()); |
| } |
| if constexpr (metadataType == StandardMetadataType::USAGE) { |
| return provide(static_cast<BufferUsage>(crosBuffer->get_android_usage())); |
| } |
| if constexpr (metadataType == StandardMetadataType::ALLOCATION_SIZE) { |
| return provide(crosBuffer->get_total_size()); |
| } |
| if constexpr (metadataType == StandardMetadataType::PROTECTED_CONTENT) { |
| uint64_t hasProtectedContent = |
| crosBuffer->get_android_usage() & static_cast<int64_t>(BufferUsage::PROTECTED) ? 1 |
| : 0; |
| return provide(hasProtectedContent); |
| } |
| if constexpr (metadataType == StandardMetadataType::COMPRESSION) { |
| return provide(android::gralloc4::Compression_None); |
| } |
| if constexpr (metadataType == StandardMetadataType::INTERLACED) { |
| return provide(android::gralloc4::Interlaced_None); |
| } |
| if constexpr (metadataType == StandardMetadataType::CHROMA_SITING) { |
| return provide(android::gralloc4::ChromaSiting_None); |
| } |
| if constexpr (metadataType == StandardMetadataType::PLANE_LAYOUTS) { |
| std::vector<PlaneLayout> planeLayouts; |
| getPlaneLayouts(crosBuffer->get_format(), &planeLayouts); |
| |
| for (size_t plane = 0; plane < planeLayouts.size(); plane++) { |
| PlaneLayout& planeLayout = planeLayouts[plane]; |
| planeLayout.offsetInBytes = crosBuffer->get_plane_offset(plane); |
| planeLayout.strideInBytes = crosBuffer->get_plane_stride(plane); |
| planeLayout.totalSizeInBytes = crosBuffer->get_plane_size(plane); |
| planeLayout.widthInSamples = |
| crosBuffer->get_width() / planeLayout.horizontalSubsampling; |
| planeLayout.heightInSamples = |
| crosBuffer->get_height() / planeLayout.verticalSubsampling; |
| } |
| |
| return provide(planeLayouts); |
| } |
| if constexpr (metadataType == StandardMetadataType::CROP) { |
| const uint32_t numPlanes = crosBuffer->get_num_planes(); |
| const uint32_t w = crosBuffer->get_width(); |
| const uint32_t h = crosBuffer->get_height(); |
| std::vector<aidl::android::hardware::graphics::common::Rect> crops; |
| for (uint32_t plane = 0; plane < numPlanes; plane++) { |
| aidl::android::hardware::graphics::common::Rect crop; |
| crop.left = 0; |
| crop.top = 0; |
| crop.right = w; |
| crop.bottom = h; |
| crops.push_back(crop); |
| } |
| |
| return provide(crops); |
| } |
| if constexpr (metadataType == StandardMetadataType::DATASPACE) { |
| return provide(crosMetadata->dataspace); |
| } |
| if constexpr (metadataType == StandardMetadataType::BLEND_MODE) { |
| return provide(crosMetadata->blendMode); |
| } |
| if constexpr (metadataType == StandardMetadataType::SMPTE2086) { |
| return crosMetadata->smpte2086 ? provide(*crosMetadata->smpte2086) : 0; |
| } |
| if constexpr (metadataType == StandardMetadataType::CTA861_3) { |
| return crosMetadata->cta861_3 ? provide(*crosMetadata->cta861_3) : 0; |
| } |
| return -AIMAPPER_ERROR_UNSUPPORTED; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::setMetadata(buffer_handle_t _Nonnull buffer, |
| AIMapper_MetadataType metadataType, |
| const void* _Nonnull metadata, |
| size_t metadataSize) { |
| // We don't have any vendor-specific metadata, so divert to setStandardMetadata after validating |
| // that this is a standard metadata request |
| if (isStandardMetadata(metadataType)) { |
| return setStandardMetadata(buffer, metadataType.value, metadata, metadataSize); |
| } |
| return AIMAPPER_ERROR_UNSUPPORTED; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::setStandardMetadata(buffer_handle_t _Nonnull bufferHandle, |
| int64_t standardTypeRaw, |
| const void* _Nonnull metadata, |
| size_t metadataSize) { |
| VALIDATE_DRIVER_AND_BUFFER_HANDLE(bufferHandle) |
| |
| cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle); |
| if (!crosHandle) { |
| ALOGE("Failed to get. Invalid handle."); |
| return AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| |
| auto standardType = static_cast<StandardMetadataType>(standardTypeRaw); |
| |
| switch (standardType) { |
| // Read-only values |
| case StandardMetadataType::BUFFER_ID: |
| case StandardMetadataType::NAME: |
| case StandardMetadataType::WIDTH: |
| case StandardMetadataType::HEIGHT: |
| case StandardMetadataType::LAYER_COUNT: |
| case StandardMetadataType::PIXEL_FORMAT_REQUESTED: |
| case StandardMetadataType::USAGE: |
| return AIMAPPER_ERROR_BAD_VALUE; |
| |
| // Supported to set |
| case StandardMetadataType::BLEND_MODE: |
| case StandardMetadataType::CTA861_3: |
| case StandardMetadataType::DATASPACE: |
| case StandardMetadataType::SMPTE2086: |
| break; |
| |
| // Everything else unsupported |
| default: |
| return AIMAPPER_ERROR_UNSUPPORTED; |
| } |
| |
| AIMapper_Error status = AIMAPPER_ERROR_UNSUPPORTED; |
| mDriver->with_buffer(crosHandle, [&](cros_gralloc_buffer* crosBuffer) { |
| CrosGralloc4Metadata* crosMetadata = nullptr; |
| status = getMutableCrosMetadata(crosBuffer, &crosMetadata); |
| if (status != AIMAPPER_ERROR_NONE) { |
| return; |
| } |
| |
| auto applier = [&]<StandardMetadataType T>(auto&& value) -> AIMapper_Error { |
| return setStandardMetadata<T>(crosMetadata, std::forward<decltype(value)>(value)); |
| }; |
| |
| status = applyStandardMetadata(standardType, metadata, metadataSize, applier); |
| }); |
| return status; |
| } |
| |
| template <StandardMetadataType TYPE> |
| AIMapper_Error CrosGrallocMapperV5::setStandardMetadata( |
| CrosGralloc4Metadata* crosMetadata, typename StandardMetadata<TYPE>::value_type&& value) { |
| if constexpr (TYPE == StandardMetadataType::BLEND_MODE) { |
| crosMetadata->blendMode = value; |
| } |
| if constexpr (TYPE == StandardMetadataType::CTA861_3) { |
| crosMetadata->cta861_3 = value; |
| } |
| if constexpr (TYPE == StandardMetadataType::DATASPACE) { |
| crosMetadata->dataspace = value; |
| } |
| if constexpr (TYPE == StandardMetadataType::SMPTE2086) { |
| crosMetadata->smpte2086 = value; |
| } |
| // Unsupported metadatas were already filtered before we reached this point |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| constexpr AIMapper_MetadataTypeDescription describeStandard(StandardMetadataType type, |
| bool isGettable, bool isSettable) { |
| return {{STANDARD_METADATA_NAME, static_cast<int64_t>(type)}, |
| nullptr, |
| isGettable, |
| isSettable, |
| {0}}; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::listSupportedMetadataTypes( |
| const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList, |
| size_t* _Nonnull outNumberOfDescriptions) { |
| static constexpr std::array<AIMapper_MetadataTypeDescription, 22> sSupportedMetadaTypes{ |
| describeStandard(StandardMetadataType::BUFFER_ID, true, false), |
| describeStandard(StandardMetadataType::NAME, true, false), |
| describeStandard(StandardMetadataType::WIDTH, true, false), |
| describeStandard(StandardMetadataType::HEIGHT, true, false), |
| describeStandard(StandardMetadataType::LAYER_COUNT, true, false), |
| describeStandard(StandardMetadataType::PIXEL_FORMAT_REQUESTED, true, false), |
| describeStandard(StandardMetadataType::PIXEL_FORMAT_FOURCC, true, false), |
| describeStandard(StandardMetadataType::PIXEL_FORMAT_MODIFIER, true, false), |
| describeStandard(StandardMetadataType::USAGE, true, false), |
| describeStandard(StandardMetadataType::ALLOCATION_SIZE, true, false), |
| describeStandard(StandardMetadataType::PROTECTED_CONTENT, true, false), |
| describeStandard(StandardMetadataType::COMPRESSION, true, false), |
| describeStandard(StandardMetadataType::INTERLACED, true, false), |
| describeStandard(StandardMetadataType::CHROMA_SITING, true, false), |
| describeStandard(StandardMetadataType::PLANE_LAYOUTS, true, false), |
| describeStandard(StandardMetadataType::CROP, true, false), |
| describeStandard(StandardMetadataType::DATASPACE, true, true), |
| describeStandard(StandardMetadataType::COMPRESSION, true, false), |
| describeStandard(StandardMetadataType::BLEND_MODE, true, true), |
| describeStandard(StandardMetadataType::SMPTE2086, true, true), |
| describeStandard(StandardMetadataType::CTA861_3, true, true), |
| describeStandard(StandardMetadataType::STRIDE, true, false), |
| }; |
| *outDescriptionList = sSupportedMetadaTypes.data(); |
| *outNumberOfDescriptions = sSupportedMetadaTypes.size(); |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| void CrosGrallocMapperV5::dumpBuffer( |
| const cros_gralloc_buffer* crosBuffer, |
| std::function<void(AIMapper_MetadataType, const std::vector<uint8_t>&)> callback) { |
| // Temp buffer of ~10kb, should be large enough for any of the metadata we want to dump |
| std::vector<uint8_t> tempBuffer; |
| tempBuffer.resize(10000); |
| AIMapper_MetadataType metadataType; |
| metadataType.name = STANDARD_METADATA_NAME; |
| |
| // Take an instance of the empty StandardMetadat<T> class just to allow auto-deduction |
| // to happen as explicit template invocation on lambdas is ugly |
| auto dump = [&]<StandardMetadataType T>(StandardMetadata<T>) { |
| // Nested templated lambdas! Woo! But the cleanness of the result is worth it |
| // The outer lambda exists basically just to capture the StandardMetadataType that's |
| // being dumped, as the `provider` parameter of getStandardMetadata only knows |
| // the value_type that the enum maps to but not the enum value itself, which we need to |
| // construct the `AIMapper_MetadataType` to pass to the dump callback |
| auto dumpInner = [&](const typename StandardMetadata<T>::value_type& value) -> int32_t { |
| int32_t size = |
| StandardMetadata<T>::value::encode(value, tempBuffer.data(), tempBuffer.size()); |
| // The initial size should always be large enough, but just in case... |
| if (size > tempBuffer.size()) { |
| tempBuffer.resize(size * 2); |
| size = StandardMetadata<T>::value::encode(value, tempBuffer.data(), |
| tempBuffer.size()); |
| } |
| // If the first resize failed _somehow_, just give up. Also don't notify if any |
| // errors occurred during encoding. |
| if (size >= 0 && size <= tempBuffer.size()) { |
| metadataType.value = static_cast<int64_t>(T); |
| callback(metadataType, tempBuffer); |
| } |
| // We don't actually care about the return value in this case, but why not use the |
| // real value anyway |
| return size; |
| }; |
| getStandardMetadata(crosBuffer, dumpInner, StandardMetadata<T>{}); |
| }; |
| |
| // So clean. So pretty. |
| dump(StandardMetadata<StandardMetadataType::BUFFER_ID>{}); |
| dump(StandardMetadata<StandardMetadataType::NAME>{}); |
| dump(StandardMetadata<StandardMetadataType::WIDTH>{}); |
| dump(StandardMetadata<StandardMetadataType::HEIGHT>{}); |
| dump(StandardMetadata<StandardMetadataType::LAYER_COUNT>{}); |
| dump(StandardMetadata<StandardMetadataType::PIXEL_FORMAT_REQUESTED>{}); |
| dump(StandardMetadata<StandardMetadataType::PIXEL_FORMAT_FOURCC>{}); |
| dump(StandardMetadata<StandardMetadataType::PIXEL_FORMAT_MODIFIER>{}); |
| dump(StandardMetadata<StandardMetadataType::USAGE>{}); |
| dump(StandardMetadata<StandardMetadataType::ALLOCATION_SIZE>{}); |
| dump(StandardMetadata<StandardMetadataType::PROTECTED_CONTENT>{}); |
| dump(StandardMetadata<StandardMetadataType::COMPRESSION>{}); |
| dump(StandardMetadata<StandardMetadataType::INTERLACED>{}); |
| dump(StandardMetadata<StandardMetadataType::CHROMA_SITING>{}); |
| dump(StandardMetadata<StandardMetadataType::PLANE_LAYOUTS>{}); |
| dump(StandardMetadata<StandardMetadataType::DATASPACE>{}); |
| dump(StandardMetadata<StandardMetadataType::BLEND_MODE>{}); |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::dumpBuffer( |
| buffer_handle_t _Nonnull bufferHandle, |
| AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback, void* _Null_unspecified context) { |
| VALIDATE_DRIVER_AND_BUFFER_HANDLE(bufferHandle) |
| cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle); |
| if (!crosHandle) { |
| ALOGE("Failed to get. Invalid handle."); |
| return AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| auto callback = [&](AIMapper_MetadataType type, const std::vector<uint8_t>& buffer) { |
| dumpBufferCallback(context, type, buffer.data(), buffer.size()); |
| }; |
| mDriver->with_buffer( |
| crosHandle, [&](cros_gralloc_buffer* crosBuffer) { dumpBuffer(crosBuffer, callback); }); |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::dumpAllBuffers( |
| AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback, |
| AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback, void* _Null_unspecified context) { |
| REQUIRE_DRIVER() |
| auto callback = [&](AIMapper_MetadataType type, const std::vector<uint8_t>& buffer) { |
| dumpBufferCallback(context, type, buffer.data(), buffer.size()); |
| }; |
| mDriver->with_each_buffer([&](cros_gralloc_buffer* crosBuffer) { |
| beginDumpBufferCallback(context); |
| dumpBuffer(crosBuffer, callback); |
| }); |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::getReservedRegion(buffer_handle_t _Nonnull buffer, |
| void* _Nullable* _Nonnull outReservedRegion, |
| uint64_t* _Nonnull outReservedSize) { |
| VALIDATE_DRIVER_AND_BUFFER_HANDLE(buffer) |
| cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(buffer); |
| if (!crosHandle) { |
| ALOGE("Failed to getReservedRegion. Invalid handle."); |
| return AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| |
| void* reservedRegionAddr = nullptr; |
| uint64_t reservedRegionSize = 0; |
| |
| AIMapper_Error error = AIMAPPER_ERROR_NONE; |
| mDriver->with_buffer(crosHandle, [&, this](cros_gralloc_buffer* crosBuffer) { |
| error = getReservedRegionArea(crosBuffer, ReservedRegionArea::USER_METADATA, |
| &reservedRegionAddr, &reservedRegionSize); |
| }); |
| |
| if (error != AIMAPPER_ERROR_NONE) { |
| ALOGE("Failed to getReservedRegion. Failed to getReservedRegionArea."); |
| return AIMAPPER_ERROR_BAD_BUFFER; |
| } |
| |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::getReservedRegionArea(const cros_gralloc_buffer* crosBuffer, |
| ReservedRegionArea area, void** outAddr, |
| uint64_t* outSize) { |
| int ret = crosBuffer->get_reserved_region(outAddr, outSize); |
| if (ret) { |
| ALOGE("Failed to getReservedRegionArea."); |
| *outAddr = nullptr; |
| *outSize = 0; |
| return AIMAPPER_ERROR_NO_RESOURCES; |
| } |
| |
| switch (area) { |
| case ReservedRegionArea::MAPPER4_METADATA: { |
| // CrosGralloc4Metadata resides at the beginning reserved region. |
| *outSize = sizeof(CrosGralloc4Metadata); |
| break; |
| } |
| case ReservedRegionArea::USER_METADATA: { |
| // User metadata resides after the CrosGralloc4Metadata. |
| *outAddr = reinterpret_cast<void*>(reinterpret_cast<char*>(*outAddr) + |
| sizeof(CrosGralloc4Metadata)); |
| *outSize = *outSize - sizeof(CrosGralloc4Metadata); |
| break; |
| } |
| } |
| |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::getCrosMetadata(const cros_gralloc_buffer* crosBuffer, |
| const CrosGralloc4Metadata** outMetadata) { |
| void* addr = nullptr; |
| uint64_t size; |
| |
| auto error = |
| getReservedRegionArea(crosBuffer, ReservedRegionArea::MAPPER4_METADATA, &addr, &size); |
| if (error != AIMAPPER_ERROR_NONE) { |
| return error; |
| } |
| |
| *outMetadata = reinterpret_cast<const CrosGralloc4Metadata*>(addr); |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| AIMapper_Error CrosGrallocMapperV5::getMutableCrosMetadata(cros_gralloc_buffer* crosBuffer, |
| CrosGralloc4Metadata** outMetadata) { |
| void* addr = nullptr; |
| uint64_t size; |
| |
| auto error = |
| getReservedRegionArea(crosBuffer, ReservedRegionArea::MAPPER4_METADATA, &addr, &size); |
| if (error != AIMAPPER_ERROR_NONE) { |
| return error; |
| } |
| |
| *outMetadata = reinterpret_cast<CrosGralloc4Metadata*>(addr); |
| return AIMAPPER_ERROR_NONE; |
| } |
| |
| extern "C" uint32_t ANDROID_HAL_MAPPER_VERSION = AIMAPPER_VERSION_5; |
| |
| extern "C" AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation) { |
| static vendor::mapper::IMapperProvider<CrosGrallocMapperV5> provider; |
| return provider.load(outImplementation); |
| } |