1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright © 2021, Google Inc.
5 * SPDX-License-Identifier: MIT
6 */
7
8 #include "u_gralloc_internal.h"
9
10 #include <hardware/gralloc.h>
11
12 #include "drm-uapi/drm_fourcc.h"
13 #include "util/log.h"
14 #include "util/macros.h"
15 #include "util/u_memory.h"
16
17 #include <dlfcn.h>
18 #include <errno.h>
19 #include <string.h>
20
21 struct fallback_gralloc {
22 struct u_gralloc base;
23 gralloc_module_t *gralloc_module;
24 };
25
26 /* returns # of fds, and by reference the actual fds */
27 static unsigned
get_native_buffer_fds(const native_handle_t * handle,int fds[3])28 get_native_buffer_fds(const native_handle_t *handle, int fds[3])
29 {
30 if (!handle)
31 return 0;
32
33 /*
34 * Various gralloc implementations exist, but the dma-buf fd tends
35 * to be first. Access it directly to avoid a dependency on specific
36 * gralloc versions.
37 */
38 for (int i = 0; i < handle->numFds; i++)
39 fds[i] = handle->data[i];
40
41 return handle->numFds;
42 }
43
44 static int
fallback_gralloc_get_yuv_info(struct u_gralloc * gralloc,struct u_gralloc_buffer_handle * hnd,struct u_gralloc_buffer_basic_info * out)45 fallback_gralloc_get_yuv_info(struct u_gralloc *gralloc,
46 struct u_gralloc_buffer_handle *hnd,
47 struct u_gralloc_buffer_basic_info *out)
48 {
49 struct fallback_gralloc *gr = (struct fallback_gralloc *)gralloc;
50 gralloc_module_t *gr_mod = gr->gralloc_module;
51 struct android_ycbcr ycbcr;
52 int num_fds = 0;
53 int fds[3];
54 int ret;
55
56 num_fds = get_native_buffer_fds(hnd->handle, fds);
57 if (num_fds == 0)
58 return -EINVAL;
59
60 if (!gr_mod || !gr_mod->lock_ycbcr) {
61 return -EINVAL;
62 }
63
64 memset(&ycbcr, 0, sizeof(ycbcr));
65 ret = gr_mod->lock_ycbcr(gr_mod, hnd->handle, 0, 0, 0, 0, 0, &ycbcr);
66 if (ret) {
67 /* HACK: See native_window_buffer_get_buffer_info() and
68 * https://issuetracker.google.com/32077885.*/
69 if (hnd->hal_format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)
70 return -EAGAIN;
71
72 mesa_logw("gralloc->lock_ycbcr failed: %d", ret);
73 return -EINVAL;
74 }
75 gr_mod->unlock(gr_mod, hnd->handle);
76
77 ret = bufferinfo_from_ycbcr(&ycbcr, hnd, out);
78 if (ret)
79 return ret;
80
81 /*
82 * Since this is EGL_NATIVE_BUFFER_ANDROID don't assume that
83 * the single-fd case cannot happen. So handle eithe single
84 * fd or fd-per-plane case:
85 */
86 if (num_fds == 1) {
87 out->fds[1] = out->fds[0] = fds[0];
88 if (out->num_planes == 3)
89 out->fds[2] = fds[0];
90 } else {
91 assert(num_fds == out->num_planes);
92 out->fds[0] = fds[0];
93 out->fds[1] = fds[1];
94 out->fds[2] = fds[2];
95 }
96
97 return 0;
98 }
99
100 static int
fallback_gralloc_get_buffer_info(struct u_gralloc * gralloc,struct u_gralloc_buffer_handle * hnd,struct u_gralloc_buffer_basic_info * out)101 fallback_gralloc_get_buffer_info(struct u_gralloc *gralloc,
102 struct u_gralloc_buffer_handle *hnd,
103 struct u_gralloc_buffer_basic_info *out)
104 {
105 int num_planes = 0;
106 int drm_fourcc = 0;
107 int stride = 0;
108 int fds[3];
109
110 if (is_hal_format_yuv(hnd->hal_format)) {
111 int ret = fallback_gralloc_get_yuv_info(gralloc, hnd, out);
112 /*
113 * HACK: https://issuetracker.google.com/32077885
114 * There is no API available to properly query the
115 * IMPLEMENTATION_DEFINED format. As a workaround we rely here on
116 * gralloc allocating either an arbitrary YCbCr 4:2:0 or RGBX_8888, with
117 * the latter being recognized by lock_ycbcr failing.
118 */
119 if (ret != -EAGAIN)
120 return ret;
121 }
122
123 /*
124 * Non-YUV formats could *also* have multiple planes, such as ancillary
125 * color compression state buffer, but the rest of the code isn't ready
126 * yet to deal with modifiers:
127 */
128 num_planes = get_native_buffer_fds(hnd->handle, fds);
129 if (num_planes == 0)
130 return -EINVAL;
131
132 assert(num_planes == 1);
133
134 drm_fourcc = get_fourcc_from_hal_format(hnd->hal_format);
135 if (drm_fourcc == -1) {
136 mesa_loge("Failed to get drm_fourcc");
137 return -EINVAL;
138 }
139
140 stride = hnd->pixel_stride * get_hal_format_bpp(hnd->hal_format);
141 if (stride == 0) {
142 mesa_loge("Failed to calcuulate stride");
143 return -EINVAL;
144 }
145
146 out->drm_fourcc = drm_fourcc;
147 out->modifier = DRM_FORMAT_MOD_INVALID;
148 out->num_planes = num_planes;
149 out->fds[0] = fds[0];
150 out->strides[0] = stride;
151
152 return 0;
153 }
154
155 static int
destroy(struct u_gralloc * gralloc)156 destroy(struct u_gralloc *gralloc)
157 {
158 struct fallback_gralloc *gr = (struct fallback_gralloc *)gralloc;
159 if (gr->gralloc_module) {
160 dlclose(gr->gralloc_module->common.dso);
161 }
162
163 FREE(gr);
164
165 return 0;
166 }
167
168 struct u_gralloc *
u_gralloc_fallback_create()169 u_gralloc_fallback_create()
170 {
171 struct fallback_gralloc *gr = CALLOC_STRUCT(fallback_gralloc);
172 int err = 0;
173
174 err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
175 (const hw_module_t **)&gr->gralloc_module);
176
177 if (err) {
178 mesa_logw(
179 "No gralloc hwmodule detected (video buffers won't be supported)");
180 } else if (!gr->gralloc_module->lock_ycbcr) {
181 mesa_logw("Gralloc doesn't support lock_ycbcr (video buffers won't be "
182 "supported)");
183 }
184
185 gr->base.ops.get_buffer_basic_info = fallback_gralloc_get_buffer_info;
186 gr->base.ops.destroy = destroy;
187
188 mesa_logi("Using fallback gralloc implementation");
189
190 return &gr->base;
191 }
192