blob: d81fa5aed26f9a5cfdf6f28aee3f4d9de29b4e05 [file] [log] [blame]
/*
* Copyright (c) 2011-2018, 2020-2021 The Linux Foundation. All rights reserved.
* Not a Contribution
*
* Copyright (C) 2010 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.
*/
/*
* Changes from Qualcomm Innovation Center are provided under the following license:
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "gr_buf_mgr.h"
#include <QtiGralloc.h>
#include <QtiGrallocPriv.h>
#include <QtiGrallocDefs.h>
#include <gralloctypes/Gralloc4.h>
#include <sys/mman.h>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <fstream>
#include "gr_adreno_info.h"
#include "gr_buf_descriptor.h"
#include "gr_utils.h"
#include "qd_utils.h"
#include "color_extensions.h"
static bool enable_logs = false;
namespace gralloc {
using aidl::android::hardware::graphics::common::BlendMode;
using aidl::android::hardware::graphics::common::Cta861_3;
using aidl::android::hardware::graphics::common::Dataspace;
using aidl::android::hardware::graphics::common::PlaneLayout;
using aidl::android::hardware::graphics::common::Rect;
using aidl::android::hardware::graphics::common::Smpte2086;
using aidl::android::hardware::graphics::common::StandardMetadataType;
using aidl::android::hardware::graphics::common::XyColor;
using ::android::hardware::graphics::common::V1_2::PixelFormat;
using IMapper_4_0_Error = ::android::hardware::graphics::mapper::V4_0::Error;
static BufferInfo GetBufferInfo(const BufferDescriptor &descriptor) {
return BufferInfo(descriptor.GetWidth(), descriptor.GetHeight(), descriptor.GetFormat(),
descriptor.GetUsage());
}
static Error dataspaceToColorMetadata(Dataspace dataspace, ColorMetaData *color_metadata) {
ColorMetaData out;
uint32_t primaries = (uint32_t)dataspace & (uint32_t)Dataspace::STANDARD_MASK;
uint32_t transfer = (uint32_t)dataspace & (uint32_t)Dataspace::TRANSFER_MASK;
uint32_t range = (uint32_t)dataspace & (uint32_t)Dataspace::RANGE_MASK;
switch (primaries) {
case (uint32_t)Dataspace::STANDARD_BT709:
out.colorPrimaries = ColorPrimaries_BT709_5;
break;
// TODO(user): verify this is equivalent
case (uint32_t)Dataspace::STANDARD_BT470M:
out.colorPrimaries = ColorPrimaries_BT470_6M;
break;
case (uint32_t)Dataspace::STANDARD_BT601_625:
case (uint32_t)Dataspace::STANDARD_BT601_625_UNADJUSTED:
out.colorPrimaries = ColorPrimaries_BT601_6_625;
break;
case (uint32_t)Dataspace::STANDARD_BT601_525:
case (uint32_t)Dataspace::STANDARD_BT601_525_UNADJUSTED:
out.colorPrimaries = ColorPrimaries_BT601_6_525;
break;
case (uint32_t)Dataspace::STANDARD_FILM:
out.colorPrimaries = ColorPrimaries_GenericFilm;
break;
case (uint32_t)Dataspace::STANDARD_BT2020:
out.colorPrimaries = ColorPrimaries_BT2020;
break;
case (uint32_t)Dataspace::STANDARD_ADOBE_RGB:
out.colorPrimaries = ColorPrimaries_AdobeRGB;
break;
case (uint32_t)Dataspace::STANDARD_DCI_P3:
out.colorPrimaries = ColorPrimaries_DCIP3;
break;
default:
return Error::UNSUPPORTED;
/*
ColorPrimaries_SMPTE_240M;
ColorPrimaries_SMPTE_ST428;
ColorPrimaries_EBU3213;
*/
}
switch (transfer) {
case (uint32_t)Dataspace::TRANSFER_SRGB:
out.transfer = Transfer_sRGB;
break;
case (uint32_t)Dataspace::TRANSFER_GAMMA2_2:
out.transfer = Transfer_Gamma2_2;
break;
case (uint32_t)Dataspace::TRANSFER_GAMMA2_8:
out.transfer = Transfer_Gamma2_8;
break;
case (uint32_t)Dataspace::TRANSFER_SMPTE_170M:
out.transfer = Transfer_SMPTE_170M;
break;
case (uint32_t)Dataspace::TRANSFER_LINEAR:
out.transfer = Transfer_Linear;
break;
case (uint32_t)Dataspace::TRANSFER_HLG:
out.transfer = Transfer_HLG;
break;
default:
return Error::UNSUPPORTED;
/*
Transfer_SMPTE_240M
Transfer_Log
Transfer_Log_Sqrt
Transfer_XvYCC
Transfer_BT1361
Transfer_sYCC
Transfer_BT2020_2_1
Transfer_BT2020_2_2
Transfer_SMPTE_ST2084
Transfer_ST_428
*/
}
switch (range) {
case (uint32_t)Dataspace::RANGE_FULL:
out.range = Range_Full;
break;
case (uint32_t)Dataspace::RANGE_LIMITED:
out.range = Range_Limited;
break;
case (uint32_t)Dataspace::RANGE_EXTENDED:
out.range = Range_Extended;
break;
default:
return Error::UNSUPPORTED;
}
color_metadata->colorPrimaries = out.colorPrimaries;
color_metadata->transfer = out.transfer;
color_metadata->range = out.range;
return Error::NONE;
}
#ifdef QTI_YUV_PLANE_INFO
static Error getYUVPlaneInfo(const private_handle_t *hnd, struct android_ycbcr ycbcr[2]) {
Error err = Error::NONE;
int ret = 0;
uint32_t width = UINT(hnd->width);
uint32_t height = UINT(hnd->height);
int format = hnd->format;
uint64_t usage = hnd->usage;
int32_t interlaced = 0;
int plane_count = 0;
int unaligned_width = INT(hnd->unaligned_width);
int unaligned_height = INT(hnd->unaligned_height);
BufferInfo info(unaligned_width, unaligned_height, format, usage);
auto metadata = reinterpret_cast<MetaData_t *>(hnd->base_metadata);
memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
// Check metadata if UBWC buffer has been rendered in linear format
if (metadata->isVendorMetadataSet[GET_VENDOR_METADATA_STATUS_INDEX(QTI_LINEAR_FORMAT)])
format = metadata->linearFormat;
// Check metadata if geometry has been updated
if (metadata->isStandardMetadataSet[GET_STANDARD_METADATA_STATUS_INDEX(
(int64_t)StandardMetadataType::CROP)])
BufferInfo info(metadata->crop.right, metadata->crop.bottom, format, usage);
if (GetAlignedWidthAndHeight(info, &width, &height)) {
err = Error::BAD_VALUE;
return err;
}
// Check metadata for interlaced content
if (metadata->isVendorMetadataSet[GET_VENDOR_METADATA_STATUS_INDEX(QTI_PP_PARAM_INTERLACED)])
interlaced = 1 << 0;
PlaneLayoutInfo plane_info[8] = {};
// Get the chroma offsets from the handle width/height. We take advantage
// of the fact the width _is_ the stride
ret = GetYUVPlaneInfo(info, format, width, height, interlaced, &plane_count, plane_info, hnd);
if (ret == 0) {
if (interlaced && format == HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC) {
CopyPlaneLayoutInfotoAndroidYcbcr(hnd->base, plane_count, &plane_info[0], &ycbcr[0]);
unsigned int uv_stride = 0, uv_height = 0, uv_size = 0;
unsigned int alignment = 4096;
uint64_t field_base;
height = (height + 1) >> 1;
uv_stride = MMM_COLOR_FMT_UV_STRIDE(MMM_COLOR_FMT_NV12_UBWC, INT(width));
uv_height = MMM_COLOR_FMT_UV_SCANLINES(MMM_COLOR_FMT_NV12_UBWC, INT(height));
uv_size = ALIGN((uv_stride * uv_height), alignment);
field_base = hnd->base + plane_info[1].offset + uv_size;
memset(ycbcr[1].reserved, 0, sizeof(ycbcr[1].reserved));
CopyPlaneLayoutInfotoAndroidYcbcr(field_base, plane_count, &plane_info[4], &ycbcr[1]);
} else {
CopyPlaneLayoutInfotoAndroidYcbcr(hnd->base, plane_count, plane_info, ycbcr);
switch (format) {
case static_cast<int>(PixelFormat::YCRCB_420_SP):
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS:
case HAL_PIXEL_FORMAT_NV21_ZSL:
std::swap(ycbcr->cb, ycbcr->cr);
}
}
} else {
err = Error::BAD_VALUE;
}
return err;
}
#endif
int BufferManager::GetCustomDimensions(private_handle_t *hnd, int *stride, int *height) {
auto metadata = reinterpret_cast<MetaData_t *>(hnd->base_metadata);
hidl_vec<uint8_t> crop;
int32_t interlaced = 0;
*stride = hnd->width;
*height = hnd->height;
if (metadata->isStandardMetadataSet[GET_STANDARD_METADATA_STATUS_INDEX(
(int64_t)StandardMetadataType::CROP)]) {
*stride = metadata->crop.right;
*height = metadata->crop.bottom;
} else if (metadata
->isVendorMetadataSet[GET_VENDOR_METADATA_STATUS_INDEX(QTI_PP_PARAM_INTERLACED)]) {
interlaced = metadata->interlaced;
if (interlaced && IsUBwcFormat(hnd->format)) {
uint32_t alignedw = 0, alignedh = 0;
BufferInfo info(hnd->width, ((hnd->height + 1) >> 1), hnd->format);
int err = GetAlignedWidthAndHeight(info, &alignedw, &alignedh);
if (err) {
*stride = 0;
*height = 0;
return err;
}
*stride = static_cast<int>(alignedw);
*height = static_cast<int>(alignedh * 2);
}
}
return 0;
}
BufferManager::BufferManager() : next_id_(0) {
handles_map_.clear();
allocator_ = new Allocator();
enable_logs = property_get_bool(ENABLE_LOGS_PROP, 0);
}
BufferManager *BufferManager::GetInstance() {
static BufferManager *instance = new BufferManager();
return instance;
}
BufferManager::~BufferManager() {
if (allocator_) {
delete allocator_;
}
}
void BufferManager::SetGrallocDebugProperties(gralloc::GrallocProperties props) {
allocator_->SetProperties(props);
if (AdrenoMemInfo::GetInstance()) {
AdrenoMemInfo::GetInstance()->AdrenoSetProperties(props);
}
}
Error BufferManager::FreeBuffer(std::shared_ptr<Buffer> buf) {
auto hnd = buf->handle;
ALOGD_IF(enable_logs, "FreeBuffer handle:%p", hnd);
if (private_handle_t::validate(hnd) != 0) {
ALOGE("FreeBuffer: Invalid handle: %p", hnd);
return Error::BAD_BUFFER;
}
auto meta_size = GetMetaDataSize(hnd->reserved_size, buf->custom_content_md_size);
if (allocator_->FreeBuffer(reinterpret_cast<void *>(hnd->base), hnd->size, hnd->offset, hnd->fd,
buf->ion_handle_main) != 0) {
return Error::BAD_BUFFER;
}
if (allocator_->FreeBuffer(reinterpret_cast<void *>(hnd->base_metadata), meta_size,
hnd->offset_metadata, hnd->fd_metadata, buf->ion_handle_meta) != 0) {
return Error::BAD_BUFFER;
}
private_handle_t *handle = const_cast<private_handle_t *>(hnd);
handle->fd = -1;
handle->fd_metadata = -1;
free(handle);
return Error::NONE;
}
Error BufferManager::ValidateBufferSize(private_handle_t const *hnd, BufferInfo info) {
unsigned int size, alignedw, alignedh;
unsigned int max_bpp =
gralloc::GetBppForUncompressedRGB(static_cast<int>(PixelFormat::RGBA_FP16));
info.format = GetImplDefinedFormat(info.usage, info.format);
int ret = GetBufferSizeAndDimensions(info, &size, &alignedw, &alignedh);
if ((ret < 0) || (OVERFLOW((alignedw * max_bpp), alignedh))) {
return Error::BAD_BUFFER;
}
auto ion_fd_size = static_cast<unsigned int>(lseek(hnd->fd, 0, SEEK_END));
if (size != ion_fd_size) {
return Error::BAD_VALUE;
}
return Error::NONE;
}
void BufferManager::RegisterHandleLocked(const private_handle_t *hnd, int ion_handle,
int ion_handle_meta) {
auto buffer = std::make_shared<Buffer>(hnd, ion_handle, ion_handle_meta);
if (hnd->base_metadata) {
#ifdef METADATA_V2
buffer->reserved_size = hnd->reserved_size;
if (buffer->reserved_size > 0) {
buffer->reserved_region_ptr =
reinterpret_cast<void *>(hnd->base_metadata + sizeof(MetaData_t));
} else {
buffer->reserved_region_ptr = nullptr;
}
buffer->custom_content_md_size = hnd->custom_content_md_reserved_size;
if (buffer->custom_content_md_size > 0) {
buffer->custom_content_md_region_ptr =
reinterpret_cast<void *>(hnd->base_metadata + sizeof(MetaData_t) + buffer->reserved_size);
} else {
buffer->custom_content_md_region_ptr = nullptr;
}
#else
buffer->reserved_size = hnd->reserved_size;
buffer->reserved_region_ptr = reinterpret_cast<void *>(hnd->base_metadata + sizeof(MetaData_t));
#endif
}
handles_map_.emplace(std::make_pair(hnd, buffer));
}
Error BufferManager::ImportHandleLocked(private_handle_t *hnd) {
if (private_handle_t::validate(hnd) != 0) {
ALOGE("ImportHandleLocked: Invalid handle: %p", hnd);
return Error::BAD_BUFFER;
}
ALOGD_IF(enable_logs, "Importing handle:%p id: %" PRIu64, hnd, hnd->id);
int ion_handle = allocator_->ImportBuffer(hnd->fd);
if (ion_handle < 0) {
ALOGE("Failed to import ion buffer: hnd: %p, fd:%d, id:%" PRIu64, hnd, hnd->fd, hnd->id);
return Error::BAD_BUFFER;
}
int ion_handle_meta = allocator_->ImportBuffer(hnd->fd_metadata);
if (ion_handle_meta < 0) {
ALOGE("Failed to import ion metadata buffer: hnd: %p, fd:%d, id:%" PRIu64, hnd, hnd->fd,
hnd->id);
return Error::BAD_BUFFER;
}
// Initialize members that aren't transported
hnd->size = static_cast<unsigned int>(lseek(hnd->fd, 0, SEEK_END));
hnd->offset = 0;
hnd->offset_metadata = 0;
hnd->base = 0;
hnd->base_metadata = 0;
hnd->gpuaddr = 0;
if (ValidateAndMap(hnd)) {
ALOGE("Failed to map metadata: hnd: %p, fd:%d, id:%" PRIu64, hnd, hnd->fd, hnd->id);
return Error::BAD_BUFFER;
}
RegisterHandleLocked(hnd, ion_handle, ion_handle_meta);
allocated_ += hnd->size;
if (allocated_ >= kAllocThreshold) {
kAllocThreshold += kMemoryOffset;
BuffersDump();
}
return Error::NONE;
}
std::shared_ptr<BufferManager::Buffer> BufferManager::GetBufferFromHandleLocked(
const private_handle_t *hnd) {
auto it = handles_map_.find(hnd);
if (it != handles_map_.end()) {
return it->second;
} else {
return nullptr;
}
}
Error BufferManager::MapBuffer(private_handle_t const *handle) {
private_handle_t *hnd = const_cast<private_handle_t *>(handle);
ALOGD_IF(enable_logs, "Map buffer handle:%p id: %" PRIu64, hnd, hnd->id);
hnd->base = 0;
if (allocator_->MapBuffer(reinterpret_cast<void **>(&hnd->base), hnd->size, hnd->offset,
hnd->fd) != 0) {
return Error::BAD_BUFFER;
}
return Error::NONE;
}
Error BufferManager::IsBufferImported(const private_handle_t *hnd) {
std::lock_guard<std::mutex> lock(buffer_lock_);
auto buf = GetBufferFromHandleLocked(hnd);
if (buf != nullptr) {
return Error::NONE;
}
return Error::BAD_BUFFER;
}
Error BufferManager::RetainBuffer(private_handle_t const *hnd) {
ALOGD_IF(enable_logs, "Retain buffer handle:%p id: %" PRIu64, hnd, hnd->id);
auto err = Error::NONE;
std::lock_guard<std::mutex> lock(buffer_lock_);
auto buf = GetBufferFromHandleLocked(hnd);
if (buf != nullptr) {
buf->IncRef();
} else {
private_handle_t *handle = const_cast<private_handle_t *>(hnd);
err = ImportHandleLocked(handle);
}
return err;
}
Error BufferManager::ReleaseBuffer(private_handle_t const *hnd) {
ALOGD_IF(enable_logs, "Release buffer handle:%p", hnd);
std::lock_guard<std::mutex> lock(buffer_lock_);
auto buf = GetBufferFromHandleLocked(hnd);
if (buf == nullptr) {
ALOGE("Could not find handle: %p", hnd);
return Error::BAD_BUFFER;
} else {
if (buf->DecRef()) {
handles_map_.erase(hnd);
// Unmap, close ion handle and close fd
if (allocated_ >= hnd->size) {
allocated_ -= hnd->size;
}
FreeBuffer(buf);
}
}
return Error::NONE;
}
Error BufferManager::LockBuffer(const private_handle_t *hnd, uint64_t usage) {
std::lock_guard<std::mutex> lock(buffer_lock_);
auto err = Error::NONE;
ALOGD_IF(enable_logs, "LockBuffer buffer handle:%p id: %" PRIu64, hnd, hnd->id);
// If buffer is not meant for CPU return err
if (!CpuCanAccess(usage)) {
return Error::BAD_VALUE;
}
auto buf = GetBufferFromHandleLocked(hnd);
if (buf == nullptr) {
return Error::BAD_BUFFER;
}
if (hnd->base == 0) {
// we need to map for real
err = MapBuffer(hnd);
}
// Invalidate if CPU reads in software and there are non-CPU
// writers. No need to do this for the metadata buffer as it is
// only read/written in software.
// todo use handle here
if (err == Error::NONE && (hnd->flags & qtigralloc::PRIV_FLAGS_USES_ION) &&
(hnd->flags & qtigralloc::PRIV_FLAGS_CACHED)) {
if (allocator_->CleanBuffer(reinterpret_cast<void *>(hnd->base), hnd->size, hnd->offset,
buf->ion_handle_main, CACHE_INVALIDATE, hnd->fd)) {
return Error::BAD_BUFFER;
}
}
// Mark the buffer to be flushed after CPU write.
if (err == Error::NONE && CpuCanWrite(usage)) {
private_handle_t *handle = const_cast<private_handle_t *>(hnd);
handle->flags |= qtigralloc::PRIV_FLAGS_NEEDS_FLUSH;
}
return err;
}
Error BufferManager::FlushBuffer(const private_handle_t *handle) {
std::lock_guard<std::mutex> lock(buffer_lock_);
auto status = Error::NONE;
private_handle_t *hnd = const_cast<private_handle_t *>(handle);
auto buf = GetBufferFromHandleLocked(hnd);
if (buf == nullptr) {
return Error::BAD_BUFFER;
}
if (allocator_->CleanBuffer(reinterpret_cast<void *>(hnd->base), hnd->size, hnd->offset,
buf->ion_handle_main, CACHE_CLEAN, hnd->fd) != 0) {
status = Error::BAD_BUFFER;
}
return status;
}
Error BufferManager::RereadBuffer(const private_handle_t *handle) {
std::lock_guard<std::mutex> lock(buffer_lock_);
auto status = Error::NONE;
private_handle_t *hnd = const_cast<private_handle_t *>(handle);
auto buf = GetBufferFromHandleLocked(hnd);
if (buf == nullptr) {
return Error::BAD_BUFFER;
}
if (allocator_->CleanBuffer(reinterpret_cast<void *>(hnd->base), hnd->size, hnd->offset,
buf->ion_handle_main, CACHE_INVALIDATE, hnd->fd) != 0) {
status = Error::BAD_BUFFER;
}
return status;
}
Error BufferManager::UnlockBuffer(const private_handle_t *handle) {
std::lock_guard<std::mutex> lock(buffer_lock_);
auto status = Error::NONE;
private_handle_t *hnd = const_cast<private_handle_t *>(handle);
auto buf = GetBufferFromHandleLocked(hnd);
if (buf == nullptr) {
return Error::BAD_BUFFER;
}
if (hnd->flags & qtigralloc::PRIV_FLAGS_NEEDS_FLUSH) {
if (allocator_->CleanBuffer(reinterpret_cast<void *>(hnd->base), hnd->size, hnd->offset,
buf->ion_handle_main, CACHE_CLEAN, hnd->fd) != 0) {
status = Error::BAD_BUFFER;
}
hnd->flags &= ~qtigralloc::PRIV_FLAGS_NEEDS_FLUSH;
} else {
if (allocator_->CleanBuffer(reinterpret_cast<void *>(hnd->base), hnd->size, hnd->offset,
buf->ion_handle_main, CACHE_READ_DONE, hnd->fd) != 0) {
status = Error::BAD_BUFFER;
}
}
return status;
}
// TODO(user): Move this once private_handle_t definition is out of QSSI
static void InitializePrivateHandle(private_handle_t *hnd, int fd, int meta_fd, int flags,
int width, int height, int uw, int uh, int format, int buf_type,
unsigned int size, uint64_t usage = 0) {
hnd->fd = fd;
hnd->fd_metadata = meta_fd;
hnd->magic = private_handle_t::kMagic;
hnd->flags = flags;
hnd->width = width;
hnd->height = height;
hnd->unaligned_width = uw;
hnd->unaligned_height = uh;
hnd->format = format;
hnd->buffer_type = buf_type;
hnd->layer_count = 1;
hnd->id = 0;
hnd->usage = usage;
hnd->size = size;
hnd->offset = 0;
hnd->offset_metadata = 0;
hnd->base = 0;
hnd->base_metadata = 0;
hnd->gpuaddr = 0;
hnd->version = static_cast<int>(sizeof(native_handle));
hnd->numInts = private_handle_t::NumInts();
hnd->numFds = private_handle_t::kNumFds;
}
Error BufferManager::AllocateBuffer(const BufferDescriptor &descriptor, buffer_handle_t *handle,
unsigned int bufferSize, bool testAlloc) {
if (!handle)
return Error::BAD_BUFFER;
std::lock_guard<std::mutex> buffer_lock(buffer_lock_);
uint64_t usage = descriptor.GetUsage();
int format = GetImplDefinedFormat(usage, descriptor.GetFormat());
uint32_t layer_count = descriptor.GetLayerCount();
unsigned int size;
unsigned int alignedw, alignedh;
int err = 0;
int buffer_type = GetBufferType(format);
BufferInfo info = GetBufferInfo(descriptor);
info.format = format;
info.layer_count = layer_count;
GraphicsMetadata graphics_metadata = {};
err = GetBufferSizeAndDimensions(info, &size, &alignedw, &alignedh, &graphics_metadata);
if (err == -ENOTSUP) {
return Error::UNSUPPORTED;
} else if (err < 0) {
return Error::BAD_DESCRIPTOR;
}
if (size == 0) {
ALOGW("gralloc failed to allocate buffer for size %d format %d AWxAH %dx%d usage %" PRIu64,
size, format, alignedw, alignedh, usage);
return Error::UNSUPPORTED;
}
if (testAlloc) {
return Error::NONE;
}
size = (bufferSize >= size) ? bufferSize : size;
uint64_t flags = 0;
auto page_size = UINT(getpagesize());
AllocData data;
data.align = GetDataAlignment(format, usage);
data.size = size;
data.handle = (uintptr_t)handle;
data.uncached = UseUncached(format, usage);
// Allocate buffer memory
err = allocator_->AllocateMem(&data, usage, format);
if (err) {
ALOGE("gralloc failed to allocate err=%s format %d size %d WxH %dx%d usage %" PRIu64,
strerror(-err), format, size, alignedw, alignedh, usage);
return Error::NO_RESOURCES;
}
// Allocate memory for MetaData
AllocData e_data;
uint64_t custom_content_md_reserved_size = GetCustomContentMetadataSize(format, usage);
e_data.size = static_cast<unsigned int>(GetMetaDataSize(descriptor.GetReservedSize(),
custom_content_md_reserved_size));
e_data.handle = data.handle;
e_data.align = page_size;
err = allocator_->AllocateMem(&e_data, 0, 0);
if (err) {
ALOGE("gralloc failed to allocate metadata error=%s", strerror(-err));
return Error::NO_RESOURCES;
}
flags = GetHandleFlags(format, usage);
flags |= data.alloc_type;
// Create handle
// In FreeBuffer(), there's no way to tell if malloc or new was used at allocation time
// On the importBuffer path, native_handle_clone() uses malloc
// To avoid mismatch between malloc/free and new/delete in FreeBuffer(),
// this was changed to malloc
private_handle_t *hnd = static_cast<private_handle_t *>(malloc(sizeof(private_handle_t)));
if (hnd == nullptr) {
ALOGE("gralloc failed to allocate private_handle_t");
return Error::NO_RESOURCES;
}
InitializePrivateHandle(hnd, data.fd, e_data.fd, INT(flags), INT(alignedw), INT(alignedh),
descriptor.GetWidth(), descriptor.GetHeight(), format, buffer_type,
data.size, usage);
hnd->reserved_size = static_cast<unsigned int>(descriptor.GetReservedSize());
hnd->id = ++next_id_;
hnd->base = 0;
hnd->base_metadata = 0;
hnd->layer_count = layer_count;
hnd->custom_content_md_reserved_size = custom_content_md_reserved_size;
bool use_adreno_for_size = CanUseAdrenoForSize(buffer_type, usage);
if (use_adreno_for_size) {
SetMetaData(hnd, QTI_GRAPHICS_METADATA, reinterpret_cast<void *>(&graphics_metadata));
UnmapAndReset(hnd);
}
auto error = ValidateAndMap(hnd);
if (error != 0) {
ALOGE("ValidateAndMap failed");
return Error::BAD_BUFFER;
}
auto metadata = reinterpret_cast<MetaData_t *>(hnd->base_metadata);
auto nameLength = std::min(descriptor.GetName().size(), size_t(MAX_NAME_LEN - 1));
nameLength = descriptor.GetName().copy(metadata->name, nameLength);
metadata->name[nameLength] = '\0';
#ifdef METADATA_V2
metadata->reservedSize = descriptor.GetReservedSize();
#else
metadata->reservedRegion.size =
std::min(descriptor.GetReservedSize(), (uint64_t)RESERVED_REGION_SIZE);
#endif
metadata->crop.top = 0;
metadata->crop.left = 0;
metadata->crop.right = hnd->width;
metadata->crop.bottom = hnd->height;
UnmapAndReset(hnd);
*handle = hnd;
RegisterHandleLocked(hnd, data.ion_handle, e_data.ion_handle);
ALOGD_IF(enable_logs, "Allocated buffer handle: %p id: %" PRIu64, hnd, hnd->id);
if (enable_logs) {
private_handle_t::Dump(hnd);
}
return Error::NONE;
}
void BufferManager::BuffersDump() {
char timeStamp[32];
char hms[32];
uint64_t millis;
struct timeval tv;
struct tm ptm;
gettimeofday(&tv, NULL);
localtime_r(&tv.tv_sec, &ptm);
strftime(hms, sizeof(hms), "%H:%M:%S", &ptm);
millis = tv.tv_usec / 1000;
snprintf(timeStamp, sizeof(timeStamp), "Timestamp: %s.%03" PRIu64, hms, millis);
std::fstream fs;
fs.open(file_dump_.kDumpFile, std::ios::app);
if (!fs) {
return;
}
fs << "============================" << std::endl;
fs << timeStamp << std::endl;
fs << "Total layers = " << handles_map_.size() << std::endl;
uint64_t totalAllocationSize = 0;
for (auto it : handles_map_) {
auto buf = it.second;
auto hnd = buf->handle;
auto metadata = reinterpret_cast<MetaData_t *>(hnd->base_metadata);
fs << std::setw(80) << "Client:" << (metadata ? metadata->name : "No name");
fs << std::setw(20) << "WxH:" << std::setw(4) << hnd->width << " x " << std::setw(4)
<< hnd->height;
fs << std::setw(20) << "Size: " << std::setw(9) << hnd->size << std::endl;
totalAllocationSize += hnd->size;
}
fs << "Total allocation = " << totalAllocationSize / 1024 << "KiB" << std::endl;
file_dump_.position = fs.tellp();
if (file_dump_.position > (20 * 1024 * 1024)) {
file_dump_.position = 0;
}
fs.close();
}
Error BufferManager::Dump(std::ostringstream *os) {
std::lock_guard<std::mutex> buffer_lock(buffer_lock_);
for (auto it : handles_map_) {
auto buf = it.second;
auto hnd = buf->handle;
*os << "handle id: " << std::setw(4) << hnd->id;
*os << " fd: " << std::setw(3) << hnd->fd;
*os << " fd_meta: " << std::setw(3) << hnd->fd_metadata;
*os << " wxh: " << std::setw(4) << hnd->width << " x " << std::setw(4) << hnd->height;
*os << " uwxuh: " << std::setw(4) << hnd->unaligned_width << " x ";
*os << std::setw(4) << hnd->unaligned_height;
*os << " size: " << std::setw(9) << hnd->size;
*os << std::hex << std::setfill('0');
*os << " priv_flags: "
<< "0x" << std::setw(8) << hnd->flags;
*os << " usage: "
<< "0x" << std::setw(8) << hnd->usage;
// TODO(user): get format string from qdutils
*os << " format: "
<< "0x" << std::setw(8) << hnd->format;
*os << std::dec << std::setfill(' ') << std::endl;
}
return Error::NONE;
}
// Get list of private handles in handles_map_
Error BufferManager::GetAllHandles(std::vector<const private_handle_t *> *out_handle_list) {
std::lock_guard<std::mutex> lock(buffer_lock_);
if (handles_map_.empty()) {
return Error::NO_RESOURCES;
}
out_handle_list->reserve(handles_map_.size());
for (auto handle : handles_map_) {
out_handle_list->push_back(handle.first);
}
return Error::NONE;
}
Error BufferManager::GetReservedRegion(private_handle_t *handle, void **reserved_region,
uint64_t *reserved_region_size) {
std::lock_guard<std::mutex> lock(buffer_lock_);
if (!handle)
return Error::BAD_BUFFER;
auto buf = GetBufferFromHandleLocked(handle);
if (buf == nullptr)
return Error::BAD_BUFFER;
if (!handle->base_metadata) {
return Error::BAD_BUFFER;
}
*reserved_region = buf->reserved_region_ptr;
*reserved_region_size = buf->reserved_size;
return Error::NONE;
}
Error BufferManager::GetCustomContentMdRegion(private_handle_t *handle,
void **custom_content_md_region,
uint64_t *custom_content_md_region_size) {
std::lock_guard<std::mutex> lock(buffer_lock_);
if (!handle)
return Error::BAD_BUFFER;
auto buf = GetBufferFromHandleLocked(handle);
if (buf == nullptr)
return Error::BAD_BUFFER;
if (!handle->base_metadata) {
return Error::BAD_BUFFER;
}
*custom_content_md_region = buf->custom_content_md_region_ptr;
*custom_content_md_region_size = buf->custom_content_md_size;
return Error::NONE;
}
Error BufferManager::GetMetadataValue(private_handle_t *handle, int64_t metadatatype_value,
void *param) {
std::lock_guard<std::mutex> lock(buffer_lock_);
if (!handle)
return Error::BAD_BUFFER;
auto buf = GetBufferFromHandleLocked(handle);
if (buf == nullptr)
return Error::BAD_BUFFER;
if (!handle->base_metadata) {
return Error::BAD_BUFFER;
}
if (metadatatype_value == QTI_CUSTOM_CONTENT_METADATA) {
Error error = Error::NONE;
void *custom_content_md_region = buf->custom_content_md_region_ptr;
if (buf->custom_content_md_region_ptr == nullptr ||
buf->custom_content_md_size != sizeof(CustomContentMetadata)) {
error = Error::UNSUPPORTED;
} else {
memcpy(param, custom_content_md_region, sizeof(CustomContentMetadata));
}
return error;
} else {
return GetMetaDataValue(handle, metadatatype_value, param);
}
}
#ifdef QTI_CUSTOM_CONTENT_METADATA
static Error GetCustomMetadataHelper(void *custom_content_md_region_ptr,
uint64_t custom_content_md_size,
hidl_vec<uint8_t> *out) {
Error error = Error::NONE;
if (custom_content_md_region_ptr == nullptr ||
custom_content_md_size != sizeof(CustomContentMetadata)) {
error = Error::UNSUPPORTED;
} else {
if (qtigralloc::encodeCustomContentMetadata(custom_content_md_region_ptr, out) !=
android::hardware::graphics::mapper::V4_0::Error::NONE) {
error = Error::BAD_VALUE;
}
}
return error;
}
#endif
Error BufferManager::GetMetadata(private_handle_t *handle, int64_t metadatatype_value,
hidl_vec<uint8_t> *out) {
std::lock_guard<std::mutex> lock(buffer_lock_);
if (!handle)
return Error::BAD_BUFFER;
auto buf = GetBufferFromHandleLocked(handle);
if (buf == nullptr)
return Error::BAD_BUFFER;
if (!handle->base_metadata) {
return Error::BAD_BUFFER;
}
auto metadata = reinterpret_cast<MetaData_t *>(handle->base_metadata);
void *metadata_ptr = nullptr;
Error error = GetMetaDataByReference(handle, metadatatype_value, &metadata_ptr);
switch (metadatatype_value) {
case (int64_t)StandardMetadataType::BUFFER_ID:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeBufferId(*reinterpret_cast<uint64_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case (int64_t)StandardMetadataType::NAME: {
if (metadata_ptr != nullptr) {
std::string name(reinterpret_cast<char *>(metadata_ptr));
android::gralloc4::encodeName(name, out);
} else {
return Error::BAD_VALUE;
}
break;
}
case (int64_t)StandardMetadataType::WIDTH:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeWidth(
static_cast<uint64_t>(*reinterpret_cast<int32_t *>(metadata_ptr)), out);
} else {
return Error::BAD_VALUE;
}
break;
case (int64_t)StandardMetadataType::HEIGHT:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeHeight(
static_cast<uint64_t>(*reinterpret_cast<int32_t *>(metadata_ptr)), out);
} else {
return Error::BAD_VALUE;
}
break;
case (int64_t)StandardMetadataType::LAYER_COUNT:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeLayerCount(
static_cast<uint64_t>(*reinterpret_cast<uint32_t *>(metadata_ptr)), out);
} else {
return Error::BAD_VALUE;
}
break;
case (int64_t)StandardMetadataType::PIXEL_FORMAT_REQUESTED:
// TODO(user): need to return IMPLEMENTATION_DEFINED,
// which wouldn't be known from private_handle_t
if (metadata_ptr != nullptr) {
android::gralloc4::encodePixelFormatRequested(
static_cast<PixelFormat>(*reinterpret_cast<int32_t *>(metadata_ptr)), out);
} else {
return Error::BAD_VALUE;
}
break;
case (int64_t)StandardMetadataType::PIXEL_FORMAT_FOURCC: {
uint32_t drm_format = 0;
uint64_t drm_format_modifier = 0;
GetDRMFormat(handle->format, handle->flags, &drm_format, &drm_format_modifier);
android::gralloc4::encodePixelFormatFourCC(drm_format, out);
break;
}
case (int64_t)StandardMetadataType::PIXEL_FORMAT_MODIFIER: {
uint32_t drm_format = 0;
uint64_t drm_format_modifier = 0;
GetDRMFormat(handle->format, handle->flags, &drm_format, &drm_format_modifier);
android::gralloc4::encodePixelFormatModifier(drm_format_modifier, out);
break;
}
case (int64_t)StandardMetadataType::USAGE:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeUsage(*reinterpret_cast<uint64_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case (int64_t)StandardMetadataType::ALLOCATION_SIZE:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeAllocationSize(*reinterpret_cast<uint64_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case (int64_t)StandardMetadataType::PROTECTED_CONTENT: {
// update to use metadata ptr when implemented
uint64_t protected_content = (handle->flags & qtigralloc::PRIV_FLAGS_SECURE_BUFFER) ? 1 : 0;
android::gralloc4::encodeProtectedContent(protected_content, out);
break;
}
case (int64_t)StandardMetadataType::CHROMA_SITING:
android::gralloc4::encodeChromaSiting(android::gralloc4::ChromaSiting_None, out);
break;
case (int64_t)StandardMetadataType::DATASPACE:
#ifdef METADATA_V2
if (metadata->isStandardMetadataSet[GET_STANDARD_METADATA_STATUS_INDEX(metadatatype_value)]) {
#endif
Dataspace dataspace;
ColorMetadataToDataspace(metadata->color, &dataspace);
android::gralloc4::encodeDataspace(dataspace, out);
#ifdef METADATA_V2
} else {
android::gralloc4::encodeDataspace(Dataspace::UNKNOWN, out);
}
#endif
break;
case (int64_t)StandardMetadataType::INTERLACED:
if (metadata->interlaced > 0) {
android::gralloc4::encodeInterlaced(qtigralloc::Interlaced_Qti, out);
} else {
android::gralloc4::encodeInterlaced(android::gralloc4::Interlaced_None, out);
}
break;
case (int64_t)StandardMetadataType::COMPRESSION:
if (handle->flags & qtigralloc::PRIV_FLAGS_UBWC_ALIGNED ||
handle->flags & qtigralloc::PRIV_FLAGS_UBWC_ALIGNED_PI) {
android::gralloc4::encodeCompression(qtigralloc::Compression_QtiUBWC, out);
} else {
android::gralloc4::encodeCompression(android::gralloc4::Compression_None, out);
}
break;
case (int64_t)StandardMetadataType::PLANE_LAYOUTS: {
std::vector<PlaneLayout> plane_layouts;
GetPlaneLayout(handle, &plane_layouts);
android::gralloc4::encodePlaneLayouts(plane_layouts, out);
break;
}
case (int64_t)StandardMetadataType::BLEND_MODE:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeBlendMode(*reinterpret_cast<BlendMode *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case (int64_t)StandardMetadataType::SMPTE2086: {
if (metadata->color.masteringDisplayInfo.colorVolumeSEIEnabled) {
Smpte2086 mastering_display_values;
mastering_display_values.primaryRed = {
static_cast<float>(metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[0][0]) /
50000.0f,
static_cast<float>(metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[0][1]) /
50000.0f};
mastering_display_values.primaryGreen = {
static_cast<float>(metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[1][0]) /
50000.0f,
static_cast<float>(metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[1][1]) /
50000.0f};
mastering_display_values.primaryBlue = {
static_cast<float>(metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[2][0]) /
50000.0f,
static_cast<float>(metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[2][1]) /
50000.0f};
mastering_display_values.whitePoint = {
static_cast<float>(metadata->color.masteringDisplayInfo.primaries.whitePoint[0]) /
50000.0f,
static_cast<float>(metadata->color.masteringDisplayInfo.primaries.whitePoint[1]) /
50000.0f};
mastering_display_values.maxLuminance =
static_cast<float>(metadata->color.masteringDisplayInfo.maxDisplayLuminance);
mastering_display_values.minLuminance =
static_cast<float>(metadata->color.masteringDisplayInfo.minDisplayLuminance) / 10000.0f;
android::gralloc4::encodeSmpte2086(mastering_display_values, out);
} else {
android::gralloc4::encodeSmpte2086(std::nullopt, out);
}
break;
}
case (int64_t)StandardMetadataType::CTA861_3: {
if (metadata->color.contentLightLevel.lightLevelSEIEnabled) {
Cta861_3 content_light_level;
content_light_level.maxContentLightLevel =
static_cast<float>(metadata->color.contentLightLevel.maxContentLightLevel);
content_light_level.maxFrameAverageLightLevel =
static_cast<float>(metadata->color.contentLightLevel.minPicAverageLightLevel) /
10000.0f;
android::gralloc4::encodeCta861_3(content_light_level, out);
} else {
android::gralloc4::encodeCta861_3(std::nullopt, out);
}
break;
}
case (int64_t)StandardMetadataType::SMPTE2094_40: {
if (metadata->color.dynamicMetaDataValid &&
metadata->color.dynamicMetaDataLen <= HDR_DYNAMIC_META_DATA_SZ) {
std::vector<uint8_t> dynamic_metadata_payload;
dynamic_metadata_payload.resize(metadata->color.dynamicMetaDataLen);
dynamic_metadata_payload.assign(
metadata->color.dynamicMetaDataPayload,
metadata->color.dynamicMetaDataPayload + metadata->color.dynamicMetaDataLen);
android::gralloc4::encodeSmpte2094_40(dynamic_metadata_payload, out);
} else {
android::gralloc4::encodeSmpte2094_40(std::nullopt, out);
}
break;
}
case (int64_t)StandardMetadataType::CROP: {
// Crop is the same for all planes
std::vector<Rect> out_crop = {
{metadata->crop.left, metadata->crop.top, metadata->crop.right, metadata->crop.bottom}};
android::gralloc4::encodeCrop(out_crop, out);
break;
}
case QTI_VT_TIMESTAMP:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeUint64(qtigralloc::MetadataType_VTTimestamp,
*reinterpret_cast<uint64_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_COLOR_METADATA:
if (metadata_ptr != nullptr) {
qtigralloc::encodeColorMetadata(*reinterpret_cast<ColorMetaData *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_PP_PARAM_INTERLACED:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeInt32(qtigralloc::MetadataType_PPParamInterlaced,
*reinterpret_cast<int32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_VIDEO_PERF_MODE:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeUint32(qtigralloc::MetadataType_VideoPerfMode,
*reinterpret_cast<uint32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_GRAPHICS_METADATA:
if (metadata_ptr != nullptr) {
qtigralloc::encodeGraphicsMetadata(*reinterpret_cast<GraphicsMetadata *>(metadata_ptr),
out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_UBWC_CR_STATS_INFO:
if (metadata_ptr != nullptr) {
qtigralloc::encodeUBWCStats(reinterpret_cast<UBWCStats *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_REFRESH_RATE:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeFloat(qtigralloc::MetadataType_RefreshRate,
*reinterpret_cast<float *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_MAP_SECURE_BUFFER:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeInt32(qtigralloc::MetadataType_MapSecureBuffer,
*reinterpret_cast<int32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_LINEAR_FORMAT:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeUint32(qtigralloc::MetadataType_LinearFormat,
*reinterpret_cast<uint32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_SINGLE_BUFFER_MODE:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeUint32(qtigralloc::MetadataType_SingleBufferMode,
*reinterpret_cast<uint32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_CVP_METADATA:
if (metadata_ptr != nullptr) {
qtigralloc::encodeCVPMetadata(*reinterpret_cast<CVPMetadata *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_VIDEO_HISTOGRAM_STATS:
if (metadata_ptr != nullptr) {
qtigralloc::encodeVideoHistogramMetadata(
*reinterpret_cast<VideoHistogramMetadata *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
#ifdef QTI_VIDEO_TRANSCODE_STATS
case QTI_VIDEO_TRANSCODE_STATS:
if (metadata_ptr != nullptr) {
qtigralloc::encodeVideoTranscodeStatsMetadata(
*reinterpret_cast<VideoTranscodeStatsMetadata *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
#endif
case QTI_FD:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeInt32(qtigralloc::MetadataType_FD,
*reinterpret_cast<int32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_PRIVATE_FLAGS:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeInt32(qtigralloc::MetadataType_PrivateFlags,
*reinterpret_cast<int32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_ALIGNED_WIDTH_IN_PIXELS:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeUint32(qtigralloc::MetadataType_AlignedWidthInPixels,
*reinterpret_cast<uint32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_ALIGNED_HEIGHT_IN_PIXELS:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeUint32(qtigralloc::MetadataType_AlignedHeightInPixels,
*reinterpret_cast<uint32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
#ifdef METADATA_V2
case QTI_STANDARD_METADATA_STATUS:
if (metadata_ptr != nullptr) {
qtigralloc::encodeMetadataState(reinterpret_cast<bool *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
case QTI_VENDOR_METADATA_STATUS:
if (metadata_ptr != nullptr) {
qtigralloc::encodeMetadataState(reinterpret_cast<bool *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
#endif
#ifdef QTI_BUFFER_TYPE
case QTI_BUFFER_TYPE:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeUint32(qtigralloc::MetadataType_BufferType,
*reinterpret_cast<uint32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
#endif
#ifdef QTI_VIDEO_TS_INFO
case QTI_VIDEO_TS_INFO:
if (metadata_ptr != nullptr) {
qtigralloc::encodeVideoTimestampInfo(*reinterpret_cast<VideoTimestampInfo *>(metadata_ptr),
out);
} else {
return Error::BAD_VALUE;
}
break;
#endif
#ifdef QTI_CUSTOM_DIMENSIONS_STRIDE
case QTI_CUSTOM_DIMENSIONS_STRIDE: {
int32_t stride;
int32_t height;
if (GetCustomDimensions(handle, &stride, &height) == 0) {
android::gralloc4::encodeUint32(qtigralloc::MetadataType_CustomDimensionsStride, stride,
out);
break;
} else {
error = Error::BAD_VALUE;
break;
}
}
#endif
#ifdef QTI_CUSTOM_DIMENSIONS_HEIGHT
case QTI_CUSTOM_DIMENSIONS_HEIGHT: {
int32_t stride = handle->width;
int32_t height = handle->height;
if (GetCustomDimensions(handle, &stride, &height) == 0) {
android::gralloc4::encodeUint32(qtigralloc::MetadataType_CustomDimensionsHeight, height,
out);
break;
} else {
error = Error::BAD_VALUE;
break;
}
}
#endif
#ifdef QTI_RGB_DATA_ADDRESS
case QTI_RGB_DATA_ADDRESS: {
void *rgb_data = nullptr;
if (GetRgbDataAddress(handle, &rgb_data) == 0) {
uint64_t addr_ptr = reinterpret_cast<std::uintptr_t>(rgb_data);
android::gralloc4::encodeUint64(qtigralloc::MetadataType_RgbDataAddress, addr_ptr, out);
break;
} else {
error = Error::BAD_BUFFER;
break;
}
}
#endif
#ifdef QTI_COLORSPACE
case QTI_COLORSPACE: {
uint32_t colorspace;
error = GetColorSpaceFromColorMetaData(metadata->color, &colorspace);
if (error == Error::NONE) {
android::gralloc4::encodeUint32(qtigralloc::MetadataType_ColorSpace, colorspace, out);
break;
} else {
error = Error::BAD_BUFFER;
break;
}
}
#endif
#ifdef QTI_YUV_PLANE_INFO
case QTI_YUV_PLANE_INFO: {
qti_ycbcr layout[2];
android_ycbcr yuv_plane_info[2];
error = getYUVPlaneInfo(handle, yuv_plane_info);
if (error == Error::NONE) {
for (int i = 0; i < 2; i++) {
layout[i].y = yuv_plane_info[i].y;
layout[i].cr = yuv_plane_info[i].cr;
layout[i].cb = yuv_plane_info[i].cb;
layout[i].yStride = static_cast<uint32_t>(yuv_plane_info[i].ystride);
layout[i].cStride = static_cast<uint32_t>(yuv_plane_info[i].cstride);
layout[i].chromaStep = static_cast<uint32_t>(yuv_plane_info[i].chroma_step);
}
uint64_t yOffset = (reinterpret_cast<uint64_t>(layout[0].y) - handle->base);
uint64_t crOffset = (reinterpret_cast<uint64_t>(layout[0].cr) - handle->base);
uint64_t cbOffset = (reinterpret_cast<uint64_t>(layout[0].cb) - handle->base);
ALOGD_IF(enable_logs, " layout: y: %" PRIu64 " , cr: %" PRIu64 " , cb: %" PRIu64
" , yStride: %d, cStride: %d, chromaStep: %d ",
yOffset, crOffset, cbOffset, layout[0].yStride, layout[0].cStride,
layout[0].chromaStep);
qtigralloc::encodeYUVPlaneInfoMetadata(layout, out);
break;
} else {
error = Error::BAD_BUFFER;
break;
}
}
#endif
#ifdef QTI_BUFFER_PERMISSION
case QTI_BUFFER_PERMISSION:
if (metadata_ptr != nullptr) {
qtigralloc::encodeBufferPermission(reinterpret_cast<BufferPermission *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
#endif
#ifdef QTI_MEM_HANDLE
case QTI_MEM_HANDLE:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeInt64(qtigralloc::MetadataType_MemHandle,
*reinterpret_cast<int64_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
#endif
#ifdef QTI_TIMED_RENDERING
case QTI_TIMED_RENDERING:
if (metadata_ptr != nullptr) {
android::gralloc4::encodeUint32(qtigralloc::MetadataType_TimedRendering,
*reinterpret_cast<uint32_t *>(metadata_ptr), out);
} else {
return Error::BAD_VALUE;
}
break;
#endif
#ifdef QTI_CUSTOM_CONTENT_METADATA
case QTI_CUSTOM_CONTENT_METADATA:
error = GetCustomMetadataHelper(buf->custom_content_md_region_ptr,
buf->custom_content_md_size, out);
break;
#endif
default:
error = Error::UNSUPPORTED;
}
return error;
}
Error BufferManager::SetMetadata(private_handle_t *handle, int64_t metadatatype_value,
hidl_vec<uint8_t> in) {
std::lock_guard<std::mutex> lock(buffer_lock_);
if (!handle)
return Error::BAD_BUFFER;
auto buf = GetBufferFromHandleLocked(handle);
if (buf == nullptr)
return Error::BAD_BUFFER;
if (!handle->base_metadata) {
return Error::BAD_BUFFER;
}
if (in.size() == 0) {
return Error::UNSUPPORTED;
}
auto metadata = reinterpret_cast<MetaData_t *>(handle->base_metadata);
switch (metadatatype_value) {
// These are constant (unchanged after allocation)
case (int64_t)StandardMetadataType::BUFFER_ID:
case (int64_t)StandardMetadataType::NAME:
case (int64_t)StandardMetadataType::WIDTH:
case (int64_t)StandardMetadataType::HEIGHT:
case (int64_t)StandardMetadataType::LAYER_COUNT:
case (int64_t)StandardMetadataType::PIXEL_FORMAT_REQUESTED:
case (int64_t)StandardMetadataType::USAGE:
return Error::BAD_VALUE;
case (int64_t)StandardMetadataType::PIXEL_FORMAT_FOURCC:
case (int64_t)StandardMetadataType::PIXEL_FORMAT_MODIFIER:
case (int64_t)StandardMetadataType::PROTECTED_CONTENT:
case (int64_t)StandardMetadataType::ALLOCATION_SIZE:
case (int64_t)StandardMetadataType::PLANE_LAYOUTS:
case (int64_t)StandardMetadataType::CHROMA_SITING:
case (int64_t)StandardMetadataType::INTERLACED:
case (int64_t)StandardMetadataType::COMPRESSION:
case QTI_FD:
case QTI_PRIVATE_FLAGS:
case QTI_ALIGNED_WIDTH_IN_PIXELS:
case QTI_ALIGNED_HEIGHT_IN_PIXELS:
#ifdef QTI_CUSTOM_DIMENSIONS_STRIDE
case QTI_CUSTOM_DIMENSIONS_STRIDE:
#endif
#ifdef QTI_CUSTOM_DIMENSIONS_HEIGHT
case QTI_CUSTOM_DIMENSIONS_HEIGHT:
#endif
#ifdef QTI_RGB_DATA_ADDRESS
case QTI_RGB_DATA_ADDRESS:
#endif
#ifdef QTI_COLORSPACE
case QTI_COLORSPACE:
#endif
#ifdef QTI_MEM_HANDLE
case QTI_MEM_HANDLE:
#endif
return Error::UNSUPPORTED;
case (int64_t)StandardMetadataType::DATASPACE:
Dataspace dataspace;
if (android::gralloc4::decodeDataspace(in, &dataspace)) {
return Error::UNSUPPORTED;
}
dataspaceToColorMetadata(dataspace, &metadata->color);
break;
case (int64_t)StandardMetadataType::BLEND_MODE:
BlendMode mode;
android::gralloc4::decodeBlendMode(in, &mode);
metadata->blendMode = (int32_t)mode;
break;
case (int64_t)StandardMetadataType::SMPTE2086: {
std::optional<Smpte2086> mastering_display_values;
if (android::gralloc4::decodeSmpte2086(in, &mastering_display_values)) {
return Error::UNSUPPORTED;
}
if (mastering_display_values != std::nullopt) {
metadata->color.masteringDisplayInfo.colorVolumeSEIEnabled = true;
metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[0][0] =
static_cast<uint32_t>(mastering_display_values->primaryRed.x * 50000.0f);
metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[0][1] =
static_cast<uint32_t>(mastering_display_values->primaryRed.y * 50000.0f);
metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[1][0] =
static_cast<uint32_t>(mastering_display_values->primaryGreen.x * 50000.0f);
metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[1][1] =
static_cast<uint32_t>(mastering_display_values->primaryGreen.y * 50000.0f);
metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[2][0] =
static_cast<uint32_t>(mastering_display_values->primaryBlue.x * 50000.0f);
metadata->color.masteringDisplayInfo.primaries.rgbPrimaries[2][1] =
static_cast<uint32_t>(mastering_display_values->primaryBlue.y * 50000.0f);
metadata->color.masteringDisplayInfo.primaries.whitePoint[0] =
static_cast<uint32_t>(mastering_display_values->whitePoint.x * 50000.0f);
metadata->color.masteringDisplayInfo.primaries.whitePoint[1] =
static_cast<uint32_t>(mastering_display_values->whitePoint.y * 50000.0f);
metadata->color.masteringDisplayInfo.maxDisplayLuminance =
static_cast<uint32_t>(mastering_display_values->maxLuminance);
metadata->color.masteringDisplayInfo.minDisplayLuminance =
static_cast<uint32_t>(mastering_display_values->minLuminance * 10000.0f);
} else {
#ifdef METADATA_V2
metadata->isStandardMetadataSet[GET_STANDARD_METADATA_STATUS_INDEX(metadatatype_value)] =
false;
#endif
metadata->color.masteringDisplayInfo.colorVolumeSEIEnabled = false;
}
break;
}
case (int64_t)StandardMetadataType::CTA861_3: {
std::optional<Cta861_3> content_light_level;
if (android::gralloc4::decodeCta861_3(in, &content_light_level)) {
return Error::UNSUPPORTED;
}
if (content_light_level != std::nullopt) {
metadata->color.contentLightLevel.lightLevelSEIEnabled = true;
metadata->color.contentLightLevel.maxContentLightLevel =
static_cast<uint32_t>(content_light_level->maxContentLightLevel);
metadata->color.contentLightLevel.minPicAverageLightLevel =
static_cast<uint32_t>(content_light_level->maxFrameAverageLightLevel * 10000.0f);
} else {
#ifdef METADATA_V2
metadata->isStandardMetadataSet[GET_STANDARD_METADATA_STATUS_INDEX(metadatatype_value)] =
false;
#endif
metadata->color.contentLightLevel.lightLevelSEIEnabled = false;
}
break;
}
case (int64_t)StandardMetadataType::SMPTE2094_40: {
std::optional<std::vector<uint8_t>> dynamic_metadata_payload;
if (android::gralloc4::decodeSmpte2094_40(in, &dynamic_metadata_payload)) {
return Error::UNSUPPORTED;
}
if (dynamic_metadata_payload != std::nullopt) {
if (dynamic_metadata_payload->size() > HDR_DYNAMIC_META_DATA_SZ)
return Error::BAD_VALUE;
metadata->color.dynamicMetaDataLen = dynamic_metadata_payload->size();
std::copy(dynamic_metadata_payload->begin(), dynamic_metadata_payload->end(),
metadata->color.dynamicMetaDataPayload);
metadata->color.dynamicMetaDataValid = true;
} else {
// Reset metadata by passing in std::nullopt
#ifdef METADATA_V2
metadata->isStandardMetadataSet[GET_STANDARD_METADATA_STATUS_INDEX(metadatatype_value)] =
false;
#endif
metadata->color.dynamicMetaDataValid = false;
}
break;
}
case (int64_t)StandardMetadataType::CROP: {
std::vector<Rect> in_crop;
if (android::gralloc4::decodeCrop(in, &in_crop)) {
return Error::UNSUPPORTED;
}
if (in_crop.size() != 1) {
return Error::UNSUPPORTED;
}
metadata->crop.left = in_crop[0].left;
metadata->crop.top = in_crop[0].top;
metadata->crop.right = in_crop[0].right;
metadata->crop.bottom = in_crop[0].bottom;
break;
}
case QTI_VT_TIMESTAMP:
if (android::gralloc4::decodeUint64(qtigralloc::MetadataType_VTTimestamp, in,
&metadata->vtTimeStamp)) {
return Error::UNSUPPORTED;
}
break;
case QTI_COLOR_METADATA:
ColorMetaData color;
if (qtigralloc::decodeColorMetadata(in, &color) != IMapper_4_0_Error::NONE) {
return Error::UNSUPPORTED;
}
metadata->color = color;
break;
case QTI_PP_PARAM_INTERLACED:
if (android::gralloc4::decodeInt32(qtigralloc::MetadataType_PPParamInterlaced, in,
&metadata->interlaced)) {
return Error::UNSUPPORTED;
}
break;
case QTI_VIDEO_PERF_MODE:
if (android::gralloc4::decodeUint32(qtigralloc::MetadataType_VideoPerfMode, in,
&metadata->isVideoPerfMode)) {
return Error::UNSUPPORTED;
}
break;
case QTI_GRAPHICS_METADATA:
if (qtigralloc::decodeGraphicsMetadata(in, &metadata->graphics_metadata) !=
IMapper_4_0_Error::NONE) {
return Error::UNSUPPORTED;
}
break;
case QTI_UBWC_CR_STATS_INFO:
if (qtigralloc::decodeUBWCStats(in, &metadata->ubwcCRStats[0]) != IMapper_4_0_Error::NONE) {
return Error::UNSUPPORTED;
}
break;
case QTI_REFRESH_RATE:
if (android::gralloc4::decodeFloat(qtigralloc::MetadataType_RefreshRate, in,
&metadata->refreshrate)) {
return Error::UNSUPPORTED;
}
break;
case QTI_MAP_SECURE_BUFFER:
if (android::gralloc4::decodeInt32(qtigralloc::MetadataType_MapSecureBuffer, in,
&metadata->mapSecureBuffer)) {
return Error::UNSUPPORTED;
}
break;
case QTI_LINEAR_FORMAT:
if (android::gralloc4::decodeUint32(qtigralloc::MetadataType_LinearFormat, in,
&metadata->linearFormat)) {
return Error::UNSUPPORTED;
}
break;
case QTI_SINGLE_BUFFER_MODE:
if (android::gralloc4::decodeUint32(qtigralloc::MetadataType_SingleBufferMode, in,
&metadata->isSingleBufferMode)) {
return Error::UNSUPPORTED;
}
break;
case QTI_CVP_METADATA:
if (qtigralloc::decodeCVPMetadata(in, &metadata->cvpMetadata) != IMapper_4_0_Error::NONE) {
return Error::UNSUPPORTED;
}
break;
case QTI_VIDEO_HISTOGRAM_STATS:
if (qtigralloc::decodeVideoHistogramMetadata(in, &metadata->video_histogram_stats) !=
IMapper_4_0_Error::NONE) {
return Error::UNSUPPORTED;
}
break;
#ifdef QTI_VIDEO_TRANSCODE_STATS
case QTI_VIDEO_TRANSCODE_STATS:
qtigralloc::decodeVideoTranscodeStatsMetadata(in, &metadata->video_transcode_stats);
break;
#endif
#ifdef QTI_VIDEO_TS_INFO
case QTI_VIDEO_TS_INFO:
if (qtigralloc::decodeVideoTimestampInfo(in, &metadata->videoTsInfo) !=
IMapper_4_0_Error::NONE) {
return Error::UNSUPPORTED;
}
break;
#endif
#ifdef QTI_BUFFER_PERMISSION
case QTI_BUFFER_PERMISSION: {
qtigralloc::decodeBufferPermission(in, &metadata->bufferPerm[0]);
allocator_->SetBufferPermission(handle->fd, &metadata->bufferPerm[0], &metadata->memHandle);
}
break;
#endif
#ifdef QTI_TIMED_RENDERING
case QTI_TIMED_RENDERING:
android::gralloc4::decodeUint32(qtigralloc::MetadataType_TimedRendering, in,
&metadata->timedRendering);
break;
#endif
#ifdef QTI_CUSTOM_CONTENT_METADATA
case QTI_CUSTOM_CONTENT_METADATA:
if (buf->custom_content_md_region_ptr == nullptr ||
buf->custom_content_md_size != sizeof(CustomContentMetadata)) {
return Error::UNSUPPORTED;
} else {
if (qtigralloc::decodeCustomContentMetadata(in, buf->custom_content_md_region_ptr) !=
android::hardware::graphics::mapper::V4_0::Error::NONE) {
return Error::BAD_VALUE;
}
}
break;
#endif
default:
return Error::BAD_VALUE;
}
#ifdef METADATA_V2
if (IS_VENDOR_METADATA_TYPE(metadatatype_value)) {
if (GET_VENDOR_METADATA_STATUS_INDEX(metadatatype_value) < METADATA_SET_SIZE) {
metadata->isVendorMetadataSet[GET_VENDOR_METADATA_STATUS_INDEX(metadatatype_value)] = true;
}
} else {
if (GET_STANDARD_METADATA_STATUS_INDEX(metadatatype_value) < METADATA_SET_SIZE) {
metadata->isStandardMetadataSet[GET_STANDARD_METADATA_STATUS_INDEX(metadatatype_value)] =
true;
}
}
#endif
return Error::NONE;
}
} // namespace gralloc