Module: Mesa Branch: main Commit: 436051f8eee992287fdf3f785a2021ac4460d6b1 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=436051f8eee992287fdf3f785a2021ac4460d6b1
Author: Roman Stratiienko <r.stratiie...@gmail.com> Date: Wed Sep 27 00:57:21 2023 +0300 u_gralloc: Add QCOM gralloc support Adds support for legacy QCOM grallocs that are a part of AOSP: hardware/qcom/display/*/libgralloc Signed-off-by: Roman Stratiienko <r.stratiie...@gmail.com> Tested-by: tarsin <yuanqingxiang...@163.com> Acked-by: Chia-I Wu <olva...@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25410> --- src/util/u_gralloc/meson.build | 1 + src/util/u_gralloc/u_gralloc.c | 1 + src/util/u_gralloc/u_gralloc.h | 1 + src/util/u_gralloc/u_gralloc_internal.h | 1 + src/util/u_gralloc/u_gralloc_qcom.c | 228 ++++++++++++++++++++++++++++++++ 5 files changed, 232 insertions(+) diff --git a/src/util/u_gralloc/meson.build b/src/util/u_gralloc/meson.build index e706ca46538..39f181cae3f 100644 --- a/src/util/u_gralloc/meson.build +++ b/src/util/u_gralloc/meson.build @@ -12,6 +12,7 @@ files_u_gralloc = files( 'u_gralloc_internal.c', 'u_gralloc_fallback.c', 'u_gralloc_cros_api.c', + 'u_gralloc_qcom.c', ) if dep_android_mapper4.found() diff --git a/src/util/u_gralloc/u_gralloc.c b/src/util/u_gralloc/u_gralloc.c index c2c8ed41f25..1e694e4e66e 100644 --- a/src/util/u_gralloc/u_gralloc.c +++ b/src/util/u_gralloc/u_gralloc.c @@ -28,6 +28,7 @@ static const struct u_grallocs { #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_QCOM, .create = u_gralloc_qcom_create}, {.type = U_GRALLOC_TYPE_FALLBACK, .create = u_gralloc_fallback_create}, }; diff --git a/src/util/u_gralloc/u_gralloc.h b/src/util/u_gralloc/u_gralloc.h index 35eb8ffce39..9a56093fb41 100644 --- a/src/util/u_gralloc/u_gralloc.h +++ b/src/util/u_gralloc/u_gralloc.h @@ -51,6 +51,7 @@ enum u_gralloc_type { U_GRALLOC_TYPE_AUTO, U_GRALLOC_TYPE_GRALLOC4, U_GRALLOC_TYPE_CROS, + U_GRALLOC_TYPE_QCOM, U_GRALLOC_TYPE_FALLBACK, U_GRALLOC_TYPE_COUNT, }; diff --git a/src/util/u_gralloc/u_gralloc_internal.h b/src/util/u_gralloc/u_gralloc_internal.h index 277def2c629..b9bceef46cd 100644 --- a/src/util/u_gralloc/u_gralloc_internal.h +++ b/src/util/u_gralloc/u_gralloc_internal.h @@ -35,6 +35,7 @@ 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_qcom_create(void); extern struct u_gralloc *u_gralloc_fallback_create(void); /* Helpers for legacy grallocs */ diff --git a/src/util/u_gralloc/u_gralloc_qcom.c b/src/util/u_gralloc/u_gralloc_qcom.c new file mode 100644 index 00000000000..e8b82e55c12 --- /dev/null +++ b/src/util/u_gralloc/u_gralloc_qcom.c @@ -0,0 +1,228 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2023 Roman Stratiienko (r.stratiie...@gmail.com) + * SPDX-License-Identifier: MIT + */ + +#include <assert.h> +#include <dlfcn.h> +#include <errno.h> +#include <string.h> +#include <hardware/gralloc.h> +#include <hardware/gralloc1.h> + +#include "drm-uapi/drm_fourcc.h" + +#include "util/log.h" +#include "util/u_memory.h" + +#include "u_gralloc_internal.h" + +/* Using this gralloc is not recommended for new distributions. */ + +struct qcom_gralloc { + struct u_gralloc base; + hw_module_t *gralloc_module; + gralloc1_device_t *gralloc1_device; + void *perform_handle; + int (* perform)(void *dev, int op, ...); + struct u_gralloc *fallback_gralloc; +}; + +#define GRALLOC1_FUNCTION_PERFORM 0x00001000 /* QCOM gralloc-specific */ + +static const char qcom_gralloc_name[] = "Graphics Memory Allocator Module"; +static const char qcom_gralloc_author[] = "The Android Open Source Project"; + +static const char caf_gralloc_name[] = "Graphics Memory Module"; +static const char caf_gralloc_author[] = "Code Aurora Forum"; + +#define QCOM_GRALLOC_PROBE_WIDTH 1024 +#define QCOM_GRALLOC_PROBE_FORMAT 1 /* HAL_PIXEL_FORMAT_RGBA_8888 */ + +#define GRALLOC_MODULE_PERFORM_GET_STRIDE 2 +#define GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO 7 +#define GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG 9 + +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 qcom_gralloc *gr = (struct qcom_gralloc *)gralloc; + struct android_ycbcr ycbcr; + int ret; + + memset(&ycbcr, 0, sizeof(ycbcr)); + ret = gr->perform(gr->perform_handle, + GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO, + hnd->handle, &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; + } + + ret = bufferinfo_from_ycbcr(&ycbcr, hnd, out); + if (ret) + return ret; + + out->fds[1] = out->fds[0] = hnd->handle->data[0]; + if (out->num_planes == 3) + out->fds[2] = hnd->handle->data[0]; + + return 0; +} + +static int +get_buffer_info(struct u_gralloc *gralloc, + struct u_gralloc_buffer_handle *hnd, + struct u_gralloc_buffer_basic_info *out) +{ + struct qcom_gralloc *gr = (struct qcom_gralloc *)gralloc; + + int drm_fourcc = 0; + int stride = 0; + int out_flag = 0; + int err; + + err = gr->perform(gr->perform_handle, GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG, + hnd->handle, &out_flag); + /* This may fail since some earlier MSM grallocs do not support this + * perform call + */ + if (!err && out_flag) + out->modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED; + else + out->modifier = DRM_FORMAT_MOD_LINEAR; + + if (is_hal_format_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; + } + + drm_fourcc = get_fourcc_from_hal_format(hnd->hal_format); + if (drm_fourcc == -1) { + mesa_loge("Failed to get drm_fourcc"); + return -EINVAL; + } + + stride = hnd->pixel_stride * get_hal_format_bpp(hnd->hal_format); + if (stride == 0) { + mesa_loge("Failed to calcuulate stride"); + return -EINVAL; + } + + out->drm_fourcc = drm_fourcc; + out->num_planes = 1; + out->fds[0] = hnd->handle->data[0]; + out->strides[0] = stride; + + return 0; +} + +static int +destroy(struct u_gralloc *gralloc) +{ + struct qcom_gralloc *gr = (struct qcom_gralloc *)gralloc; + if (gr->gralloc1_device) + gralloc1_close(gr->gralloc1_device); + + if (gr->gralloc_module) + dlclose(gr->gralloc_module->dso); + + if (gr->fallback_gralloc) + gr->fallback_gralloc->ops.destroy(gr->fallback_gralloc); + + FREE(gr); + + return 0; +} + +struct u_gralloc * +u_gralloc_qcom_create() +{ + struct qcom_gralloc *gr = CALLOC_STRUCT(qcom_gralloc); + int err = 0; + + err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, + (const hw_module_t **)&gr->gralloc_module); + + if (err) + goto fail; + + bool match = false; + + if (strcmp(gr->gralloc_module->name, qcom_gralloc_name) == 0 && + strcmp(gr->gralloc_module->author, qcom_gralloc_author) == 0) { + match = true; + } + + if (strcmp(gr->gralloc_module->name, caf_gralloc_name) == 0 && + strcmp(gr->gralloc_module->author, caf_gralloc_author) == 0) { + match = true; + } + + if (!match) + goto fail; + + if (gr->gralloc_module->module_api_version <= GRALLOC_MODULE_API_VERSION_0_3) { + gralloc_module_t *gralloc_module = + (gralloc_module_t *)gr->gralloc_module; + gr->perform = (int (*)(void *, int, ...))gralloc_module->perform; + gr->perform_handle = gr->gralloc_module; + } else { + err = gralloc1_open(gr->gralloc_module, &gr->gralloc1_device); + if (err) + goto fail; + + gr->perform = (int (*)(void *, int, ...))gr->gralloc1_device-> + getFunction(gr->gralloc1_device, GRALLOC1_FUNCTION_PERFORM); + + gr->perform_handle = gr->gralloc1_device; + } + + if (!gr->perform) + goto fail; + + /* Check if the gralloc module supports the required perform call */ + int out_stride = 0; + err = gr->perform(gr->perform_handle, + GRALLOC_MODULE_PERFORM_GET_STRIDE, + QCOM_GRALLOC_PROBE_WIDTH, + QCOM_GRALLOC_PROBE_FORMAT, + &out_stride); + if (err) + goto fail; + + if (out_stride == 0) + goto fail; + + gr->base.ops.get_buffer_basic_info = get_buffer_info; + gr->base.ops.destroy = destroy; + + mesa_logi("Using QCOM gralloc (aosp/hardware/qcom/display/*/libgralloc). "); + mesa_logw("QCOM Gralloc API is old. Consider using Gralloc4 API instead."); + + gr->fallback_gralloc = u_gralloc_fallback_create(); + + return &gr->base; + +fail: + destroy(&gr->base); + + return NULL; +}