1
0
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

749 lines
23 KiB

/*
* Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd
*
* 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 "VirCamGraBuf"
//#define LOG_NDEBUG 0
#include <log/log.h>
#include <utils/threads.h>
#include <utils/Log.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
#include <ui/GraphicBuffer.h>
#include <linux/videodev2.h>
#include "VirtualCameraGralloc4.h"
#include <hwbinder/IPCThreadState.h>
#include <sync/sync.h>
#include <drm_fourcc.h>
#include <hidl/ServiceManagement.h>
#include <inttypes.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wzero-length-array"
#include <sync/sync.h>
#pragma clang diagnostic pop
using namespace android;
namespace virtuals {
#define RK_GRALLOC_USAGE_SPECIFY_STRIDE 1ULL << 30
struct dma_buf_sync {
__u64 flags;
};
#define DMA_BUF_SYNC_READ (1 << 0)
#define DMA_BUF_SYNC_WRITE (2 << 0)
#define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE)
#define DMA_BUF_SYNC_START (0 << 2)
#define DMA_BUF_SYNC_END (1 << 2)
#define DMA_BUF_SYNC_VALID_FLAGS_MASK \
(DMA_BUF_SYNC_RW | DMA_BUF_SYNC_END)
#define DMA_BUF_BASE 'b'
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
using android::hardware::graphics::mapper::V4_0::Error;
using android::hardware::graphics::mapper::V4_0::IMapper;
using android::hardware::graphics::allocator::V4_0::IAllocator;
using android::hardware::graphics::common::V1_2::BufferUsage;
using android::hardware::graphics::mapper::V4_0::BufferDescriptor;
using android::hardware::hidl_vec;
using android::gralloc4::MetadataType_PlaneLayouts;
using android::gralloc4::decodePlaneLayouts;
using android::gralloc4::MetadataType_Usage;
using android::gralloc4::decodeUsage;
using android::gralloc4::MetadataType_PlaneLayouts;
using android::gralloc4::decodePlaneLayouts;
using android::gralloc4::MetadataType_PixelFormatFourCC;
using android::gralloc4::decodePixelFormatFourCC;
using android::gralloc4::MetadataType_PixelFormatModifier;
using android::gralloc4::decodePixelFormatModifier;
using android::gralloc4::MetadataType_PixelFormatRequested;
using android::gralloc4::decodePixelFormatRequested;
using android::gralloc4::MetadataType_AllocationSize;
using android::gralloc4::decodeAllocationSize;
using android::gralloc4::MetadataType_LayerCount;
using android::gralloc4::decodeLayerCount;
using android::gralloc4::MetadataType_Dataspace;
using android::gralloc4::decodeDataspace;
using android::gralloc4::MetadataType_Crop;
using android::gralloc4::decodeCrop;
using android::gralloc4::MetadataType_Width;
using android::gralloc4::decodeWidth;
using android::gralloc4::MetadataType_Height;
using android::gralloc4::decodeHeight;
using ::android::Mutex;
using aidl::android::hardware::graphics::common::Dataspace;
using aidl::android::hardware::graphics::common::PlaneLayout;
using aidl::android::hardware::graphics::common::ExtendableType;
using aidl::android::hardware::graphics::common::PlaneLayout;
using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
namespace VirCamGralloc4 {
#define IMPORTBUFFER_CB 1
static constexpr Error kTransactionError = Error::NO_RESOURCES;
uint64_t getValidUsageBits() {
static const uint64_t validUsageBits = []() -> uint64_t {
uint64_t bits = 0;
for (const auto bit :
hardware::hidl_enum_range<hardware::graphics::common::V1_2::BufferUsage>()) {
bits = bits | bit;
}
return bits;
}();
return validUsageBits;
}
static inline IMapper::Rect sGralloc4Rect(const Rect& rect) {
IMapper::Rect outRect{};
outRect.left = rect.left;
outRect.top = rect.top;
outRect.width = rect.width();
outRect.height = rect.height();
return outRect;
}
static inline void sBufferDescriptorInfo(std::string name, uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount, uint64_t usage,
IMapper::BufferDescriptorInfo* outDescriptorInfo) {
outDescriptorInfo->name = name;
outDescriptorInfo->width = width;
outDescriptorInfo->height = height;
outDescriptorInfo->layerCount = layerCount;
outDescriptorInfo->format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
outDescriptorInfo->usage = usage;
outDescriptorInfo->reservedSize = 0;
}
/*#defined in hardware/rockchip/libgralloc/bifrost/src/hidl_common/MapperMetadata.h*/
#define GRALLOC_ARM_METADATA_TYPE_NAME "arm.graphics.ArmMetadataType"
const static IMapper::MetadataType ArmMetadataType_PLANE_FDS
{
GRALLOC_ARM_METADATA_TYPE_NAME,
// static_cast<int64_t>(aidl::arm::graphics::ArmMetadataType::PLANE_FDS)
1 // 'PLANE_FDS'
};
static IMapper &get_mapperservice()
{
static android::sp<IMapper> cached_service = IMapper::getService();
return *cached_service;
}
static IAllocator &get_allocservice()
{
static android::sp<IAllocator> cached_service = IAllocator::getService();
return *cached_service;
}
template <typename T>
static int get_metadata(IMapper &mapper, buffer_handle_t handle, IMapper::MetadataType type,
android::status_t (*decode)(const hidl_vec<uint8_t> &, T *), T *value)
{
void *handle_arg = const_cast<native_handle_t *>(handle);
assert(handle_arg);
assert(value);
assert(decode);
int err = 0;
mapper.get(handle_arg, type, [&err, value, decode](Error error, const hidl_vec<uint8_t> &metadata)
{
if (error != Error::NONE)
{
err = android::BAD_VALUE;
return;
}
err = decode(metadata, value);
});
return err;
}
android::status_t static decodeArmPlaneFds(const hidl_vec<uint8_t>& input, std::vector<int64_t>* fds)
{
assert (fds != nullptr);
int64_t size = 0;
memcpy(&size, input.data(), sizeof(int64_t));
if (size < 0)
{
return android::BAD_VALUE;
}
fds->resize(size);
const uint8_t *tmp = input.data() + sizeof(int64_t);
memcpy(fds->data(), tmp, sizeof(int64_t) * size);
return android::NO_ERROR;
}
int get_width(buffer_handle_t handle, uint64_t* width)
{
auto &mapper = get_mapperservice();
int err = get_metadata(mapper, handle, MetadataType_Width, decodeWidth, width);
if (err != android::OK)
{
LOGE("err : %d", err);
}
return err;
}
int get_height(buffer_handle_t handle, uint64_t* height)
{
auto &mapper = get_mapperservice();
int err = get_metadata(mapper, handle, MetadataType_Height, decodeHeight, height);
if (err != android::OK)
{
LOGE("err : %d", err);
}
return err;
}
status_t validateBufferDescriptorInfo(
IMapper::BufferDescriptorInfo* descriptorInfo) {
uint64_t validUsageBits = getValidUsageBits();
if (descriptorInfo->usage & ~validUsageBits) {
ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
descriptorInfo->usage & ~validUsageBits);
return android::BAD_VALUE;
}
return android::NO_ERROR;
}
status_t createDescriptor(void* bufferDescriptorInfo,
void* outBufferDescriptor) {
IMapper::BufferDescriptorInfo* descriptorInfo =
static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
status_t status = validateBufferDescriptorInfo(descriptorInfo);
if (status != android::NO_ERROR) {
return status;
}
Error error;
auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) {
error = tmpError;
if (error != Error::NONE) {
return;
}
*outDescriptor = tmpDescriptor;
};
auto &mapper = get_mapperservice();
android::hardware::Return<void> ret = mapper.createDescriptor(*descriptorInfo, hidl_cb);
return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
int vir_lock(buffer_handle_t bufferHandle,
uint32_t flags,
uint32_t left,
uint32_t top,
uint32_t width,
uint32_t height,
void** out_addr) {
auto &mapper = get_mapperservice();
auto buffer = const_cast<native_handle_t*>(bufferHandle);
IMapper::Rect accessRegion = {(int)left, (int)top, (int)width, (int)height};
android::hardware::hidl_handle acquireFenceHandle; // dummy
Error error;
auto ret = mapper.lock(buffer,
flags,
accessRegion,
acquireFenceHandle,
[&](const auto& tmpError, const auto& tmpData) {
error = tmpError;
if (error != Error::NONE) {
return;
}
*out_addr = tmpData;
});
error = (ret.isOk()) ? error : kTransactionError;
ALOGE_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
return (int)error;
}
int vir_unlock(buffer_handle_t bufferHandle) {
auto &mapper = get_mapperservice();
auto buffer = const_cast<native_handle_t*>(bufferHandle);
int releaseFence = -1;
Error error;
auto ret = mapper.unlock(buffer,
[&](const auto& tmpError, const auto& tmpReleaseFence)
{
error = tmpError;
if (error != Error::NONE) {
return;
}
auto fenceHandle = tmpReleaseFence.getNativeHandle(); // 预期 unlock() 不会返回有效的 release_fence.
if (fenceHandle && fenceHandle->numFds == 1)
{
ALOGE("got unexpected valid fd of release_fence : %d", fenceHandle->data[0]);
int fd = dup(fenceHandle->data[0]);
if (fd >= 0) {
releaseFence = fd;
} else {
ALOGE("failed to dup unlock release fence");
sync_wait(fenceHandle->data[0], -1);
}
}
});
if (!ret.isOk()) {
error = kTransactionError;
}
if (error != Error::NONE) {
ALOGE("unlock(%p) failed with %d", bufferHandle, error);
}
return 0;
}
int get_usage(buffer_handle_t handle, uint64_t* usage)
{
auto &mapper = get_mapperservice();
int err = get_metadata(mapper, handle, MetadataType_Usage, decodeUsage, usage);
if (err != android::OK)
{
LOGE("Failed to get pixel_format_requested. err : %d", err);
return err;
}
return err;
}
int get_allocation_size(buffer_handle_t handle, uint64_t* allocation_size)
{
auto &mapper = get_mapperservice();
int err = get_metadata(mapper, handle, MetadataType_AllocationSize, decodeAllocationSize, allocation_size);
if (err != android::OK)
{
LOGE("Failed to get allocation_size. err : %d", err);
return err;
}
return err;
}
status_t vir_importBuffer(buffer_handle_t rawHandle,
buffer_handle_t* outBufferHandle) {
ALOGV("import aa rawBuffer :%p", rawHandle);
Error error;
auto &mapper = get_mapperservice();
auto ret = mapper.importBuffer(android::hardware::hidl_handle(rawHandle), [&](const auto& tmpError, const auto& tmpBuffer) {
error = tmpError;
if (error != Error::NONE) {
return;
}
*outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
ALOGV("import bb outBuffer :%p", outBufferHandle);
});
return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
status_t freeBuffer(buffer_handle_t bufferHandle) {
ALOGV("freeBuffer %p", bufferHandle);
auto buffer = const_cast<native_handle_t*>(bufferHandle);
auto &mapper = get_mapperservice();
auto ret = mapper.freeBuffer(buffer);
auto error = (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
ALOGE_IF(error != Error::NONE, "freeBuffer(%p) failed with %d", buffer, error);
return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
int get_share_fd(buffer_handle_t buffer, int* share_fd) {
ALOGV(" buffer:%p", buffer);
int fd = -1;
int err = 0;
Mutex mLock;
Mutex::Autolock _l(mLock);
{
auto &mapper = get_mapperservice();
std::vector<int64_t> fds;
err = get_metadata(mapper, buffer, ArmMetadataType_PLANE_FDS, decodeArmPlaneFds, &fds);
if (err != android::OK)
{
ALOGE("Failed to get plane_fds. err : %d", err);
return err;
}
assert (fds.size() > 0);
*share_fd = (int)(fds[0]);
}
return err;
}
} // namespace VirCamGralloc4
static int allocate_gralloc_buffer(size_t width,
size_t height,
uint32_t format,
uint32_t usage,
buffer_handle_t* out_buffer,
uint32_t* out_stride) {
ALOGV("AllocateGrallocBuffer %d, %d, %d, %d", width, height, format, usage);
Mutex mLock;
Mutex::Autolock _l(mLock);
IMapper::BufferDescriptorInfo descriptorInfo;
VirCamGralloc4::sBufferDescriptorInfo("ExternalAllocateBuffer", width, height, (PixelFormat)format, 1/*layerCount*/, usage, &descriptorInfo);
BufferDescriptor descriptor;
status_t error = VirCamGralloc4::createDescriptor(static_cast<void*>(&descriptorInfo),
static_cast<void*>(&descriptor));
if (error != android::NO_ERROR) {
return error;
}
int bufferCount = 1;
auto &allocator = VirCamGralloc4::get_allocservice();
auto ret = allocator.allocate(descriptor, bufferCount,
[&](const auto& tmpError, const auto& tmpStride,
const auto& tmpBuffers) {
error = static_cast<status_t>(tmpError);
if (tmpError != Error::NONE) {
return;
}
#if IMPORTBUFFER_CB == 1
for (uint32_t i = 0; i < bufferCount; i++) {
error = VirCamGralloc4::vir_importBuffer(tmpBuffers[i],
out_buffer);
if (error != android::NO_ERROR) {
for (uint32_t j = 0; j < i; j++) {
VirCamGralloc4::freeBuffer(*out_buffer);
*out_buffer = nullptr;
}
return;
}
}
#else
for (uint32_t i = 0; i < bufferCount; i++) {
*out_buffer = native_handle_clone(
tmpBuffers[i].getNativeHandle());
if (!out_buffer) {
for (uint32_t j = 0; j < i; j++) {
//auto buffer = const_cast<native_handle_t*>(
// out_buffer);
native_handle_close(out_buffer);
native_handle_delete(out_buffer);
*out_buffer = nullptr;
}
}
}
#endif
*out_stride = tmpStride;
});
if (!ret.isOk())
return -EINVAL;
ALOGV("AllocateGrallocBuffer %p", *out_buffer);
#if 0
buffer_context->usage = 1;
buffer_context_[*out_buffer] = std::move(buffer_context);
#endif
// make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
android::hardware::IPCThreadState::self()->flushCommands();
return (ret.isOk()) ? error : static_cast<status_t>(VirCamGralloc4::kTransactionError);
}
static cam_mem_handle_t* cam_mem_gralloc_ops_init_vir(
int iommu_enabled, unsigned int mem_flag, int phy_continuos)
{
int ret = 0;
cam_mem_handle_t* handle = NULL;
handle = (cam_mem_handle_t*)malloc(sizeof(cam_mem_handle_t));
if (!handle) {
LOGE("%s:can't alloc handle!",__FUNCTION__);
goto init_error;
}
memset(handle, 0x0, sizeof(*handle));
handle->mem_type = CAM_MEM_TYPE_GRALLOC;
handle->iommu_enabled = iommu_enabled;
handle->phy_continuos = phy_continuos;
if (mem_flag & CAM_MEM_FLAG_HW_WRITE)
handle->flag |= GRALLOC_USAGE_HW_CAMERA_WRITE;
if (mem_flag & CAM_MEM_FLAG_HW_READ)
handle->flag |= GRALLOC_USAGE_HW_CAMERA_READ;
if (mem_flag & CAM_MEM_FLAG_SW_WRITE)
handle->flag |= GRALLOC_USAGE_SW_WRITE_OFTEN;
if (mem_flag & CAM_MEM_FLAG_SW_READ)
handle->flag |= GRALLOC_USAGE_SW_READ_OFTEN;
handle->flag |= RK_GRALLOC_USAGE_SPECIFY_STRIDE;
return handle;
init_error:
if (!handle)
free(handle);
return NULL;
}
//alloc GraphicBuffer
static cam_mem_info_t* cam_mem_gralloc_ops_alloc_vir(
cam_mem_handle_t* handle, size_t size,
uint32_t width, uint32_t height)
{
int ret;
unsigned int grallocFlags = 0;
unsigned int halPixFmt;
void* mem_addr = NULL;
cam_mem_info_t* mem = NULL;
buffer_handle_t buf_handle;
uint32_t stride = 0;
int fd = -1;
uint64_t allocation_size;
if (!handle) {
LOGE("invalid ion mem handle!");
return NULL;
}
mem = (cam_mem_info_t*)malloc(sizeof(cam_mem_info_t));
if (!mem) {
LOGE("can't alloc cam_mem_info_t!");
goto error_alloc;
}
//halPixFmt = HAL_PIXEL_FORMAT_RGB_565;
halPixFmt = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
grallocFlags = handle->flag;
ret = allocate_gralloc_buffer(width,height, halPixFmt, grallocFlags, &buf_handle, &stride);
if (ret) {
LOGE("alloc buffer error : %s", strerror(errno));
goto error_alloc;
}
ret = VirCamGralloc4::vir_lock(
buf_handle,
grallocFlags,
0,
0,
width,
height,
(void**)&mem_addr);
if (ret) {
LOGE("lock buffer error : %s", strerror(errno));
goto lock_error;
}
VirCamGralloc4::vir_unlock(buf_handle);
ret = VirCamGralloc4::get_allocation_size(buf_handle, &allocation_size);
ALOGV("alloc buffer size(%lld)", allocation_size);
ret = VirCamGralloc4::get_share_fd(buf_handle, &fd);
if (ret) {
LOGE("get share fd error : %s", strerror(errno));
goto lock_error;
}
mem->vir_addr = (unsigned long)mem_addr;
mem->handlle = handle;
mem->iommu_maped = 0;
mem->mmu_addr = 0;
mem->phy_addr = 0;
mem->size = size;
mem->priv = (void*)buf_handle;
mem->fd = fd;
mem->width = width;
mem->height = height;
ALOGV("alloc graphic buffer sucess,mem %p, vir_addr %p, fd %d",
mem, mem_addr, mem->fd);
return mem;
lock_error:
VirCamGralloc4::freeBuffer(buf_handle);
error_alloc:
if (mem)
free(mem);
return NULL;
}
//free
static int cam_mem_gralloc_ops_free_vir(
cam_mem_handle_t* handle, cam_mem_info_t* mem)
{
int ret = 0;
buffer_handle_t buf_handle;
if (!handle || !mem) {
LOGE("invalid ion mem handle!");
return -1;
}
if (mem->iommu_maped) {
LOGE("ion mem is mmumaped, should be unmapped firstly!");
return -1;
}
buf_handle = (buffer_handle_t)(mem->priv);
#if IMPORTBUFFER_CB == 1
if (buf_handle) {
VirCamGralloc4::freeBuffer(buf_handle);
buf_handle = nullptr;
}
#else
if (buf_handle) {
auto abuffer = const_cast<native_handle_t*>(
buf_handle);
native_handle_close(abuffer);
native_handle_delete(abuffer);
buf_handle = nullptr;
}
#endif
free(mem);
return ret;
}
//flush cache
static int cam_mem_gralloc_ops_flush_cache_vir(
cam_mem_handle_t* handle, cam_mem_info_t* mem,
uint32_t width, uint32_t height)
{
struct dma_buf_sync sync_args;
int ret = 0;
void* mem_addr;
buffer_handle_t* buf_handle = (buffer_handle_t*)(mem->priv);
if (!handle || !mem) {
LOGE("invalid ion mem handle!");
return -1;
}
ret = VirCamGralloc4::vir_lock(
*buf_handle,
handle->flag,
0,
0,
width,
height,
(void**)&mem_addr);
if (ret) {
LOGE("lock buffer error : %s", strerror(errno));
return -1;
}
sync_args.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW;
ret = ioctl(mem->fd, DMA_BUF_IOCTL_SYNC, &sync_args);
if (ret != 0)
LOGE("ret %d ,DMA_BUF_IOCTL_SYNC failed!", ret);
VirCamGralloc4::vir_unlock(*buf_handle);
return ret;
}
//deinit
static int cam_mem_gralloc_ops_deInit_vir(cam_mem_handle_t* handle)
{
int ret = 0;
if (!handle) {
LOGE("invalid ion mem handle!");
return -1;
}
free(handle);
return ret;
}
cam_mem_ops_t g_rk_gralloc_mem_ops {
//init
.init = cam_mem_gralloc_ops_init_vir,
//alloc
.alloc = cam_mem_gralloc_ops_alloc_vir,
//free
.free = cam_mem_gralloc_ops_free_vir,
//flush cache
.flush_cache = cam_mem_gralloc_ops_flush_cache_vir,
//deinit
.deInit = cam_mem_gralloc_ops_deInit_vir,
};
static struct cam_mem_ops_des_s cam_mem_ops_array[] = {
{"ion",CAM_MEM_TYPE_ION,NULL},
{"ionDma",CAM_MEM_TYPE_IONDMA,NULL},
{"gralloc",CAM_MEM_TYPE_GRALLOC,&g_rk_gralloc_mem_ops},
};
cam_mem_ops_t* get_cam_ops_vir(enum cam_mem_type_e mem_type)
{
int ops_index = -1;
switch(mem_type) {
case CAM_MEM_TYPE_ION:
ops_index = 0;
break;
case CAM_MEM_TYPE_IONDMA:
ops_index = 1;
break;
case CAM_MEM_TYPE_GRALLOC:
ops_index = 2;
break;
default:
ops_index = -1;
break;
}
if (ops_index != -1)
return cam_mem_ops_array[ops_index].ops;
else
return NULL;
}
}//namespace virtuals