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