diff --git a/src/util/meson.build b/src/util/meson.build index c0c1b9d1fa1..4ac84b1d055 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -23,6 +23,10 @@ # util is self contained. inc_util = [inc_include, include_directories('..')] +if with_platform_android +subdir('u_gralloc') +endif + subdir('blake3') files_mesa_util = files( diff --git a/src/util/u_gralloc/meson.build b/src/util/u_gralloc/meson.build new file mode 100644 index 00000000000..14e2cd0d115 --- /dev/null +++ b/src/util/u_gralloc/meson.build @@ -0,0 +1,35 @@ +# Mesa 3-D graphics library +# +# Copyright (C) 2022 Roman Stratiienko (r.stratiienko@gmail.com) +# SPDX-License-Identifier: MIT + +c_args_for_u_gralloc = [] +cpp_args_for_u_gralloc = [] +options_for_u_gralloc = [] + +files_u_gralloc = files( + 'u_gralloc.c', + 'u_gralloc_fallback.c', + 'u_gralloc_cros_api.c', +) + +if dep_android_mapper4.found() + files_u_gralloc += files('u_gralloc_imapper4_api.cpp') + c_args_for_u_gralloc += '-DUSE_IMAPPER4_METADATA_API' + cpp_args_for_u_gralloc += '-DUSE_IMAPPER4_METADATA_API' + options_for_u_gralloc += 'cpp_std=c++17' +endif + +_libmesa_u_gralloc = static_library( + '_mesa_u_gralloc', + [files_u_gralloc], + include_directories : [inc_include, inc_util], + c_args : c_args_for_u_gralloc, + cpp_args : cpp_args_for_u_gralloc, + override_options : options_for_u_gralloc, + gnu_symbol_visibility : 'hidden', + build_by_default : false, + dependencies: dep_android, +) + +idep_u_gralloc = declare_dependency(link_with: _libmesa_u_gralloc) diff --git a/src/util/u_gralloc/u_gralloc.c b/src/util/u_gralloc/u_gralloc.c new file mode 100644 index 00000000000..0d1e5f6f62b --- /dev/null +++ b/src/util/u_gralloc/u_gralloc.c @@ -0,0 +1,151 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2022 Roman Stratiienko (r.stratiienko@gmail.com) + * SPDX-License-Identifier: MIT + */ + +#include "u_gralloc_internal.h" + +#include +#include + +#include "drm-uapi/drm_fourcc.h" +#include "util/log.h" +#include "util/macros.h" +#include "util/simple_mtx.h" +#include "util/u_atomic.h" +#include "util/u_memory.h" + +static simple_mtx_t u_gralloc_mutex = SIMPLE_MTX_INITIALIZER; + +static const struct u_grallocs { + enum u_gralloc_type type; + struct u_gralloc *(*create)(); +} u_grallocs[] = { + {.type = U_GRALLOC_TYPE_CROS, .create = u_gralloc_cros_api_create}, +#ifdef USE_IMAPPER4_METADATA_API + {.type = U_GRALLOC_TYPE_GRALLOC4, .create = u_gralloc_imapper_api_create}, +#endif /* USE_IMAPPER4_METADATA_API */ + {.type = U_GRALLOC_TYPE_FALLBACK, .create = u_gralloc_fallback_create}, +}; + +static struct u_gralloc_cache { + struct u_gralloc *u_gralloc; + int refcount; +} u_gralloc_cache[U_GRALLOC_TYPE_COUNT] = {0}; + +struct u_gralloc * +u_gralloc_create(enum u_gralloc_type type) +{ + struct u_gralloc *out_gralloc = NULL; + + simple_mtx_lock(&u_gralloc_mutex); + + if (u_gralloc_cache[type].u_gralloc != NULL) { + u_gralloc_cache[type].refcount++; + out_gralloc = u_gralloc_cache[type].u_gralloc; + goto out; + } + + for (int i = 0; i < ARRAY_SIZE(u_grallocs); i++) { + if (u_grallocs[i].type != type && type != U_GRALLOC_TYPE_AUTO) + continue; + + u_gralloc_cache[type].u_gralloc = u_grallocs[i].create(); + if (u_gralloc_cache[type].u_gralloc) { + assert(u_gralloc_cache[type].u_gralloc->ops.get_buffer_basic_info); + assert(u_gralloc_cache[type].u_gralloc->ops.destroy); + + u_gralloc_cache[type].refcount = 1; + + out_gralloc = u_gralloc_cache[type].u_gralloc; + goto out; + } + } + +out: + simple_mtx_unlock(&u_gralloc_mutex); + + return out_gralloc; +} + +void +u_gralloc_destroy(struct u_gralloc **gralloc NONNULL) +{ + int i; + + if (*gralloc == NULL) + return; + + simple_mtx_lock(&u_gralloc_mutex); + + for (i = 0; i < ARRAY_SIZE(u_gralloc_cache); i++) { + if (u_gralloc_cache[i].u_gralloc == *gralloc) { + u_gralloc_cache[i].refcount--; + if (u_gralloc_cache[i].refcount == 0) { + u_gralloc_cache[i].u_gralloc->ops.destroy( + u_gralloc_cache[i].u_gralloc); + u_gralloc_cache[i].u_gralloc = NULL; + } + break; + } + } + + simple_mtx_unlock(&u_gralloc_mutex); + + assert(i < ARRAY_SIZE(u_grallocs)); + + *gralloc = NULL; +} + +inline int +u_gralloc_get_buffer_basic_info(struct u_gralloc *gralloc NONNULL, + struct u_gralloc_buffer_handle *hnd NONNULL, + struct u_gralloc_buffer_basic_info *out + NONNULL) +{ + struct u_gralloc_buffer_basic_info info = {0}; + int ret; + + ret = gralloc->ops.get_buffer_basic_info(gralloc, hnd, &info); + + if (ret) + return ret; + + *out = info; + + return 0; +} + +inline int +u_gralloc_get_buffer_color_info(struct u_gralloc *gralloc NONNULL, + struct u_gralloc_buffer_handle *hnd NONNULL, + struct u_gralloc_buffer_color_info *out + NONNULL) +{ + struct u_gralloc_buffer_color_info info = {0}; + int ret; + + if (!gralloc->ops.get_buffer_color_info) + return -ENOTSUP; + + ret = gralloc->ops.get_buffer_color_info(gralloc, hnd, &info); + + if (ret) + return ret; + + *out = info; + + return 0; +} + +inline int +u_gralloc_get_front_rendering_usage(struct u_gralloc *gralloc NONNULL, + uint64_t *out_usage NONNULL) +{ + if (!gralloc->ops.get_front_rendering_usage) + return -ENOTSUP; + + return gralloc->ops.get_front_rendering_usage(gralloc, out_usage); +} diff --git a/src/util/u_gralloc/u_gralloc.h b/src/util/u_gralloc/u_gralloc.h new file mode 100644 index 00000000000..596e3a31230 --- /dev/null +++ b/src/util/u_gralloc/u_gralloc.h @@ -0,0 +1,81 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2022 Roman Stratiienko (r.stratiienko@gmail.com) + * SPDX-License-Identifier: MIT + */ + +#ifndef U_GRALLOC_H +#define U_GRALLOC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +#include "util/macros.h" +#include "GL/internal/dri_interface.h" + +struct u_gralloc; + +/* Both Vulkan and EGL API exposes HAL format / pixel stride which is required + * by the fallback implementation. + */ +struct u_gralloc_buffer_handle { + const native_handle_t *handle; + int hal_format; + int pixel_stride; +}; + +struct u_gralloc_buffer_basic_info { + uint32_t drm_fourcc; + uint64_t modifier; + + int num_planes; + int fds[4]; + int offsets[4]; + int strides[4]; +}; + +struct u_gralloc_buffer_color_info { + enum __DRIYUVColorSpace yuv_color_space; + enum __DRISampleRange sample_range; + enum __DRIChromaSiting horizontal_siting; + enum __DRIChromaSiting vertical_siting; +}; + +enum u_gralloc_type { + U_GRALLOC_TYPE_AUTO, +#ifdef USE_IMAPPER4_METADATA_API + U_GRALLOC_TYPE_GRALLOC4, +#endif + U_GRALLOC_TYPE_CROS, + U_GRALLOC_TYPE_FALLBACK, + U_GRALLOC_TYPE_COUNT, +}; + +struct u_gralloc *u_gralloc_create(enum u_gralloc_type type); + +void u_gralloc_destroy(struct u_gralloc **gralloc NONNULL); + +int u_gralloc_get_buffer_basic_info( + struct u_gralloc *gralloc NONNULL, + struct u_gralloc_buffer_handle *hnd NONNULL, + struct u_gralloc_buffer_basic_info *out NONNULL); + +int u_gralloc_get_buffer_color_info( + struct u_gralloc *gralloc NONNULL, + struct u_gralloc_buffer_handle *hnd NONNULL, + struct u_gralloc_buffer_color_info *out NONNULL); + +int u_gralloc_get_front_rendering_usage(struct u_gralloc *gralloc NONNULL, + uint64_t *out_usage NONNULL); + +#ifdef __cplusplus +} +#endif + +#endif /* U_GRALLOC_H */ diff --git a/src/util/u_gralloc/u_gralloc_cros_api.c b/src/util/u_gralloc/u_gralloc_cros_api.c new file mode 100644 index 00000000000..a94e7fee724 --- /dev/null +++ b/src/util/u_gralloc/u_gralloc_cros_api.c @@ -0,0 +1,135 @@ +/* + * Mesa 3-D graphics library + * + * Copyright © 2021, Google Inc. + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +#include "util/log.h" +#include "util/u_memory.h" + +#include "u_gralloc_internal.h" + +/* More recent CrOS gralloc has a perform op that fills out the struct below + * with canonical information about the buffer and its modifier, planes, + * offsets and strides. If we have this, we can skip straight to + * createImageFromDmaBufs2() and avoid all the guessing and recalculations. + * This also gives us the modifier and plane offsets/strides for multiplanar + * compressed buffers (eg Intel CCS buffers) in order to make that work in + * Android. + */ + +struct cros_gralloc { + struct u_gralloc base; + gralloc_module_t *gralloc_module; +}; + +static const char cros_gralloc_module_name[] = "CrOS Gralloc"; + +#define CROS_GRALLOC_DRM_GET_BUFFER_INFO 4 +#define CROS_GRALLOC_DRM_GET_USAGE 5 +#define CROS_GRALLOC_DRM_GET_USAGE_FRONT_RENDERING_BIT 0x1 + +struct cros_gralloc0_buffer_info { + uint32_t drm_fourcc; + int num_fds; + int fds[4]; + uint64_t modifier; + int offset[4]; + int stride[4]; +}; + +static int +cros_get_buffer_info(struct u_gralloc *gralloc, + struct u_gralloc_buffer_handle *hnd, + struct u_gralloc_buffer_basic_info *out) +{ + struct cros_gralloc0_buffer_info info; + struct cros_gralloc *gr = (struct cros_gralloc *)gralloc; + gralloc_module_t *gr_mod = gr->gralloc_module; + + if (gr_mod->perform(gr_mod, CROS_GRALLOC_DRM_GET_BUFFER_INFO, hnd->handle, + &info) == 0) { + out->drm_fourcc = info.drm_fourcc; + out->modifier = info.modifier; + out->num_planes = info.num_fds; + for (int i = 0; i < out->num_planes; i++) { + out->fds[i] = info.fds[i]; + out->offsets[i] = info.offset[i]; + out->strides[i] = info.stride[i]; + } + + return 0; + } + + return -EINVAL; +} + +static int +cros_get_front_rendering_usage(struct u_gralloc *gralloc, uint64_t *out_usage) +{ + struct cros_gralloc *gr = (struct cros_gralloc *)gralloc; + uint32_t front_rendering_usage = 0; + + if (gr->gralloc_module->perform( + gr->gralloc_module, CROS_GRALLOC_DRM_GET_USAGE, + CROS_GRALLOC_DRM_GET_USAGE_FRONT_RENDERING_BIT, + &front_rendering_usage) == 0) { + *out_usage = front_rendering_usage; + return 0; + } + + return -ENOTSUP; +} + +static int +destroy(struct u_gralloc *gralloc) +{ + struct cros_gralloc *gr = (struct cros_gralloc *)gralloc; + if (gr->gralloc_module) + dlclose(gr->gralloc_module->common.dso); + + FREE(gr); + + return 0; +} + +struct u_gralloc * +u_gralloc_cros_api_create() +{ + struct cros_gralloc *gr = CALLOC_STRUCT(cros_gralloc); + int err = 0; + + err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, + (const hw_module_t **)&gr->gralloc_module); + + if (err) + goto fail; + + if (strcmp(gr->gralloc_module->common.name, cros_gralloc_module_name) != 0) + goto fail; + + if (!gr->gralloc_module->perform) { + mesa_logw("Oops. CrOS gralloc doesn't have perform callback"); + goto fail; + } + + gr->base.ops.get_buffer_basic_info = cros_get_buffer_info; + gr->base.ops.get_front_rendering_usage = cros_get_front_rendering_usage; + gr->base.ops.destroy = destroy; + + mesa_logi("Using gralloc0 CrOS API"); + + return &gr->base; + +fail: + destroy(&gr->base); + + return NULL; +} diff --git a/src/util/u_gralloc/u_gralloc_fallback.c b/src/util/u_gralloc/u_gralloc_fallback.c new file mode 100644 index 00000000000..27999a76ff1 --- /dev/null +++ b/src/util/u_gralloc/u_gralloc_fallback.c @@ -0,0 +1,343 @@ +/* + * Mesa 3-D graphics library + * + * Copyright © 2021, Google Inc. + * SPDX-License-Identifier: MIT + */ + +#include "u_gralloc_internal.h" + +#include + +#include "drm-uapi/drm_fourcc.h" +#include "util/log.h" +#include "util/macros.h" +#include "util/u_memory.h" + +#include +#include +#include + +struct fallback_gralloc { + struct u_gralloc base; + gralloc_module_t *gralloc_module; +}; + +enum chroma_order { + YCbCr, + YCrCb, +}; + +struct droid_yuv_format { + /* Lookup keys */ + int native; /* HAL_PIXEL_FORMAT_ */ + enum chroma_order chroma_order; /* chroma order is {Cb, Cr} or {Cr, Cb} */ + int chroma_step; /* Distance in bytes between subsequent chroma pixels. */ + + /* Result */ + int fourcc; /* DRM_FORMAT_ */ +}; + +/* The following table is used to look up a DRI image FourCC based + * on native format and information contained in android_ycbcr struct. */ +static const struct droid_yuv_format droid_yuv_formats[] = { + /* Native format, YCrCb, Chroma step, DRI image FourCC */ + {HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 2, DRM_FORMAT_NV12}, + {HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 1, DRM_FORMAT_YUV420}, + {HAL_PIXEL_FORMAT_YCbCr_420_888, YCrCb, 1, DRM_FORMAT_YVU420}, + {HAL_PIXEL_FORMAT_YV12, YCrCb, 1, DRM_FORMAT_YVU420}, + /* HACK: See droid_create_image_from_prime_fds() and + * https://issuetracker.google.com/32077885. */ + {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 2, DRM_FORMAT_NV12}, + {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 1, DRM_FORMAT_YUV420}, + {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_YVU420}, + {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_AYUV}, + {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_XYUV8888}, +}; + +static int +get_fourcc_yuv(int native, enum chroma_order chroma_order, int chroma_step) +{ + for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i) + if (droid_yuv_formats[i].native == native && + droid_yuv_formats[i].chroma_order == chroma_order && + droid_yuv_formats[i].chroma_step == chroma_step) + return droid_yuv_formats[i].fourcc; + + return -1; +} + +static bool +is_yuv(int native) +{ + for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i) + if (droid_yuv_formats[i].native == native) + return true; + + return false; +} + +static int +get_format_bpp(int native) +{ + int bpp; + + switch (native) { + case HAL_PIXEL_FORMAT_RGBA_FP16: + bpp = 8; + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: + /* + * HACK: Hardcode this to RGBX_8888 as per cros_gralloc hack. + * TODO: Remove this once https://issuetracker.google.com/32077885 is + * fixed. + */ + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_1010102: + bpp = 4; + break; + case HAL_PIXEL_FORMAT_RGB_565: + bpp = 2; + break; + default: + bpp = 0; + break; + } + + return bpp; +} + +/* createImageFromFds requires fourcc format */ +static int +get_fourcc(int native) +{ + switch (native) { + case HAL_PIXEL_FORMAT_RGB_565: + return DRM_FORMAT_RGB565; + case HAL_PIXEL_FORMAT_BGRA_8888: + return DRM_FORMAT_ARGB8888; + case HAL_PIXEL_FORMAT_RGBA_8888: + return DRM_FORMAT_ABGR8888; + case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: + /* + * HACK: Hardcode this to RGBX_8888 as per cros_gralloc hack. + * TODO: Remove this once https://issuetracker.google.com/32077885 is + * fixed. + */ + case HAL_PIXEL_FORMAT_RGBX_8888: + return DRM_FORMAT_XBGR8888; + case HAL_PIXEL_FORMAT_RGBA_FP16: + return DRM_FORMAT_ABGR16161616F; + case HAL_PIXEL_FORMAT_RGBA_1010102: + return DRM_FORMAT_ABGR2101010; + default: + mesa_logw("unsupported native buffer format 0x%x", native); + } + return -1; +} + +/* returns # of fds, and by reference the actual fds */ +static unsigned +get_native_buffer_fds(const native_handle_t *handle, int fds[3]) +{ + if (!handle) + return 0; + + /* + * Various gralloc implementations exist, but the dma-buf fd tends + * to be first. Access it directly to avoid a dependency on specific + * gralloc versions. + */ + for (int i = 0; i < handle->numFds; i++) + fds[i] = handle->data[i]; + + return handle->numFds; +} + +static int +fallback_gralloc_get_yuv_info(struct u_gralloc *gralloc, + struct u_gralloc_buffer_handle *hnd, + struct u_gralloc_buffer_basic_info *out) +{ + struct fallback_gralloc *gr = (struct fallback_gralloc *)gralloc; + gralloc_module_t *gr_mod = gr->gralloc_module; + enum chroma_order chroma_order; + struct android_ycbcr ycbcr; + int drm_fourcc = 0; + int num_planes = 0; + int num_fds = 0; + int fds[3]; + int ret; + + num_fds = get_native_buffer_fds(hnd->handle, fds); + if (num_fds == 0) + return -EINVAL; + + if (!gr_mod || !gr_mod->lock_ycbcr) { + return -EINVAL; + } + + memset(&ycbcr, 0, sizeof(ycbcr)); + ret = gr_mod->lock_ycbcr(gr_mod, hnd->handle, 0, 0, 0, 0, 0, &ycbcr); + if (ret) { + /* HACK: See native_window_buffer_get_buffer_info() and + * https://issuetracker.google.com/32077885.*/ + if (hnd->hal_format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) + return -EAGAIN; + + mesa_logw("gralloc->lock_ycbcr failed: %d", ret); + return -EINVAL; + } + gr_mod->unlock(gr_mod, hnd->handle); + + chroma_order = ((size_t)ycbcr.cr < (size_t)ycbcr.cb) ? YCrCb : YCbCr; + + /* .chroma_step is the byte distance between the same chroma channel + * values of subsequent pixels, assumed to be the same for Cb and Cr. */ + drm_fourcc = + get_fourcc_yuv(hnd->hal_format, chroma_order, ycbcr.chroma_step); + if (drm_fourcc == -1) { + mesa_logw("unsupported YUV format, native = %x, chroma_order = %s, " + "chroma_step = %zu", + hnd->hal_format, chroma_order == YCbCr ? "YCbCr" : "YCrCb", + ycbcr.chroma_step); + return -EINVAL; + } + + out->drm_fourcc = drm_fourcc; + out->modifier = DRM_FORMAT_MOD_INVALID; + + num_planes = ycbcr.chroma_step == 2 ? 2 : 3; + /* When lock_ycbcr's usage argument contains no SW_READ/WRITE flags + * it will return the .y/.cb/.cr pointers based on a NULL pointer, + * so they can be interpreted as offsets. */ + out->offsets[0] = (size_t)ycbcr.y; + /* We assume here that all the planes are located in one DMA-buf. */ + if (chroma_order == YCrCb) { + out->offsets[1] = (size_t)ycbcr.cr; + out->offsets[2] = (size_t)ycbcr.cb; + } else { + out->offsets[1] = (size_t)ycbcr.cb; + out->offsets[2] = (size_t)ycbcr.cr; + } + + /* .ystride is the line length (in bytes) of the Y plane, + * .cstride is the line length (in bytes) of any of the remaining + * Cb/Cr/CbCr planes, assumed to be the same for Cb and Cr for fully + * planar formats. */ + out->strides[0] = ycbcr.ystride; + out->strides[1] = out->strides[2] = ycbcr.cstride; + + /* + * Since this is EGL_NATIVE_BUFFER_ANDROID don't assume that + * the single-fd case cannot happen. So handle eithe single + * fd or fd-per-plane case: + */ + if (num_fds == 1) { + out->fds[1] = out->fds[0] = fds[0]; + if (out->num_planes == 3) + out->fds[2] = fds[0]; + } else { + assert(num_fds == out->num_planes); + out->fds[0] = fds[0]; + out->fds[1] = fds[1]; + out->fds[2] = fds[2]; + } + + return 0; +} + +static int +fallback_gralloc_get_buffer_info(struct u_gralloc *gralloc, + struct u_gralloc_buffer_handle *hnd, + struct u_gralloc_buffer_basic_info *out) +{ + int num_planes = 0; + int drm_fourcc = 0; + int stride = 0; + int fds[3]; + + if (is_yuv(hnd->hal_format)) { + int ret = fallback_gralloc_get_yuv_info(gralloc, hnd, out); + /* + * HACK: https://issuetracker.google.com/32077885 + * There is no API available to properly query the + * IMPLEMENTATION_DEFINED format. As a workaround we rely here on + * gralloc allocating either an arbitrary YCbCr 4:2:0 or RGBX_8888, with + * the latter being recognized by lock_ycbcr failing. + */ + if (ret != -EAGAIN) + return ret; + } + + /* + * Non-YUV formats could *also* have multiple planes, such as ancillary + * color compression state buffer, but the rest of the code isn't ready + * yet to deal with modifiers: + */ + num_planes = get_native_buffer_fds(hnd->handle, fds); + if (num_planes == 0) + return -EINVAL; + + assert(num_planes == 1); + + drm_fourcc = get_fourcc(hnd->hal_format); + if (drm_fourcc == -1) { + mesa_loge("Failed to get drm_fourcc"); + return -EINVAL; + } + + stride = hnd->pixel_stride * get_format_bpp(hnd->hal_format); + if (stride == 0) { + mesa_loge("Failed to calcuulate stride"); + return -EINVAL; + } + + out->drm_fourcc = drm_fourcc; + out->modifier = DRM_FORMAT_MOD_INVALID; + out->num_planes = num_planes; + out->fds[0] = fds[0]; + out->strides[0] = stride; + + return 0; +} + +static int +destroy(struct u_gralloc *gralloc) +{ + struct fallback_gralloc *gr = (struct fallback_gralloc *)gralloc; + if (gr->gralloc_module) { + dlclose(gr->gralloc_module->common.dso); + } + + FREE(gr); + + return 0; +} + +struct u_gralloc * +u_gralloc_fallback_create() +{ + struct fallback_gralloc *gr = CALLOC_STRUCT(fallback_gralloc); + int err = 0; + + err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, + (const hw_module_t **)&gr->gralloc_module); + + if (err) { + mesa_logw( + "No gralloc hwmodule detected (video buffers won't be supported)"); + } else if (!gr->gralloc_module->lock_ycbcr) { + mesa_logw("Gralloc doesn't support lock_ycbcr (video buffers won't be " + "supported)"); + } + + gr->base.ops.get_buffer_basic_info = fallback_gralloc_get_buffer_info; + gr->base.ops.destroy = destroy; + + mesa_logi("Using fallback gralloc implementation"); + + return &gr->base; +} diff --git a/src/util/u_gralloc/u_gralloc_imapper4_api.cpp b/src/util/u_gralloc/u_gralloc_imapper4_api.cpp new file mode 100644 index 00000000000..3b9380f51ae --- /dev/null +++ b/src/util/u_gralloc/u_gralloc_imapper4_api.cpp @@ -0,0 +1,294 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2021 GlobalLogic Ukraine + * Copyright (C) 2021-2022 Roman Stratiienko (r.stratiienko@gmail.com) + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util/log.h" +#include "u_gralloc_internal.h" + +using aidl::android::hardware::graphics::common::BufferUsage; +using aidl::android::hardware::graphics::common::ChromaSiting; +using aidl::android::hardware::graphics::common::Dataspace; +using aidl::android::hardware::graphics::common::ExtendableType; +using aidl::android::hardware::graphics::common::PlaneLayout; +using aidl::android::hardware::graphics::common::PlaneLayoutComponent; +using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; +using android::hardware::hidl_handle; +using android::hardware::hidl_vec; +using android::hardware::graphics::mapper::V4_0::Error; +using android::hardware::graphics::mapper::V4_0::IMapper; + +using MetadataType = + android::hardware::graphics::mapper::V4_0::IMapper::MetadataType; + +Error +GetMetadata(android::sp mapper, const native_handle_t *buffer, + MetadataType type, hidl_vec *metadata) +{ + Error error = Error::NONE; + + auto native_handle = const_cast(buffer); + + auto ret = + mapper->get(native_handle, type, + [&](const auto &get_error, const auto &get_metadata) { + error = get_error; + *metadata = get_metadata; + }); + + if (!ret.isOk()) + error = Error::NO_RESOURCES; + + return error; +} + +std::optional> +GetPlaneLayouts(android::sp mapper, const native_handle_t *buffer) +{ + hidl_vec encoded_layouts; + + Error error = GetMetadata(mapper, buffer, + android::gralloc4::MetadataType_PlaneLayouts, + &encoded_layouts); + + if (error != Error::NONE) + return std::nullopt; + + std::vector plane_layouts; + + auto status = + android::gralloc4::decodePlaneLayouts(encoded_layouts, &plane_layouts); + + if (status != android::OK) + return std::nullopt; + + return plane_layouts; +} + +struct gralloc4 { + struct u_gralloc base; + android::sp mapper; +}; + +extern "C" { + +static int +mapper4_get_buffer_basic_info(struct u_gralloc *gralloc, + struct u_gralloc_buffer_handle *hnd, + struct u_gralloc_buffer_basic_info *out) +{ + gralloc4 *gr4 = (gralloc4 *)gralloc; + + if (gr4->mapper == nullptr) + return -EINVAL; + + if (!hnd->handle) + return -EINVAL; + + hidl_vec encoded_format; + auto err = GetMetadata(gr4->mapper, hnd->handle, + android::gralloc4::MetadataType_PixelFormatFourCC, + &encoded_format); + if (err != Error::NONE) + return -EINVAL; + + uint32_t drm_fourcc; + + auto status = + android::gralloc4::decodePixelFormatFourCC(encoded_format, &drm_fourcc); + if (status != android::OK) + return -EINVAL; + + uint64_t drm_modifier; + + hidl_vec encoded_modifier; + err = GetMetadata(gr4->mapper, hnd->handle, + android::gralloc4::MetadataType_PixelFormatModifier, + &encoded_modifier); + if (err != Error::NONE) + return -EINVAL; + + status = android::gralloc4::decodePixelFormatModifier(encoded_modifier, + &drm_modifier); + if (status != android::OK) + return -EINVAL; + + out->drm_fourcc = drm_fourcc; + out->modifier = drm_modifier; + + auto layouts_opt = GetPlaneLayouts(gr4->mapper, hnd->handle); + + if (!layouts_opt) + return -EINVAL; + + std::vector &layouts = *layouts_opt; + + out->num_planes = layouts.size(); + + int fd_index = 0; + + for (uint32_t i = 0; i < layouts.size(); i++) { + out->strides[i] = layouts[i].strideInBytes; + out->offsets[i] = layouts[i].offsetInBytes; + + /* offset == 0 means layer is located in different dma-buf */ + if (out->offsets[i] == 0 && i > 0) + fd_index++; + + if (fd_index >= hnd->handle->numFds) + return -EINVAL; + + out->fds[i] = hnd->handle->data[fd_index]; + } + + return 0; +} + +static int +mapper4_get_buffer_color_info(struct u_gralloc *gralloc, + struct u_gralloc_buffer_handle *hnd, + struct u_gralloc_buffer_color_info *out) +{ + gralloc4 *gr4 = (gralloc4 *)gralloc; + + if (gr4->mapper == nullptr) + return -EINVAL; + + if (!hnd->handle) + return -EINVAL; + + /* optional attributes */ + hidl_vec encoded_chroma_siting; + std::optional chroma_siting; + auto err = GetMetadata(gr4->mapper, hnd->handle, + android::gralloc4::MetadataType_ChromaSiting, + &encoded_chroma_siting); + if (err == Error::NONE) { + ExtendableType chroma_siting_ext; + auto status = android::gralloc4::decodeChromaSiting( + encoded_chroma_siting, &chroma_siting_ext); + if (status != android::OK) + return -EINVAL; + + chroma_siting = + android::gralloc4::getStandardChromaSitingValue(chroma_siting_ext); + } + + hidl_vec encoded_dataspace; + err = GetMetadata(gr4->mapper, hnd->handle, + android::gralloc4::MetadataType_Dataspace, + &encoded_dataspace); + if (err == Error::NONE) { + Dataspace dataspace; + auto status = + android::gralloc4::decodeDataspace(encoded_dataspace, &dataspace); + if (status != android::OK) + return -EINVAL; + + Dataspace standard = + (Dataspace)((int)dataspace & (uint32_t)Dataspace::STANDARD_MASK); + switch (standard) { + case Dataspace::STANDARD_BT709: + out->yuv_color_space = __DRI_YUV_COLOR_SPACE_ITU_REC709; + break; + case Dataspace::STANDARD_BT601_625: + case Dataspace::STANDARD_BT601_625_UNADJUSTED: + case Dataspace::STANDARD_BT601_525: + case Dataspace::STANDARD_BT601_525_UNADJUSTED: + out->yuv_color_space = __DRI_YUV_COLOR_SPACE_ITU_REC601; + break; + case Dataspace::STANDARD_BT2020: + case Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE: + out->yuv_color_space = __DRI_YUV_COLOR_SPACE_ITU_REC2020; + break; + default: + break; + } + + Dataspace range = + (Dataspace)((int)dataspace & (uint32_t)Dataspace::RANGE_MASK); + switch (range) { + case Dataspace::RANGE_FULL: + out->sample_range = __DRI_YUV_FULL_RANGE; + break; + case Dataspace::RANGE_LIMITED: + out->sample_range = __DRI_YUV_NARROW_RANGE; + break; + default: + break; + } + } + + if (chroma_siting) { + switch (*chroma_siting) { + case ChromaSiting::SITED_INTERSTITIAL: + out->horizontal_siting = __DRI_YUV_CHROMA_SITING_0_5; + out->vertical_siting = __DRI_YUV_CHROMA_SITING_0_5; + break; + case ChromaSiting::COSITED_HORIZONTAL: + out->horizontal_siting = __DRI_YUV_CHROMA_SITING_0; + out->vertical_siting = __DRI_YUV_CHROMA_SITING_0_5; + break; + default: + break; + } + } + + return 0; +} + +static int +mapper4_get_front_rendering_usage(struct u_gralloc *gralloc, + uint64_t *out_usage) +{ + assert(out_usage); +#if ANDROID_API_LEVEL >= 33 + *out_usage = static_cast(BufferUsage::FRONT_BUFFER); + + return 0; +#else + return -ENOTSUP; +#endif +} + +static int +destroy(struct u_gralloc *gralloc) +{ + gralloc4 *gr = (struct gralloc4 *)gralloc; + delete gr; + + return 0; +} + +struct u_gralloc * +u_gralloc_imapper_api_create() +{ + auto mapper = IMapper::getService(); + if (!mapper) + return NULL; + + auto gr = new gralloc4; + gr->mapper = mapper; + gr->base.ops.get_buffer_basic_info = mapper4_get_buffer_basic_info; + gr->base.ops.get_buffer_color_info = mapper4_get_buffer_color_info; + gr->base.ops.get_front_rendering_usage = mapper4_get_front_rendering_usage; + gr->base.ops.destroy = destroy; + + mesa_logi("Using IMapper v4 API"); + + return &gr->base; +} + +} // extern "C" diff --git a/src/util/u_gralloc/u_gralloc_internal.h b/src/util/u_gralloc/u_gralloc_internal.h new file mode 100644 index 00000000000..a837d2ea33d --- /dev/null +++ b/src/util/u_gralloc/u_gralloc_internal.h @@ -0,0 +1,43 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2023 Roman Stratiienko (r.stratiienko@gmail.com) + * SPDX-License-Identifier: MIT + */ + +#ifndef U_GRALLOC_INTERNAL_H +#define U_GRALLOC_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "u_gralloc.h" + +struct u_gralloc_ops { + int (*get_buffer_basic_info)(struct u_gralloc *gralloc, + struct u_gralloc_buffer_handle *hnd, + struct u_gralloc_buffer_basic_info *out); + int (*get_buffer_color_info)(struct u_gralloc *gralloc, + struct u_gralloc_buffer_handle *hnd, + struct u_gralloc_buffer_color_info *out); + int (*get_front_rendering_usage)(struct u_gralloc *gralloc, + uint64_t *out_usage); + int (*destroy)(struct u_gralloc *gralloc); +}; + +struct u_gralloc { + struct u_gralloc_ops ops; +}; + +extern struct u_gralloc *u_gralloc_cros_api_create(void); +#ifdef USE_IMAPPER4_METADATA_API +extern struct u_gralloc *u_gralloc_imapper_api_create(void); +#endif +extern struct u_gralloc *u_gralloc_fallback_create(void); + +#ifdef __cplusplus +} +#endif + +#endif /* U_GRALLOC_INTERNAL_H */