blob: 08da01681fa95447e2786eb3554f19365a934aa9 [file] [log] [blame]
/*
* Copyright 2020 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 "cros_gralloc/gralloc3/CrosGralloc3Mapper.h"
#include <cutils/native_handle.h>
#include "cros_gralloc/cros_gralloc_helpers.h"
#include "cros_gralloc/gralloc3/CrosGralloc3Utils.h"
#include "helpers.h"
using android::hardware::hidl_handle;
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::hardware::Void;
using android::hardware::graphics::common::V1_2::BufferUsage;
using android::hardware::graphics::common::V1_2::PixelFormat;
using android::hardware::graphics::mapper::V3_0::Error;
using android::hardware::graphics::mapper::V3_0::IMapper;
using android::hardware::graphics::mapper::V3_0::YCbCrLayout;
CrosGralloc3Mapper::CrosGralloc3Mapper() : mDriver(std::make_unique<cros_gralloc_driver>()) {
if (mDriver->init()) {
drv_log("Failed to initialize driver.\n");
mDriver = nullptr;
}
}
Return<void> CrosGralloc3Mapper::createDescriptor(const BufferDescriptorInfo& description,
createDescriptor_cb hidlCb) {
hidl_vec<uint32_t> descriptor;
if (description.width == 0) {
drv_log("Failed to createDescriptor. Bad width: %d.\n", description.width);
hidlCb(Error::BAD_VALUE, descriptor);
return Void();
}
if (description.height == 0) {
drv_log("Failed to createDescriptor. Bad height: %d.\n", description.height);
hidlCb(Error::BAD_VALUE, descriptor);
return Void();
}
if (description.layerCount == 0) {
drv_log("Failed to createDescriptor. Bad layer count: %d.\n", description.layerCount);
hidlCb(Error::BAD_VALUE, descriptor);
return Void();
}
auto descriptor_opt = encodeBufferDescriptorInfo(description);
if (!descriptor_opt) {
drv_log("Failed to createDescriptor. Failed to encodeBufferDescriptorInfo\n");
hidlCb(Error::BAD_VALUE, descriptor);
return Void();
}
descriptor = *descriptor_opt;
hidlCb(Error::NONE, descriptor);
return Void();
}
Return<void> CrosGralloc3Mapper::importBuffer(const hidl_handle& handle, importBuffer_cb hidlCb) {
if (!mDriver) {
drv_log("Failed to import buffer. Driver is uninitialized.\n");
hidlCb(Error::NO_RESOURCES, nullptr);
return Void();
}
const native_handle_t* bufferHandle = handle.getNativeHandle();
if (!bufferHandle || bufferHandle->numFds == 0) {
drv_log("Failed to importBuffer. Bad handle.\n");
hidlCb(Error::BAD_BUFFER, nullptr);
return Void();
}
native_handle_t* importedBufferHandle = native_handle_clone(bufferHandle);
if (!importedBufferHandle) {
drv_log("Failed to importBuffer. Handle clone failed.\n");
hidlCb(Error::NO_RESOURCES, nullptr);
return Void();
}
int ret = mDriver->retain(importedBufferHandle);
if (ret) {
native_handle_close(importedBufferHandle);
native_handle_delete(importedBufferHandle);
hidlCb(Error::NO_RESOURCES, nullptr);
return Void();
}
hidlCb(Error::NONE, importedBufferHandle);
return Void();
}
Return<Error> CrosGralloc3Mapper::freeBuffer(void* rawHandle) {
if (!mDriver) {
drv_log("Failed to freeBuffer. Driver is uninitialized.\n");
return Error::NO_RESOURCES;
}
native_handle_t* bufferHandle = reinterpret_cast<native_handle_t*>(rawHandle);
if (!bufferHandle) {
drv_log("Failed to freeBuffer. Empty handle.\n");
return Error::BAD_BUFFER;
}
int ret = mDriver->release(bufferHandle);
if (ret) {
drv_log("Failed to freeBuffer.\n");
return Error::BAD_BUFFER;
}
native_handle_close(bufferHandle);
native_handle_delete(bufferHandle);
return Error::NONE;
}
Return<Error> CrosGralloc3Mapper::validateBufferSize(void* rawHandle,
const BufferDescriptorInfo& descriptor,
uint32_t stride) {
if (!mDriver) {
drv_log("Failed to validateBufferSize. Driver is uninitialized.\n");
return Error::NO_RESOURCES;
}
native_handle_t* bufferHandle = reinterpret_cast<native_handle_t*>(rawHandle);
if (!bufferHandle) {
drv_log("Failed to validateBufferSize. Empty handle.\n");
return Error::BAD_BUFFER;
}
cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
if (!crosHandle) {
drv_log("Failed to validateBufferSize. Invalid handle.\n");
return Error::BAD_BUFFER;
}
PixelFormat crosHandleFormat = static_cast<PixelFormat>(crosHandle->droid_format);
if (descriptor.format != crosHandleFormat) {
drv_log("Failed to validateBufferSize. Format mismatch.\n");
return Error::BAD_BUFFER;
}
if (descriptor.width != crosHandle->width) {
drv_log("Failed to validateBufferSize. Width mismatch (%d vs %d).\n", descriptor.width,
crosHandle->width);
return Error::BAD_VALUE;
}
if (descriptor.height != crosHandle->height) {
drv_log("Failed to validateBufferSize. Height mismatch (%d vs %d).\n", descriptor.height,
crosHandle->height);
return Error::BAD_VALUE;
}
if (stride != crosHandle->pixel_stride) {
drv_log("Failed to validateBufferSize. Stride mismatch (%d vs %d).\n", stride,
crosHandle->pixel_stride);
return Error::BAD_VALUE;
}
return Error::NONE;
}
Return<void> CrosGralloc3Mapper::getTransportSize(void* rawHandle, getTransportSize_cb hidlCb) {
if (!mDriver) {
drv_log("Failed to getTransportSize. Driver is uninitialized.\n");
hidlCb(Error::BAD_BUFFER, 0, 0);
return Void();
}
native_handle_t* bufferHandle = reinterpret_cast<native_handle_t*>(rawHandle);
if (!bufferHandle) {
drv_log("Failed to getTransportSize. Bad handle.\n");
hidlCb(Error::BAD_BUFFER, 0, 0);
return Void();
}
// No local process data is currently stored on the native handle.
hidlCb(Error::NONE, bufferHandle->numFds, bufferHandle->numInts);
return Void();
}
Return<void> CrosGralloc3Mapper::lock(void* rawHandle, uint64_t cpuUsage, const Rect& accessRegion,
const hidl_handle& acquireFence, lock_cb hidlCb) {
if (!mDriver) {
drv_log("Failed to lock. Driver is uninitialized.\n");
hidlCb(Error::NO_RESOURCES, nullptr, 0, 0);
return Void();
}
buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
if (!bufferHandle) {
drv_log("Failed to lock. Empty handle.\n");
hidlCb(Error::BAD_BUFFER, nullptr, 0, 0);
return Void();
}
cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
if (crosHandle == nullptr) {
drv_log("Failed to lock. Invalid handle.\n");
hidlCb(Error::BAD_BUFFER, nullptr, 0, 0);
return Void();
}
LockResult result = lockInternal(crosHandle, cpuUsage, accessRegion, acquireFence);
if (result.error != Error::NONE) {
drv_log("Failed to lock. Failed to lockInternal.\n");
hidlCb(result.error, nullptr, 0, 0);
return Void();
}
int32_t bytesPerPixel = drv_bytes_per_pixel_from_format(crosHandle->format, 0);
int32_t bytesPerStride = static_cast<int32_t>(crosHandle->strides[0]);
hidlCb(Error::NONE, result.mapped[0], bytesPerPixel, bytesPerStride);
return Void();
}
Return<void> CrosGralloc3Mapper::lockYCbCr(void* rawHandle, uint64_t cpuUsage,
const Rect& accessRegion,
const android::hardware::hidl_handle& acquireFence,
lockYCbCr_cb hidlCb) {
YCbCrLayout ycbcr = {};
if (!mDriver) {
drv_log("Failed to lock. Driver is uninitialized.\n");
hidlCb(Error::NO_RESOURCES, ycbcr);
return Void();
}
buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
if (!bufferHandle) {
drv_log("Failed to lockYCbCr. Empty handle.\n");
hidlCb(Error::BAD_BUFFER, ycbcr);
return Void();
}
cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
if (crosHandle == nullptr) {
drv_log("Failed to lockYCbCr. Invalid handle.\n");
hidlCb(Error::BAD_BUFFER, ycbcr);
return Void();
}
LockResult result = lockInternal(crosHandle, cpuUsage, accessRegion, acquireFence);
if (result.error != Error::NONE) {
drv_log("Failed to lockYCbCr. Failed to lockInternal.\n");
hidlCb(result.error, ycbcr);
return Void();
}
switch (crosHandle->format) {
case DRM_FORMAT_NV12: {
ycbcr.y = result.mapped[0] + crosHandle->offsets[0];
ycbcr.cb = result.mapped[0] + crosHandle->offsets[1];
ycbcr.cr = result.mapped[0] + crosHandle->offsets[1] + 1;
ycbcr.yStride = crosHandle->strides[0];
ycbcr.cStride = crosHandle->strides[1];
ycbcr.chromaStep = 2;
break;
}
case DRM_FORMAT_NV21: {
ycbcr.y = result.mapped[0] + crosHandle->offsets[0];
ycbcr.cb = result.mapped[0] + crosHandle->offsets[1] + 1;
ycbcr.cr = result.mapped[0] + crosHandle->offsets[1];
ycbcr.yStride = crosHandle->strides[0];
ycbcr.cStride = crosHandle->strides[1];
ycbcr.chromaStep = 2;
break;
}
case DRM_FORMAT_YVU420: {
ycbcr.y = result.mapped[0] + crosHandle->offsets[0];
ycbcr.cb = result.mapped[0] + crosHandle->offsets[1];
ycbcr.cr = result.mapped[0] + crosHandle->offsets[2];
ycbcr.yStride = crosHandle->strides[0];
ycbcr.cStride = crosHandle->strides[1];
ycbcr.chromaStep = 1;
break;
}
case DRM_FORMAT_YVU420_ANDROID: {
ycbcr.y = result.mapped[0] + crosHandle->offsets[0];
ycbcr.cb = result.mapped[0] + crosHandle->offsets[2];
ycbcr.cr = result.mapped[0] + crosHandle->offsets[1];
ycbcr.yStride = crosHandle->strides[0];
ycbcr.cStride = crosHandle->strides[1];
ycbcr.chromaStep = 1;
break;
}
default: {
std::string format = get_drm_format_string(crosHandle->format);
drv_log("Failed to lockYCbCr. Unhandled format: %s\n", format.c_str());
hidlCb(Error::BAD_BUFFER, ycbcr);
return Void();
}
}
hidlCb(Error::NONE, ycbcr);
return Void();
}
CrosGralloc3Mapper::LockResult CrosGralloc3Mapper::lockInternal(
cros_gralloc_handle_t crosHandle, uint64_t cpuUsage, const Rect& region,
const android::hardware::hidl_handle& acquireFence) {
LockResult result = {};
if (!mDriver) {
drv_log("Failed to lock. Driver is uninitialized.\n");
result.error = Error::NO_RESOURCES;
return result;
}
if (cpuUsage == 0) {
drv_log("Failed to lock. Bad cpu usage: %" PRIu64 ".\n", cpuUsage);
result.error = Error::BAD_VALUE;
return result;
}
uint32_t mapUsage = 0;
int ret = convertToMapUsage(cpuUsage, &mapUsage);
if (ret) {
drv_log("Failed to lock. Convert usage failed.\n");
result.error = Error::BAD_VALUE;
return result;
}
if (region.left < 0) {
drv_log("Failed to lock. Invalid region: negative left value %d.\n", region.left);
result.error = Error::BAD_VALUE;
return result;
}
if (region.top < 0) {
drv_log("Failed to lock. Invalid region: negative top value %d.\n", region.top);
result.error = Error::BAD_VALUE;
return result;
}
if (region.width < 0) {
drv_log("Failed to lock. Invalid region: negative width value %d.\n", region.width);
result.error = Error::BAD_VALUE;
return result;
}
if (region.height < 0) {
drv_log("Failed to lock. Invalid region: negative height value %d.\n", region.height);
result.error = Error::BAD_VALUE;
return result;
}
if (region.width > crosHandle->width) {
drv_log("Failed to lock. Invalid region: width greater than buffer width (%d vs %d).\n",
region.width, crosHandle->width);
result.error = Error::BAD_VALUE;
return result;
}
if (region.height > crosHandle->height) {
drv_log("Failed to lock. Invalid region: height greater than buffer height (%d vs %d).\n",
region.height, crosHandle->height);
result.error = Error::BAD_VALUE;
return result;
}
struct rectangle rect = {static_cast<uint32_t>(region.left), static_cast<uint32_t>(region.top),
static_cast<uint32_t>(region.width),
static_cast<uint32_t>(region.height)};
// An access region of all zeros means the entire buffer.
if (rect.x == 0 && rect.y == 0 && rect.width == 0 && rect.height == 0) {
rect.width = crosHandle->width;
rect.height = crosHandle->height;
}
int acquireFenceFd = -1;
ret = convertToFenceFd(acquireFence, &acquireFenceFd);
if (ret) {
drv_log("Failed to lock. Bad acquire fence.\n");
result.error = Error::BAD_VALUE;
return result;
}
buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(crosHandle);
ret = mDriver->lock(bufferHandle, acquireFenceFd, false, &rect, mapUsage, result.mapped);
if (ret) {
result.error = Error::BAD_VALUE;
return result;
}
result.error = Error::NONE;
return result;
}
Return<void> CrosGralloc3Mapper::unlock(void* rawHandle, unlock_cb hidlCb) {
if (!mDriver) {
drv_log("Failed to unlock. Driver is uninitialized.\n");
hidlCb(Error::BAD_BUFFER, nullptr);
return Void();
}
buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
if (!bufferHandle) {
drv_log("Failed to unlock. Empty handle.\n");
hidlCb(Error::BAD_BUFFER, nullptr);
return Void();
}
int releaseFenceFd = -1;
int ret = mDriver->unlock(bufferHandle, &releaseFenceFd);
if (ret) {
drv_log("Failed to unlock.\n");
hidlCb(Error::BAD_BUFFER, nullptr);
return Void();
}
hidl_handle releaseFenceHandle;
ret = convertToFenceHandle(releaseFenceFd, &releaseFenceHandle);
if (ret) {
drv_log("Failed to unlock. Failed to convert release fence to handle.\n");
hidlCb(Error::BAD_BUFFER, nullptr);
return Void();
}
hidlCb(Error::NONE, releaseFenceHandle);
return Void();
}
Return<void> CrosGralloc3Mapper::isSupported(const BufferDescriptorInfo& descriptor,
isSupported_cb hidlCb) {
if (!mDriver) {
drv_log("Failed to isSupported. Driver is uninitialized.\n");
hidlCb(Error::BAD_VALUE, false);
return Void();
}
struct cros_gralloc_buffer_descriptor crosDescriptor;
if (convertToCrosDescriptor(descriptor, &crosDescriptor)) {
hidlCb(Error::NONE, false);
return Void();
}
bool supported = mDriver->is_supported(&crosDescriptor);
if (!supported) {
crosDescriptor.use_flags &= ~BO_USE_SCANOUT;
supported = mDriver->is_supported(&crosDescriptor);
}
hidlCb(Error::NONE, supported);
return Void();
}
int CrosGralloc3Mapper::getResolvedDrmFormat(PixelFormat pixelFormat, uint64_t bufferUsage,
uint32_t* outDrmFormat) {
uint32_t drmFormat;
if (convertToDrmFormat(pixelFormat, &drmFormat)) {
std::string pixelFormatString = getPixelFormatString(pixelFormat);
drv_log("Failed to getResolvedDrmFormat. Failed to convert format %s\n",
pixelFormatString.c_str());
return -EINVAL;
}
uint64_t usage;
if (convertToBufferUsage(bufferUsage, &usage)) {
std::string usageString = getUsageString(bufferUsage);
drv_log("Failed to getResolvedDrmFormat. Failed to convert usage %s\n",
usageString.c_str());
return -EINVAL;
}
uint32_t resolvedDrmFormat = mDriver->get_resolved_drm_format(drmFormat, usage);
if (resolvedDrmFormat == DRM_FORMAT_INVALID) {
std::string drmFormatString = get_drm_format_string(drmFormat);
drv_log("Failed to getResolvedDrmFormat. Failed to resolve drm format %s\n",
drmFormatString.c_str());
return -EINVAL;
}
*outDrmFormat = resolvedDrmFormat;
return 0;
}
android::hardware::graphics::mapper::V3_0::IMapper* HIDL_FETCH_IMapper(const char* /*name*/) {
return static_cast<android::hardware::graphics::mapper::V3_0::IMapper*>(new CrosGralloc3Mapper);
}