xref: /aosp_15_r20/external/mesa3d/src/util/u_gralloc/u_gralloc_qcom.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 2023 Roman Stratiienko ([email protected])
5  * SPDX-License-Identifier: MIT
6  */
7 
8 #include <assert.h>
9 #include <dlfcn.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <hardware/gralloc.h>
13 #include <hardware/gralloc1.h>
14 
15 #include "drm-uapi/drm_fourcc.h"
16 
17 #include "util/log.h"
18 #include "util/u_memory.h"
19 
20 #include "u_gralloc_internal.h"
21 
22 /* Using this gralloc is not recommended for new distributions. */
23 
24 struct qcom_gralloc {
25    struct u_gralloc base;
26    hw_module_t *gralloc_module;
27    gralloc1_device_t *gralloc1_device;
28    void *perform_handle;
29    int (* perform)(void *dev, int op, ...);
30    struct u_gralloc *fallback_gralloc;
31 };
32 
33 #define GRALLOC1_FUNCTION_PERFORM 0x00001000 /* QCOM gralloc-specific */
34 
35 static const char qcom_gralloc_name[] = "Graphics Memory Allocator Module";
36 static const char qcom_gralloc_author[] = "The Android Open Source Project";
37 
38 static const char caf_gralloc_name[] = "Graphics Memory Module";
39 static const char caf_gralloc_author[] = "Code Aurora Forum";
40 
41 #define QCOM_GRALLOC_PROBE_WIDTH 1024
42 #define QCOM_GRALLOC_PROBE_FORMAT 1 /* HAL_PIXEL_FORMAT_RGBA_8888 */
43 
44 #define GRALLOC_MODULE_PERFORM_GET_STRIDE 2
45 #define GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO 7
46 #define GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG 9
47 
48 static int
fallback_gralloc_get_yuv_info(struct u_gralloc * gralloc,struct u_gralloc_buffer_handle * hnd,struct u_gralloc_buffer_basic_info * out)49 fallback_gralloc_get_yuv_info(struct u_gralloc *gralloc,
50                               struct u_gralloc_buffer_handle *hnd,
51                               struct u_gralloc_buffer_basic_info *out)
52 {
53    struct qcom_gralloc *gr = (struct qcom_gralloc *)gralloc;
54    struct android_ycbcr ycbcr;
55    int ret;
56 
57    memset(&ycbcr, 0, sizeof(ycbcr));
58    ret = gr->perform(gr->perform_handle,
59                      GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO,
60                      hnd->handle, &ycbcr);
61    if (ret) {
62       /* HACK: See native_window_buffer_get_buffer_info() and
63        * https://issuetracker.google.com/32077885.*/
64       if (hnd->hal_format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)
65          return -EAGAIN;
66 
67       mesa_logw("gralloc->lock_ycbcr failed: %d", ret);
68       return -EINVAL;
69    }
70 
71    ret = bufferinfo_from_ycbcr(&ycbcr, hnd, out);
72    if (ret)
73       return ret;
74 
75    out->fds[1] = out->fds[0] = hnd->handle->data[0];
76    if (out->num_planes == 3)
77       out->fds[2] = hnd->handle->data[0];
78 
79    return 0;
80 }
81 
82 static int
get_buffer_info(struct u_gralloc * gralloc,struct u_gralloc_buffer_handle * hnd,struct u_gralloc_buffer_basic_info * out)83 get_buffer_info(struct u_gralloc *gralloc,
84                 struct u_gralloc_buffer_handle *hnd,
85                 struct u_gralloc_buffer_basic_info *out)
86 {
87    struct qcom_gralloc *gr = (struct qcom_gralloc *)gralloc;
88 
89    int drm_fourcc = 0;
90    int stride = 0;
91    int out_flag = 0;
92    int err;
93 
94    err = gr->perform(gr->perform_handle, GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG,
95                      hnd->handle, &out_flag);
96    /* This may fail since some earlier MSM  grallocs do not support this
97     * perform call
98     */
99    if (!err && out_flag)
100       out->modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED;
101    else
102       out->modifier = DRM_FORMAT_MOD_LINEAR;
103 
104    if (is_hal_format_yuv(hnd->hal_format)) {
105       int ret = fallback_gralloc_get_yuv_info(gralloc, hnd, out);
106       /*
107        * HACK: https://issuetracker.google.com/32077885
108        * There is no API available to properly query the
109        * IMPLEMENTATION_DEFINED format. As a workaround we rely here on
110        * gralloc allocating either an arbitrary YCbCr 4:2:0 or RGBX_8888, with
111        * the latter being recognized by lock_ycbcr failing.
112        */
113       if (ret != -EAGAIN)
114          return ret;
115    }
116 
117    drm_fourcc = get_fourcc_from_hal_format(hnd->hal_format);
118    if (drm_fourcc == -1) {
119       mesa_loge("Failed to get drm_fourcc");
120       return -EINVAL;
121    }
122 
123    stride = hnd->pixel_stride * get_hal_format_bpp(hnd->hal_format);
124    if (stride == 0) {
125       mesa_loge("Failed to calcuulate stride");
126       return -EINVAL;
127    }
128 
129    out->drm_fourcc = drm_fourcc;
130    out->num_planes = 1;
131    out->fds[0] = hnd->handle->data[0];
132    out->strides[0] = stride;
133 
134    return 0;
135 }
136 
137 static int
destroy(struct u_gralloc * gralloc)138 destroy(struct u_gralloc *gralloc)
139 {
140    struct qcom_gralloc *gr = (struct qcom_gralloc *)gralloc;
141    if (gr->gralloc1_device)
142       gralloc1_close(gr->gralloc1_device);
143 
144    if (gr->gralloc_module)
145       dlclose(gr->gralloc_module->dso);
146 
147    if (gr->fallback_gralloc)
148       gr->fallback_gralloc->ops.destroy(gr->fallback_gralloc);
149 
150    FREE(gr);
151 
152    return 0;
153 }
154 
155 struct u_gralloc *
u_gralloc_qcom_create()156 u_gralloc_qcom_create()
157 {
158    struct qcom_gralloc *gr = CALLOC_STRUCT(qcom_gralloc);
159    int err = 0;
160 
161    err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
162                        (const hw_module_t **)&gr->gralloc_module);
163 
164    if (err)
165       goto fail;
166 
167    bool match = false;
168 
169    if (strcmp(gr->gralloc_module->name, qcom_gralloc_name) == 0 &&
170        strcmp(gr->gralloc_module->author, qcom_gralloc_author) == 0) {
171       match = true;
172    }
173 
174    if (strcmp(gr->gralloc_module->name, caf_gralloc_name) == 0 &&
175        strcmp(gr->gralloc_module->author, caf_gralloc_author) == 0) {
176       match = true;
177    }
178 
179    if (!match)
180       goto fail;
181 
182    if (gr->gralloc_module->module_api_version <= GRALLOC_MODULE_API_VERSION_0_3) {
183       gralloc_module_t *gralloc_module =
184          (gralloc_module_t *)gr->gralloc_module;
185       gr->perform = (int (*)(void *, int, ...))gralloc_module->perform;
186       gr->perform_handle = gr->gralloc_module;
187    } else {
188       err = gralloc1_open(gr->gralloc_module, &gr->gralloc1_device);
189       if (err)
190          goto fail;
191 
192       gr->perform = (int (*)(void *, int, ...))gr->gralloc1_device->
193          getFunction(gr->gralloc1_device, GRALLOC1_FUNCTION_PERFORM);
194 
195       gr->perform_handle = gr->gralloc1_device;
196    }
197 
198    if (!gr->perform)
199       goto fail;
200 
201    /* Check if the gralloc module supports the required perform call */
202    int out_stride = 0;
203    err = gr->perform(gr->perform_handle,
204                      GRALLOC_MODULE_PERFORM_GET_STRIDE,
205                      QCOM_GRALLOC_PROBE_WIDTH,
206                      QCOM_GRALLOC_PROBE_FORMAT,
207                      &out_stride);
208    if (err)
209       goto fail;
210 
211    if (out_stride == 0)
212       goto fail;
213 
214    gr->base.ops.get_buffer_basic_info = get_buffer_info;
215    gr->base.ops.destroy = destroy;
216 
217    mesa_logi("Using QCOM gralloc (aosp/hardware/qcom/display/*/libgralloc). ");
218    mesa_logw("QCOM Gralloc API is old. Consider using Gralloc4 API instead.");
219 
220    gr->fallback_gralloc = u_gralloc_fallback_create();
221 
222    return &gr->base;
223 
224 fail:
225    destroy(&gr->base);
226 
227    return NULL;
228 }
229