/* * Copyright (C) 2022 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_TAG "Gralloc5" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #include #include #include #include #include #include using namespace aidl::android::hardware::graphics::allocator; using namespace aidl::android::hardware::graphics::common; using namespace ::android::hardware::graphics::mapper; using ADataspace = aidl::android::hardware::graphics::common::Dataspace; using APixelFormat = aidl::android::hardware::graphics::common::PixelFormat; namespace android { static const auto kIAllocatorServiceName = IAllocator::descriptor + std::string("/default"); static const auto kIAllocatorMinimumVersion = 2; constexpr const char* kStandardMetadataName = "android.hardware.graphics.common.StandardMetadataType"; // TODO(b/72323293, b/72703005): Remove these invalid bits from callers static constexpr uint64_t kRemovedUsageBits = static_cast((1 << 10) | (1 << 13)); typedef AIMapper_Error (*AIMapper_loadIMapperFn)(AIMapper *_Nullable *_Nonnull outImplementation); struct Gralloc5 { std::shared_ptr allocator; AIMapper *mapper = nullptr; }; static std::shared_ptr waitForAllocator() { if (__builtin_available(android 31, *)) { if (!AServiceManager_isDeclared(kIAllocatorServiceName.c_str())) { return nullptr; } auto allocator = IAllocator::fromBinder( ndk::SpAIBinder(AServiceManager_waitForService(kIAllocatorServiceName.c_str()))); if (!allocator) { ALOGE("AIDL IAllocator declared but failed to get service"); return nullptr; } int32_t version = 0; if (!allocator->getInterfaceVersion(&version).isOk()) { ALOGE("Failed to query interface version"); return nullptr; } if (version < kIAllocatorMinimumVersion) { return nullptr; } return allocator; } else { // TODO: LOG_ALWAYS_FATAL("libui is not backwards compatible"); return nullptr; } } static void *loadIMapperLibrary() { static void *imapperLibrary = []() -> void * { auto allocator = waitForAllocator(); std::string mapperSuffix; auto status = allocator->getIMapperLibrarySuffix(&mapperSuffix); if (!status.isOk()) { ALOGE("Failed to get IMapper library suffix"); return nullptr; } void* so = nullptr; // TODO(b/322384429) switch this to __ANDROID_API_V__ when V is finalized if API_LEVEL_AT_LEAST(__ANDROID_API_FUTURE__, 202404) { so = AServiceManager_openDeclaredPassthroughHal("mapper", mapperSuffix.c_str(), RTLD_LOCAL | RTLD_NOW); } else { std::string lib_name = "mapper." + mapperSuffix + ".so"; so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW); } if (!so) { ALOGE("Failed to load mapper.%s.so", mapperSuffix.c_str()); } return so; }(); return imapperLibrary; } static const Gralloc5 &getInstance() { static Gralloc5 instance = []() { auto allocator = waitForAllocator(); if (!allocator) { return Gralloc5{}; } void *so = loadIMapperLibrary(); if (!so) { return Gralloc5{}; } auto loadIMapper = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper"); AIMapper *mapper = nullptr; AIMapper_Error error = loadIMapper(&mapper); if (error != AIMAPPER_ERROR_NONE) { ALOGE("AIMapper_loadIMapper failed %d", error); return Gralloc5{}; } return Gralloc5{std::move(allocator), mapper}; }(); return instance; } template static auto getStandardMetadata(AIMapper *mapper, buffer_handle_t bufferHandle) -> decltype(StandardMetadata::value::decode(nullptr, 0)) { using Value = typename StandardMetadata::value; // TODO: Tune for common-case better FatVector buffer; int32_t sizeRequired = mapper->v5.getStandardMetadata(bufferHandle, static_cast(T), buffer.data(), buffer.size()); if (sizeRequired < 0) { ALOGW_IF(-AIMAPPER_ERROR_UNSUPPORTED != sizeRequired, "Unexpected error %d from valid getStandardMetadata call", -sizeRequired); return std::nullopt; } if ((size_t)sizeRequired > buffer.size()) { buffer.resize(sizeRequired); sizeRequired = mapper->v5.getStandardMetadata(bufferHandle, static_cast(T), buffer.data(), buffer.size()); } if (sizeRequired < 0 || (size_t)sizeRequired > buffer.size()) { ALOGW("getStandardMetadata failed, received %d with buffer size %zd", sizeRequired, buffer.size()); // Generate a fail type return std::nullopt; } return Value::decode(buffer.data(), sizeRequired); } template static AIMapper_Error setStandardMetadata(AIMapper *mapper, buffer_handle_t bufferHandle, const typename StandardMetadata::value_type &value) { using Value = typename StandardMetadata::value; int32_t sizeRequired = Value::encode(value, nullptr, 0); if (sizeRequired < 0) { ALOGW("Failed to calculate required size"); return static_cast(-sizeRequired); } FatVector buffer; buffer.resize(sizeRequired); sizeRequired = Value::encode(value, buffer.data(), buffer.size()); if (sizeRequired < 0 || (size_t)sizeRequired > buffer.size()) { ALOGW("Failed to encode with calculated size %d; buffer size %zd", sizeRequired, buffer.size()); return static_cast(-sizeRequired); } return mapper->v5.setStandardMetadata(bufferHandle, static_cast(T), buffer.data(), sizeRequired); } Gralloc5Allocator::Gralloc5Allocator(const Gralloc5Mapper &mapper) : mMapper(mapper) { mAllocator = getInstance().allocator; } bool Gralloc5Allocator::isLoaded() const { return mAllocator != nullptr; } static uint64_t getValidUsageBits() { static const uint64_t validUsageBits = []() -> uint64_t { uint64_t bits = 0; for (const auto bit : ndk::enum_range{}) { bits |= static_cast(bit); } return bits; }(); return validUsageBits | kRemovedUsageBits; } static std::optional makeDescriptor(std::string requestorName, uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage) { uint64_t validUsageBits = getValidUsageBits(); if (usage & ~validUsageBits) { ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64, usage & ~validUsageBits); return std::nullopt; } BufferDescriptorInfo descriptorInfo{ .width = static_cast(width), .height = static_cast(height), .layerCount = static_cast(layerCount), .format = static_cast<::aidl::android::hardware::graphics::common::PixelFormat>(format), .usage = static_cast(usage), }; auto nameLength = std::min(requestorName.length(), descriptorInfo.name.size() - 1); memcpy(descriptorInfo.name.data(), requestorName.data(), nameLength); requestorName.data()[nameLength] = 0; return descriptorInfo; } std::string Gralloc5Allocator::dumpDebugInfo(bool less) const { return mMapper.dumpBuffers(less); } status_t Gralloc5Allocator::allocate(std::string requestorName, uint32_t width, uint32_t height, android::PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t* outStride, buffer_handle_t* outBufferHandles, bool importBuffers) const { auto result = allocate(GraphicBufferAllocator::AllocationRequest{ .importBuffer = importBuffers, .width = width, .height = height, .format = format, .layerCount = layerCount, .usage = usage, .requestorName = requestorName, }); *outStride = result.stride; outBufferHandles[0] = result.handle; return result.status; } GraphicBufferAllocator::AllocationResult Gralloc5Allocator::allocate( const GraphicBufferAllocator::AllocationRequest& request) const { auto descriptorInfo = makeDescriptor(request.requestorName, request.width, request.height, request.format, request.layerCount, request.usage); if (!descriptorInfo) { return GraphicBufferAllocator::AllocationResult{BAD_VALUE}; } descriptorInfo->additionalOptions.reserve(request.extras.size()); for (const auto& option : request.extras) { ExtendableType type; type.name = option.name; type.value = option.value; descriptorInfo->additionalOptions.push_back(std::move(type)); } AllocationResult result; auto status = mAllocator->allocate2(*descriptorInfo, 1, &result); if (!status.isOk()) { auto error = status.getExceptionCode(); if (error == EX_SERVICE_SPECIFIC) { switch (static_cast(status.getServiceSpecificError())) { case AllocationError::BAD_DESCRIPTOR: error = BAD_VALUE; break; case AllocationError::NO_RESOURCES: error = NO_MEMORY; break; default: error = UNKNOWN_ERROR; break; } } return GraphicBufferAllocator::AllocationResult{error}; } GraphicBufferAllocator::AllocationResult ret{OK}; if (request.importBuffer) { auto handle = makeFromAidl(result.buffers[0]); auto error = mMapper.importBuffer(handle, &ret.handle); native_handle_delete(handle); if (error != NO_ERROR) { return GraphicBufferAllocator::AllocationResult{error}; } } else { ret.handle = dupFromAidl(result.buffers[0]); if (!ret.handle) { return GraphicBufferAllocator::AllocationResult{NO_MEMORY}; } } ret.stride = result.stride; // Release all the resources held by AllocationResult (specifically any remaining FDs) result = {}; // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now // TODO: Re-enable this at some point if it's necessary. We can't do it now because libui // is marked apex_available (b/214400477) and libbinder isn't (which of course is correct) // IPCThreadState::self()->flushCommands(); return ret; } void Gralloc5Mapper::preload() { // TODO(b/261858155): Implement. We can't bounce off of IAllocator for this because zygote can't // use binder. So when an alternate strategy of retrieving the library prefix is available, // use that here. } Gralloc5Mapper::Gralloc5Mapper() { mMapper = getInstance().mapper; } bool Gralloc5Mapper::isLoaded() const { return mMapper != nullptr && mMapper->version >= AIMAPPER_VERSION_5; } static bool isStandardMetadata(AIMapper_MetadataType metadataType) { return strcmp(kStandardMetadataName, metadataType.name) == 0; } struct DumpBufferResult { uint64_t bufferId; std::string name; uint64_t width; uint64_t height; uint64_t layerCount; APixelFormat pixelFormatRequested; uint32_t pixelFormatFourCC; uint64_t pixelFormatModifier; BufferUsage usage; ADataspace dataspace; uint64_t allocationSize; uint64_t protectedContent; ExtendableType compression; ExtendableType interlaced; ExtendableType chromaSiting; std::vector planeLayouts; }; #define DECODE_TO(name, output) \ case StandardMetadataType::name: \ output = StandardMetadata::value ::decode(value, valueSize) \ .value(); \ break static void dumpBufferCommon(DumpBufferResult* outResult, AIMapper_MetadataType metadataType, const void* value, size_t valueSize) { if (!isStandardMetadata(metadataType)) { return; } StandardMetadataType type = (StandardMetadataType)metadataType.value; switch (type) { DECODE_TO(BUFFER_ID, outResult->bufferId); DECODE_TO(NAME, outResult->name); DECODE_TO(WIDTH, outResult->width); DECODE_TO(HEIGHT, outResult->height); DECODE_TO(LAYER_COUNT, outResult->layerCount); DECODE_TO(PIXEL_FORMAT_REQUESTED, outResult->pixelFormatRequested); DECODE_TO(PIXEL_FORMAT_FOURCC, outResult->pixelFormatFourCC); DECODE_TO(PIXEL_FORMAT_MODIFIER, outResult->pixelFormatModifier); DECODE_TO(USAGE, outResult->usage); DECODE_TO(DATASPACE, outResult->dataspace); DECODE_TO(ALLOCATION_SIZE, outResult->allocationSize); DECODE_TO(PROTECTED_CONTENT, outResult->protectedContent); DECODE_TO(COMPRESSION, outResult->compression); DECODE_TO(INTERLACED, outResult->interlaced); DECODE_TO(CHROMA_SITING, outResult->chromaSiting); DECODE_TO(PLANE_LAYOUTS, outResult->planeLayouts); default: break; } } #undef DECODE_TO template {}>> constexpr std::underlying_type_t to_underlying(EnumT e) noexcept { return static_cast>(e); } static void writeDumpToStream(const DumpBufferResult& bufferDump, std::ostream& outDump, bool less) { double allocationSizeKiB = static_cast(bufferDump.allocationSize) / 1024; outDump << "+ name:" << bufferDump.name << ", id:" << bufferDump.bufferId << ", size:" << std::fixed << allocationSizeKiB << "KiB, w/h:" << bufferDump.width << "x" << bufferDump.height << ", usage: 0x" << std::hex << to_underlying(bufferDump.usage) << std::dec << ", req fmt:" << to_underlying(bufferDump.pixelFormatRequested) << ", fourcc/mod:" << bufferDump.pixelFormatFourCC << "/" << bufferDump.pixelFormatModifier << ", dataspace: 0x" << std::hex << to_underlying(bufferDump.dataspace) << std::dec << ", compressed: "; if (less) { bool isCompressed = !gralloc4::isStandardCompression(bufferDump.compression) || (gralloc4::getStandardCompressionValue(bufferDump.compression) != ui::Compression::NONE); outDump << std::boolalpha << isCompressed << "\n"; } else { outDump << gralloc4::getCompressionName(bufferDump.compression) << "\n"; } if (!less) { bool firstPlane = true; for (const auto& planeLayout : bufferDump.planeLayouts) { if (firstPlane) { firstPlane = false; outDump << "\tplanes: "; } else { outDump << "\t "; } for (size_t i = 0; i < planeLayout.components.size(); i++) { const auto& planeLayoutComponent = planeLayout.components[i]; outDump << gralloc4::getPlaneLayoutComponentTypeName(planeLayoutComponent.type); if (i < planeLayout.components.size() - 1) { outDump << "/"; } else { outDump << ":\t"; } } outDump << " w/h:" << planeLayout.widthInSamples << "x" << planeLayout.heightInSamples << ", stride:" << planeLayout.strideInBytes << " bytes, size:" << planeLayout.totalSizeInBytes; outDump << ", inc:" << planeLayout.sampleIncrementInBits << " bits, subsampling w/h:" << planeLayout.horizontalSubsampling << "x" << planeLayout.verticalSubsampling; outDump << "\n"; } outDump << "\tlayer cnt: " << bufferDump.layerCount << ", protected content: " << bufferDump.protectedContent << ", interlaced: " << gralloc4::getInterlacedName(bufferDump.interlaced) << ", chroma siting:" << gralloc4::getChromaSitingName(bufferDump.chromaSiting) << "\n"; } } std::string Gralloc5Mapper::dumpBuffer(buffer_handle_t bufferHandle, bool less) const { DumpBufferResult bufferInfo; AIMapper_DumpBufferCallback dumpBuffer = [](void* contextPtr, AIMapper_MetadataType metadataType, const void* _Nonnull value, size_t valueSize) { DumpBufferResult* context = reinterpret_cast(contextPtr); dumpBufferCommon(context, metadataType, value, valueSize); }; AIMapper_Error error = mMapper->v5.dumpBuffer(bufferHandle, dumpBuffer, &bufferInfo); if (error != AIMAPPER_ERROR_NONE) { ALOGE("Error dumping buffer: %d", error); return std::string{}; } std::ostringstream stream; stream.precision(2); writeDumpToStream(bufferInfo, stream, less); return stream.str(); } std::string Gralloc5Mapper::dumpBuffers(bool less) const { class DumpAllBuffersContext { private: bool mHasPending = false; DumpBufferResult mPending; std::vector mResults; public: DumpAllBuffersContext() { mResults.reserve(10); } void commit() { if (mHasPending) { mResults.push_back(mPending); mHasPending = false; } } DumpBufferResult* write() { mHasPending = true; return &mPending; } const std::vector& results() { commit(); return mResults; } } context; AIMapper_BeginDumpBufferCallback beginCallback = [](void* contextPtr) { DumpAllBuffersContext* context = reinterpret_cast(contextPtr); context->commit(); }; AIMapper_DumpBufferCallback dumpBuffer = [](void* contextPtr, AIMapper_MetadataType metadataType, const void* _Nonnull value, size_t valueSize) { DumpAllBuffersContext* context = reinterpret_cast(contextPtr); dumpBufferCommon(context->write(), metadataType, value, valueSize); }; AIMapper_Error error = mMapper->v5.dumpAllBuffers(beginCallback, dumpBuffer, &context); if (error != AIMAPPER_ERROR_NONE) { ALOGE("Error dumping buffers: %d", error); return std::string{}; } uint64_t totalAllocationSize = 0; std::ostringstream stream; stream.precision(2); stream << "Imported gralloc buffers:\n"; for (const auto& bufferDump : context.results()) { writeDumpToStream(bufferDump, stream, less); totalAllocationSize += bufferDump.allocationSize; } double totalAllocationSizeKiB = static_cast(totalAllocationSize) / 1024; stream << "Total imported by gralloc: " << totalAllocationSizeKiB << "KiB\n"; return stream.str(); } status_t Gralloc5Mapper::importBuffer(const native_handle_t *rawHandle, buffer_handle_t *outBufferHandle) const { return mMapper->v5.importBuffer(rawHandle, outBufferHandle); } void Gralloc5Mapper::freeBuffer(buffer_handle_t bufferHandle) const { mMapper->v5.freeBuffer(bufferHandle); } status_t Gralloc5Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t stride) const { { auto value = getStandardMetadata(mMapper, bufferHandle); if (width != value) { ALOGW("Width didn't match, expected %d got %" PRId64, width, value.value_or(-1)); return BAD_VALUE; } } { auto value = getStandardMetadata(mMapper, bufferHandle); if (height != value) { ALOGW("Height didn't match, expected %d got %" PRId64, height, value.value_or(-1)); return BAD_VALUE; } } { auto expected = static_cast(format); if (expected != APixelFormat::IMPLEMENTATION_DEFINED) { auto value = getStandardMetadata(mMapper, bufferHandle); if (expected != value) { ALOGW("Format didn't match, expected %d got %s", format, value.has_value() ? toString(*value).c_str() : ""); return BAD_VALUE; } } } { auto value = getStandardMetadata(mMapper, bufferHandle); if (layerCount != value) { ALOGW("Layer count didn't match, expected %d got %" PRId64, layerCount, value.value_or(-1)); return BAD_VALUE; } } // TODO: This can false-positive fail if the allocator adjusted the USAGE bits internally // Investigate further & re-enable or remove, but for now ignoring usage should be OK (void)usage; // { // auto value = getStandardMetadata(mMapper, bufferHandle); // if (static_cast(usage) != value) { // ALOGW("Usage didn't match, expected %" PRIu64 " got %" PRId64, usage, // static_cast(value.value_or(BufferUsage::CPU_READ_NEVER))); // return BAD_VALUE; // } // } { auto value = getStandardMetadata(mMapper, bufferHandle); if (stride != value) { ALOGW("Stride didn't match, expected %" PRIu32 " got %" PRId32, stride, value.value_or(-1)); return BAD_VALUE; } } return OK; } void Gralloc5Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t *outNumFds, uint32_t *outNumInts) const { mMapper->v5.getTransportSize(bufferHandle, outNumFds, outNumInts); } status_t Gralloc5Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect &bounds, int acquireFence, void **outData, int32_t *outBytesPerPixel, int32_t *outBytesPerStride) const { if (outBytesPerPixel) *outBytesPerPixel = -1; if (outBytesPerStride) *outBytesPerStride = -1; auto status = mMapper->v5.lock(bufferHandle, usage, bounds, acquireFence, outData); ALOGW_IF(status != AIMAPPER_ERROR_NONE, "lock(%p, ...) failed: %d", bufferHandle, status); return static_cast(status); } status_t Gralloc5Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect &bounds, int acquireFence, android_ycbcr *outYcbcr) const { if (!outYcbcr) { return BAD_VALUE; } // TODO(b/262279301): Change the return type of ::unlock to unique_fd instead of int so that // ignoring the return value "just works" instead auto unlock = [this](buffer_handle_t bufferHandle) { int fence = this->unlock(bufferHandle); if (fence != -1) { ::close(fence); } }; std::vector planeLayouts; status_t error = getPlaneLayouts(bufferHandle, &planeLayouts); if (error != NO_ERROR) { return error; } void *data = nullptr; error = lock(bufferHandle, usage, bounds, acquireFence, &data, nullptr, nullptr); if (error != NO_ERROR) { return error; } android_ycbcr ycbcr; ycbcr.y = nullptr; ycbcr.cb = nullptr; ycbcr.cr = nullptr; ycbcr.ystride = 0; ycbcr.cstride = 0; ycbcr.chroma_step = 0; for (const auto &planeLayout : planeLayouts) { for (const auto &planeLayoutComponent : planeLayout.components) { if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) { continue; } uint8_t *tmpData = static_cast(data) + planeLayout.offsetInBytes; // Note that `offsetInBits` may not be a multiple of 8 for packed formats (e.g. P010) // but we still want to point to the start of the first byte. tmpData += (planeLayoutComponent.offsetInBits / 8); uint64_t sampleIncrementInBytes; auto type = static_cast(planeLayoutComponent.type.value); switch (type) { case PlaneLayoutComponentType::Y: if ((ycbcr.y != nullptr) || (planeLayout.sampleIncrementInBits % 8 != 0)) { unlock(bufferHandle); return BAD_VALUE; } ycbcr.y = tmpData; ycbcr.ystride = planeLayout.strideInBytes; break; case PlaneLayoutComponentType::CB: case PlaneLayoutComponentType::CR: if (planeLayout.sampleIncrementInBits % 8 != 0) { unlock(bufferHandle); return BAD_VALUE; } sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8; if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2) && (sampleIncrementInBytes != 4)) { unlock(bufferHandle); return BAD_VALUE; } if (ycbcr.cstride == 0 && ycbcr.chroma_step == 0) { ycbcr.cstride = planeLayout.strideInBytes; ycbcr.chroma_step = sampleIncrementInBytes; } else { if ((static_cast(ycbcr.cstride) != planeLayout.strideInBytes) || (ycbcr.chroma_step != sampleIncrementInBytes)) { unlock(bufferHandle); return BAD_VALUE; } } if (type == PlaneLayoutComponentType::CB) { if (ycbcr.cb != nullptr) { unlock(bufferHandle); return BAD_VALUE; } ycbcr.cb = tmpData; } else { if (ycbcr.cr != nullptr) { unlock(bufferHandle); return BAD_VALUE; } ycbcr.cr = tmpData; } break; default: break; }; } } *outYcbcr = ycbcr; return OK; } int Gralloc5Mapper::unlock(buffer_handle_t bufferHandle) const { int fence = -1; AIMapper_Error error = mMapper->v5.unlock(bufferHandle, &fence); if (error != AIMAPPER_ERROR_NONE) { ALOGW("unlock failed with error %d", error); } return fence; } status_t Gralloc5Mapper::isSupported(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, bool *outSupported) const { auto descriptorInfo = makeDescriptor("", width, height, format, layerCount, usage); if (!descriptorInfo) { *outSupported = false; return OK; } auto status = getInstance().allocator->isSupported(*descriptorInfo, outSupported); if (!status.isOk()) { ALOGW("IAllocator::isSupported error %d (%s)", status.getStatus(), status.getMessage()); *outSupported = false; } return OK; } status_t Gralloc5Mapper::getBufferId(buffer_handle_t bufferHandle, uint64_t *outBufferId) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outBufferId = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getName(buffer_handle_t bufferHandle, std::string *outName) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outName = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getWidth(buffer_handle_t bufferHandle, uint64_t *outWidth) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outWidth = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getHeight(buffer_handle_t bufferHandle, uint64_t *outHeight) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outHeight = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getLayerCount(buffer_handle_t bufferHandle, uint64_t *outLayerCount) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outLayerCount = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getPixelFormatRequested(buffer_handle_t bufferHandle, ui::PixelFormat *outPixelFormatRequested) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outPixelFormatRequested = static_cast(*value); return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getPixelFormatFourCC(buffer_handle_t bufferHandle, uint32_t *outPixelFormatFourCC) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outPixelFormatFourCC = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getPixelFormatModifier(buffer_handle_t bufferHandle, uint64_t *outPixelFormatModifier) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outPixelFormatModifier = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getUsage(buffer_handle_t bufferHandle, uint64_t *outUsage) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outUsage = static_cast(*value); return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getAllocationSize(buffer_handle_t bufferHandle, uint64_t *outAllocationSize) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outAllocationSize = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getProtectedContent(buffer_handle_t bufferHandle, uint64_t *outProtectedContent) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outProtectedContent = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getCompression( buffer_handle_t bufferHandle, aidl::android::hardware::graphics::common::ExtendableType *outCompression) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outCompression = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getCompression(buffer_handle_t bufferHandle, ui::Compression *outCompression) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (!value.has_value()) { return UNKNOWN_TRANSACTION; } if (!gralloc4::isStandardCompression(*value)) { return BAD_TYPE; } *outCompression = gralloc4::getStandardCompressionValue(*value); return OK; } status_t Gralloc5Mapper::getInterlaced( buffer_handle_t bufferHandle, aidl::android::hardware::graphics::common::ExtendableType *outInterlaced) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outInterlaced = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getInterlaced(buffer_handle_t bufferHandle, ui::Interlaced *outInterlaced) const { if (!outInterlaced) { return BAD_VALUE; } ExtendableType interlaced; status_t error = getInterlaced(bufferHandle, &interlaced); if (error) { return error; } if (!gralloc4::isStandardInterlaced(interlaced)) { return BAD_TYPE; } *outInterlaced = gralloc4::getStandardInterlacedValue(interlaced); return NO_ERROR; } status_t Gralloc5Mapper::getChromaSiting( buffer_handle_t bufferHandle, aidl::android::hardware::graphics::common::ExtendableType *outChromaSiting) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outChromaSiting = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getChromaSiting(buffer_handle_t bufferHandle, ui::ChromaSiting *outChromaSiting) const { if (!outChromaSiting) { return BAD_VALUE; } ExtendableType chromaSiting; status_t error = getChromaSiting(bufferHandle, &chromaSiting); if (error) { return error; } if (!gralloc4::isStandardChromaSiting(chromaSiting)) { return BAD_TYPE; } *outChromaSiting = gralloc4::getStandardChromaSitingValue(chromaSiting); return NO_ERROR; } status_t Gralloc5Mapper::getPlaneLayouts(buffer_handle_t bufferHandle, std::vector *outPlaneLayouts) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outPlaneLayouts = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getDataspace(buffer_handle_t bufferHandle, ui::Dataspace *outDataspace) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outDataspace = static_cast(*value); return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace) const { return setStandardMetadata(mMapper, bufferHandle, static_cast(dataspace)); } status_t Gralloc5Mapper::getBlendMode(buffer_handle_t bufferHandle, ui::BlendMode *outBlendMode) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outBlendMode = static_cast(*value); return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::getSmpte2086(buffer_handle_t bufferHandle, std::optional *outSmpte2086) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outSmpte2086 = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::setSmpte2086(buffer_handle_t bufferHandle, std::optional smpte2086) const { return setStandardMetadata(mMapper, bufferHandle, smpte2086); } status_t Gralloc5Mapper::getCta861_3(buffer_handle_t bufferHandle, std::optional *outCta861_3) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outCta861_3 = *value; return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::setCta861_3(buffer_handle_t bufferHandle, std::optional cta861_3) const { return setStandardMetadata(mMapper, bufferHandle, cta861_3); } status_t Gralloc5Mapper::getSmpte2094_40( buffer_handle_t bufferHandle, std::optional> *outSmpte2094_40) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outSmpte2094_40 = std::move(*value); return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::setSmpte2094_40(buffer_handle_t bufferHandle, std::optional> smpte2094_40) const { return setStandardMetadata(mMapper, bufferHandle, smpte2094_40); } status_t Gralloc5Mapper::getSmpte2094_10( buffer_handle_t bufferHandle, std::optional> *outSmpte2094_10) const { auto value = getStandardMetadata(mMapper, bufferHandle); if (value.has_value()) { *outSmpte2094_10 = std::move(*value); return OK; } return UNKNOWN_TRANSACTION; } status_t Gralloc5Mapper::setSmpte2094_10(buffer_handle_t bufferHandle, std::optional> smpte2094_10) const { return setStandardMetadata(mMapper, bufferHandle, smpte2094_10); } } // namespace android