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.stratiienko@gmail.com>
Tested-by: tarsin <yuanqingxiang233@163.com>
Acked-by: Chia-I Wu <olvaffe@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25410>
This commit is contained in:
Roman Stratiienko
2023-09-27 00:57:21 +03:00
committed by Marge Bot
parent 3922bd5976
commit 436051f8ee
5 changed files with 232 additions and 0 deletions

View File

@@ -12,6 +12,7 @@ files_u_gralloc = files(
'u_gralloc_internal.c', 'u_gralloc_internal.c',
'u_gralloc_fallback.c', 'u_gralloc_fallback.c',
'u_gralloc_cros_api.c', 'u_gralloc_cros_api.c',
'u_gralloc_qcom.c',
) )
if dep_android_mapper4.found() if dep_android_mapper4.found()

View File

@@ -28,6 +28,7 @@ static const struct u_grallocs {
#ifdef USE_IMAPPER4_METADATA_API #ifdef USE_IMAPPER4_METADATA_API
{.type = U_GRALLOC_TYPE_GRALLOC4, .create = u_gralloc_imapper_api_create}, {.type = U_GRALLOC_TYPE_GRALLOC4, .create = u_gralloc_imapper_api_create},
#endif /* USE_IMAPPER4_METADATA_API */ #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}, {.type = U_GRALLOC_TYPE_FALLBACK, .create = u_gralloc_fallback_create},
}; };

View File

@@ -51,6 +51,7 @@ enum u_gralloc_type {
U_GRALLOC_TYPE_AUTO, U_GRALLOC_TYPE_AUTO,
U_GRALLOC_TYPE_GRALLOC4, U_GRALLOC_TYPE_GRALLOC4,
U_GRALLOC_TYPE_CROS, U_GRALLOC_TYPE_CROS,
U_GRALLOC_TYPE_QCOM,
U_GRALLOC_TYPE_FALLBACK, U_GRALLOC_TYPE_FALLBACK,
U_GRALLOC_TYPE_COUNT, U_GRALLOC_TYPE_COUNT,
}; };

View File

@@ -35,6 +35,7 @@ extern struct u_gralloc *u_gralloc_cros_api_create(void);
#ifdef USE_IMAPPER4_METADATA_API #ifdef USE_IMAPPER4_METADATA_API
extern struct u_gralloc *u_gralloc_imapper_api_create(void); extern struct u_gralloc *u_gralloc_imapper_api_create(void);
#endif #endif
extern struct u_gralloc *u_gralloc_qcom_create(void);
extern struct u_gralloc *u_gralloc_fallback_create(void); extern struct u_gralloc *u_gralloc_fallback_create(void);
/* Helpers for legacy grallocs */ /* Helpers for legacy grallocs */

View File

@@ -0,0 +1,228 @@
/*
* Mesa 3-D graphics library
*
* Copyright (C) 2023 Roman Stratiienko (r.stratiienko@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;
}