blob: 93e62bf6c76fe2c31e9fc000949165ae10b98b8b [file] [log] [blame]
/*
* Copyright (C) 2020 Samsung 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 "ExynosGraphicBuffer"
#include "ExynosGraphicBufferCore.h"
#include "ExynosGraphicBufferUtils.h"
#include "metadata_gpu.h"
#include "metadata_gralloc.h"
#include "private_handle.h"
#include <errno.h>
#include <exynos_format.h>
#include <inttypes.h>
#include <log/log.h>
#include <string.h>
#include <sys/mman.h>
using namespace vendor::graphics;
#define UNUSED(x) ((void)x)
#define SZ_4k 0x1000
#define SGR_LOGD(...)
#define SGR_LOGE(...) ALOGE(__VA_ARGS__)
constexpr int SGR_META_OFFSET[3] = {SGR_METADATA_OFFSET_VIDEO, SGR_METADATA_OFFSET_GRALLOC, SGR_METADATA_OFFSET_GPU};
enum METADATA_TYPE {
TYPE_VIDEO = 0,
TYPE_GRALLOC,
TYPE_GPU,
};
static void *map_and_get_metadata(buffer_handle_t hnd, METADATA_TYPE type, bool write) {
if (hnd == nullptr) {
SGR_LOGD("[%s] buffer handle is null", __func__);
return nullptr;
}
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
const uint32_t metadata_fd_index = phnd->numFds - 1;
int prot = write ? PROT_READ | PROT_WRITE : PROT_READ;
void *metadata = mmap(0, SGR_METADATA_SIZE_SUB_TOTAL, prot, MAP_SHARED, phnd->fds[metadata_fd_index], 0);
if (metadata == MAP_FAILED) {
SGR_LOGE("[%s] mmap failed: %s", __func__, strerror(errno));
return nullptr;
}
return reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(metadata) + SGR_META_OFFSET[type]);
}
static void unmap_metadata(void *metadata, METADATA_TYPE type) {
void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(metadata) - SGR_META_OFFSET[type]);
munmap(addr, SGR_METADATA_SIZE_SUB_TOTAL);
}
int ExynosGraphicBufferMeta::get_video_metadata_fd(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return -1;
}
int ret = -1;
if (phnd->usage & ExynosGraphicBufferUsage::VIDEO_PRIVATE_DATA) {
const uint32_t metadata_fd_index = phnd->numFds - 1;
SGR_LOGD("[%s] usage has video_private_data, numFds %d, fdindex %u", __func__, phnd->numFds, metadata_fd_index);
ret = phnd->fds[metadata_fd_index];
} else {
SGR_LOGD("[%s] usage has NO video_private_data", __func__);
}
return ret;
}
int ExynosGraphicBufferMeta::get_dataspace(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
int ret = HAL_DATASPACE_UNKNOWN;
struct sgr_metadata *metadata = (struct sgr_metadata *)map_and_get_metadata(hnd, TYPE_GRALLOC, false);
if (metadata == nullptr) {
SGR_LOGE("[%s] metadata is null", __func__);
return ret;
}
ret = metadata->dataspace;
unmap_metadata((void *)metadata, TYPE_GRALLOC);
return ret;
}
int ExynosGraphicBufferMeta::set_dataspace(buffer_handle_t hnd, android_dataspace_t dataspace) {
SGR_LOGD("[%s] entry", __func__);
struct sgr_metadata *metadata = (struct sgr_metadata *)map_and_get_metadata(hnd, TYPE_GRALLOC, true);
if (metadata == nullptr) {
SGR_LOGE("[%s] metadata is null", __func__);
return -1;
}
int temp = metadata->dataspace;
metadata->dataspace = dataspace;
unmap_metadata((void *)metadata, TYPE_GRALLOC);
SGR_LOGD("[%s] dataspace changed %d to %d", __func__, temp, dataspace);
UNUSED(temp);
return 0;
}
bool ExynosGraphicBufferMeta::is_sajc(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return false;
}
return (phnd->alloc_layout == SGR_ALLOC_LAYOUT_DCC);
}
int ExynosGraphicBufferMeta::is_afbc(buffer_handle_t) {
return 0;
}
uint64_t ExynosGraphicBufferMeta::get_buffer_id(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
struct sgr_metadata *metadata = sgr_get_metadata(hnd);
if (metadata == nullptr) {
SGR_LOGD("metadata is null(not imported), so mmap gralloc metadata");
metadata = (struct sgr_metadata *)map_and_get_metadata(hnd, TYPE_GRALLOC, false);
if (metadata == nullptr) {
SGR_LOGE("[%s] metadata is null, return id as 0", __func__);
return 0;
}
uint64_t ret = metadata->buffer_id;
unmap_metadata((void *)metadata, TYPE_GRALLOC);
return ret;
}
return metadata->buffer_id;
}
#define GRALLOC_META_GETTER(__type__, __name__, __member__) \
__type__ ExynosGraphicBufferMeta::get_##__name__(buffer_handle_t hnd) { \
SGR_LOGD("[%s] entry", __func__); \
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd); \
if (phnd == nullptr) { \
SGR_LOGD("[%s] private_handle is null", __func__); \
return -EINVAL; \
} \
return phnd->__member__; \
}
GRALLOC_META_GETTER(int, num_image_fds, num_allocs);
GRALLOC_META_GETTER(uint32_t, format, alloc_format);
GRALLOC_META_GETTER(uint64_t, internal_format, alloc_format);
GRALLOC_META_GETTER(uint64_t, frameworkFormat, format);
GRALLOC_META_GETTER(int, width, width);
GRALLOC_META_GETTER(int, height, height);
GRALLOC_META_GETTER(uint32_t, vstride, plane_infos[0].height_in_samples);
GRALLOC_META_GETTER(uint64_t, producer_usage, usage);
GRALLOC_META_GETTER(uint64_t, consumer_usage, usage);
GRALLOC_META_GETTER(uint64_t, usage, usage);
uint32_t ExynosGraphicBufferMeta::get_stride(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return 0;
}
uint32_t stride;
switch (phnd->alloc_format) {
case HAL_PIXEL_FORMAT_RAW10:
case HAL_PIXEL_FORMAT_RAW12:
stride = phnd->plane_infos[0].stride_in_bytes;
break;
default:
stride = phnd->plane_infos[0].width_in_samples;
break;
}
return stride;
}
uint32_t ExynosGraphicBufferMeta::get_cstride(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return 0;
}
uint32_t stride = phnd->plane_infos[1].width_in_samples;
if (is_semi_planar(phnd->alloc_format)) {
stride = phnd->plane_infos[0].width_in_samples;
}
return stride;
}
int ExynosGraphicBufferMeta::get_fd(buffer_handle_t hnd, int num) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return -1;
}
return phnd->fds[num];
}
int ExynosGraphicBufferMeta::get_size(buffer_handle_t hnd, int num) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return 0;
}
return phnd->alloc_infos[num].size;
}
void *ExynosGraphicBufferMeta::get_video_metadata(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
void *metadata = sgr_get_metadata_video(const_cast<native_handle_t *>(hnd));
SGR_LOGD("[%s] metadata %p", __func__, metadata);
if (metadata == nullptr) {
SGR_LOGD("[%s] metadata is null", __func__);
return nullptr;
}
return metadata;
}
void *ExynosGraphicBufferMeta::get_video_metadata_roiinfo(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return nullptr;
}
void *video_metadata = sgr_get_metadata_video(hnd);
// TODO
if (phnd->usage & ExynosGraphicBufferUsage::ROIINFO) {
SGR_LOGE("[%s] ROIINFO this shouldn't be called", __func__);
return reinterpret_cast<char *>(video_metadata) + SZ_4k * 2;
}
return nullptr;
}
int64_t ExynosGraphicBufferMeta::get_plane_offset(buffer_handle_t hnd, int plane_num) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return -EINVAL;
}
uint32_t buffer_num_planes = phnd->num_planes;
if (plane_num > buffer_num_planes) {
SGR_LOGD("[%s] buffer have %" PRIu32 " planes, but input is %d", __func__, buffer_num_planes, plane_num);
return -EINVAL;
}
return phnd->plane_infos[plane_num].offset;
}
int ExynosGraphicBufferMeta::get_pad_align(buffer_handle_t hnd, pad_align_t *pad_align) {
SGR_LOGD("[%s] entry", __func__);
UNUSED(pad_align);
const private_handle_t *gralloc_hnd = static_cast<const private_handle_t *>(hnd);
if (!gralloc_hnd)
return -EINVAL;
return 0;
}
int64_t ExynosGraphicBufferMeta::get_sub_plane_offset(buffer_handle_t hnd, int plane_num) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return -EINVAL;
}
if (~phnd->usage & ExynosGraphicBufferUsage::DOWNSCALE) {
SGR_LOGD("[%s] buffer has no usage for DOWNSCALE", __func__);
return -EINVAL;
}
uint32_t sub_num_plane = phnd->num_planes / 2;
if (plane_num > sub_num_plane) {
SGR_LOGE("[%s] sub have %" PRIu32 " planes, but input is %d", __func__, sub_num_plane, plane_num);
return -EINVAL;
}
return phnd->plane_infos[sub_num_plane + plane_num].offset;
}
int32_t ExynosGraphicBufferMeta::get_sajc_independent_block_size(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return -EINVAL;
}
int32_t ret = -1;
if (phnd->alloc_layout != SGR_ALLOC_LAYOUT_DCC) {
SGR_LOGE("[%s] buffer is not SAJC buffer", __func__);
} else {
uint32_t sajc_independent_64;
uint32_t sajc_independent_128;
struct sgr_metadata_gpu *gpu_meta = (struct sgr_metadata_gpu *)sgr_get_metadata_gpu(hnd);
if (gpu_meta == nullptr) {
SGR_LOGD("metadata is null(not imported), so mmap gpu metadata");
gpu_meta = (struct sgr_metadata_gpu *)map_and_get_metadata(hnd, TYPE_GPU, false);
if (gpu_meta == nullptr) {
SGR_LOGE("[%s] metadata is null", __func__);
return ret;
}
sajc_independent_64 = gpu_meta->dcc_independent_block_size_64;
sajc_independent_128 = gpu_meta->dcc_independent_block_size_128;
ret = (sajc_independent_128 << 1) | (sajc_independent_64);
unmap_metadata((void *)gpu_meta, TYPE_GPU);
return ret;
}
sajc_independent_64 = gpu_meta->dcc_independent_block_size_64;
sajc_independent_128 = gpu_meta->dcc_independent_block_size_128;
ret = (sajc_independent_128 << 1) | (sajc_independent_64);
}
return ret;
}
int32_t ExynosGraphicBufferMeta::get_sajc_key_offset(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return -EINVAL;
}
int32_t ret = -1;
if (phnd->alloc_layout != SGR_ALLOC_LAYOUT_DCC) {
SGR_LOGE("[%s] buffer is not SAJC buffer", __func__);
} else {
ret = static_cast<int32_t>(phnd->alloc_infos[0].key_offset);
}
return ret;
}
int32_t ExynosGraphicBufferMeta::get_sub_stride(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return -EINVAL;
}
if (~phnd->usage & ExynosGraphicBufferUsage::DOWNSCALE) {
SGR_LOGD("[%s] buffer has no usage for DOWNSCALE", __func__);
return -EINVAL;
}
uint32_t sub_idx = phnd->num_allocs / 2;
return static_cast<int32_t>(phnd->plane_infos[sub_idx].width_in_samples);
}
int32_t ExynosGraphicBufferMeta::get_sub_vstride(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return -EINVAL;
}
if (~phnd->usage & ExynosGraphicBufferUsage::DOWNSCALE) {
SGR_LOGD("[%s] buffer has no usage for DOWNSCALE", __func__);
return -EINVAL;
}
uint32_t sub_idx = phnd->num_allocs / 2;
return static_cast<int32_t>(phnd->plane_infos[sub_idx].height_in_samples);
}
int32_t ExynosGraphicBufferMeta::get_sub_format(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return -EINVAL;
}
if (~phnd->usage & ExynosGraphicBufferUsage::DOWNSCALE) {
SGR_LOGD("[%s] buffer has no usage for DOWNSCALE", __func__);
return -EINVAL;
}
uint32_t alloc_format = phnd->alloc_format;
struct sub_format_list {
uint32_t base_format;
uint32_t sbwc_format;
};
static const sub_format_list format_table[] = {
{HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC},
{HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC},
};
int32_t sub_format = 0;
for (uint32_t i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++) {
if (alloc_format == format_table[i].base_format) {
sub_format = static_cast<int32_t>(format_table[i].sbwc_format);
break;
}
}
return sub_format;
}
bool ExynosGraphicBufferMeta::get_sub_valid(buffer_handle_t hnd) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return false;
}
if (~phnd->usage & ExynosGraphicBufferUsage::DOWNSCALE) {
SGR_LOGD("[%s] buffer has no usage for DOWNSCALE", __func__);
return false;
}
struct sgr_metadata *metadata = (struct sgr_metadata *)map_and_get_metadata(hnd, TYPE_GRALLOC, false);
if (metadata == nullptr) {
SGR_LOGE("[%s] metadata is null", __func__);
return false;
}
bool ret = metadata->sub_valid;
unmap_metadata((void *)metadata, TYPE_GRALLOC);
return ret;
}
int ExynosGraphicBufferMeta::set_sub_valid(buffer_handle_t hnd, bool valid) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(hnd);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return -EINVAL;
}
if (~phnd->usage & ExynosGraphicBufferUsage::DOWNSCALE) {
SGR_LOGD("[%s] buffer has no usage for DOWNSCALE", __func__);
return -EINVAL;
}
struct sgr_metadata *metadata = (struct sgr_metadata *)map_and_get_metadata(hnd, TYPE_GRALLOC, true);
if (metadata == nullptr) {
SGR_LOGE("[%s] metadata is null", __func__);
return -EINVAL;
}
metadata->sub_valid = valid;
unmap_metadata((void *)metadata, TYPE_GRALLOC);
return 0;
}
void ExynosGraphicBufferMeta::init(const buffer_handle_t handle) {
SGR_LOGD("[%s] entry", __func__);
const private_handle_t *phnd = static_cast<const private_handle_t *>(handle);
if (phnd == nullptr) {
SGR_LOGD("[%s] private_handle is null", __func__);
return;
}
fd = phnd->fds[0];
fd1 = phnd->fds[1];
fd2 = phnd->fds[2];
SGR_LOGD("[%s] fds (%d, %d, %d)", __func__, fd, fd1, fd2);
size = phnd->alloc_infos[0].size;
size1 = phnd->alloc_infos[1].size;
size2 = phnd->alloc_infos[2].size;
SGR_LOGD("[%s] size (%d, %d, %d)", __func__, size, size1, size2);
uint64_t usage = phnd->usage;
if (usage & ExynosGraphicBufferUsage::VIDEO_PRIVATE_DATA) {
SGR_LOGD("[%s] VIDEO_PRIVATE_DATA", __func__);
const uint32_t metadata_fd_index = phnd->numFds - 1;
switch (metadata_fd_index) {
case 1:
size1 = SGR_METADATA_SIZE_SUB_TOTAL;
break;
case 2:
size2 = SGR_METADATA_SIZE_SUB_TOTAL;
break;
}
}
internal_format = phnd->alloc_format;
frameworkFormat = phnd->format;
SGR_LOGD("[%s] internal_format %x, frameworkFormat %x", __func__, (int)internal_format, (int)frameworkFormat);
width = phnd->width;
height = phnd->height;
stride = phnd->alloc_width;
vstride = phnd->alloc_height;
SGR_LOGD("[%s] width %d height %d, strid %d, vstride %d", __func__, width, height, stride, vstride);
producer_usage = usage;
consumer_usage = usage;
SGR_LOGD("[%s] usage %" PRIx64, __func__, usage);
flags = 0;
}
ExynosGraphicBufferMeta::ExynosGraphicBufferMeta(buffer_handle_t handle) {
init(handle);
}