1 /* TODO */
2
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include <vulkan/vulkan.h>
7
8 #include "dri_util.h"
9 #include "egl_dri2.h"
10 #include "kopper_interface.h"
11
12 #include "display_type.h"
13 #include "external_window.h"
14
15 static _EGLSurface *
ohos_create_surface(_EGLDisplay * disp,EGLint type,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)16 ohos_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
17 void *native_window, const EGLint *attrib_list)
18 {
19 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
20 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
21 struct dri2_egl_surface *dri2_surf;
22 struct NativeWindow *window = native_window;
23 const struct dri_config *config;
24
25 dri2_surf = calloc(1, sizeof *dri2_surf);
26 if (!dri2_surf) {
27 _eglError(EGL_BAD_ALLOC, "ohos_create_surface");
28 return NULL;
29 }
30
31 if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list,
32 false, native_window))
33 goto cleanup_surface;
34
35 if (type == EGL_WINDOW_BIT) {
36 int format = 0;
37
38 OH_NativeWindow_NativeWindowHandleOpt(native_window, GET_FORMAT, &format);
39 if (format < 0) {
40 _eglError(EGL_BAD_NATIVE_WINDOW, "ohos_create_surface");
41 goto cleanup_surface;
42 }
43
44 if (format != dri2_conf->base.NativeVisualID) {
45 _eglLog(_EGL_WARNING, "Native format mismatch: 0x%x != 0x%x", format,
46 dri2_conf->base.NativeVisualID);
47 }
48
49 OH_NativeWindow_NativeWindowHandleOpt(native_window, GET_BUFFER_GEOMETRY,
50 &dri2_surf->base.Height,
51 &dri2_surf->base.Width);
52
53 dri2_surf->window = window;
54 }
55
56 config = dri2_get_dri_config(dri2_conf, type, dri2_surf->base.GLColorspace);
57 if (!config) {
58 _eglError(EGL_BAD_MATCH,
59 "Unsupported surfacetype/colorspace configuration");
60 goto cleanup_surface;
61 }
62
63 if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
64 goto cleanup_surface;
65
66 if (window)
67 OH_NativeWindow_NativeObjectReference(window);
68
69 return &dri2_surf->base;
70
71 cleanup_surface:
72 free(dri2_surf);
73 return NULL;
74 }
75
76 static EGLBoolean
device_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)77 device_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
78 {
79 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
80
81 driDestroyDrawable(dri2_surf->dri_drawable);
82
83 if (dri2_surf->window)
84 OH_NativeWindow_NativeObjectUnreference(dri2_surf->window);
85
86 dri2_fini_surface(surf);
87 free(dri2_surf);
88 return EGL_TRUE;
89 }
90
91 static _EGLSurface *
ohos_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)92 ohos_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
93 void *native_window, const EGLint *attrib_list)
94 {
95 return ohos_create_surface(disp, EGL_WINDOW_BIT, conf, native_window,
96 attrib_list);
97 }
98
99 static _EGLSurface *
ohos_create_pbuffer_surface(_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)100 ohos_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
101 const EGLint *attrib_list)
102 {
103 return ohos_create_surface(disp, EGL_PBUFFER_BIT, conf, NULL, attrib_list);
104 }
105
106 static EGLBoolean
ohos_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)107 ohos_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
108 {
109 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
110
111 driSwapBuffers(dri2_surf->dri_drawable);
112
113 return EGL_TRUE;
114 }
115
116 static const struct dri2_egl_display_vtbl dri2_ohos_display_vtbl = {
117 .create_window_surface = ohos_create_window_surface,
118 .create_pbuffer_surface = ohos_create_pbuffer_surface,
119 .destroy_surface = device_destroy_surface,
120 .create_image = dri2_create_image_khr,
121 .get_dri_drawable = dri2_surface_get_dri_drawable,
122 .swap_buffers = ohos_swap_buffers,
123 };
124
125 static void
kopperSetSurfaceCreateInfo(void * _draw,struct kopper_loader_info * out)126 kopperSetSurfaceCreateInfo(void *_draw, struct kopper_loader_info *out)
127 {
128 struct dri2_egl_surface *dri2_surf = _draw;
129 VkSurfaceCreateInfoOHOS *sci = (VkSurfaceCreateInfoOHOS *)&out->bos;
130
131 sci->sType = VK_STRUCTURE_TYPE_SURFACE_CREATE_INFO_OHOS;
132 sci->pNext = NULL;
133 sci->flags = 0;
134 sci->window = dri2_surf->window;
135
136 out->present_opaque = dri2_surf->base.PresentOpaque;
137 /* convert to vulkan constants */
138 switch (dri2_surf->base.CompressionRate) {
139 case EGL_SURFACE_COMPRESSION_FIXED_RATE_NONE_EXT:
140 out->compression = 0;
141 break;
142 case EGL_SURFACE_COMPRESSION_FIXED_RATE_DEFAULT_EXT:
143 out->compression = UINT32_MAX;
144 break;
145 #define EGL_VK_COMP(NUM) \
146 case EGL_SURFACE_COMPRESSION_FIXED_RATE_##NUM##BPC_EXT: \
147 out->compression = VK_IMAGE_COMPRESSION_FIXED_RATE_##NUM##BPC_BIT_EXT; \
148 break
149 EGL_VK_COMP(1);
150 EGL_VK_COMP(2);
151 EGL_VK_COMP(3);
152 EGL_VK_COMP(4);
153 EGL_VK_COMP(5);
154 EGL_VK_COMP(6);
155 EGL_VK_COMP(7);
156 EGL_VK_COMP(8);
157 EGL_VK_COMP(9);
158 EGL_VK_COMP(10);
159 EGL_VK_COMP(11);
160 EGL_VK_COMP(12);
161 #undef EGL_VK_COMP
162 default:
163 unreachable("unknown compression rate");
164 }
165 }
166
167 static const __DRIkopperLoaderExtension kopper_loader_extension = {
168 .base = {__DRI_KOPPER_LOADER, 1},
169 .SetSurfaceCreateInfo = kopperSetSurfaceCreateInfo,
170 };
171
172 static void
ohos_drawable_info(struct dri_drawable * draw,int * x,int * y,int * w,int * h,void * loaderPrivate)173 ohos_drawable_info(struct dri_drawable *draw, int *x, int *y, int *w, int *h,
174 void *loaderPrivate)
175 {
176 struct dri2_egl_surface *dri2_surf = loaderPrivate;
177
178 *x = *y = 0;
179 *w = dri2_surf->base.Width;
180 *h = dri2_surf->base.Height;
181 }
182
183 static const __DRIswrastLoaderExtension swrast_loader_extension = {
184 .base = {__DRI_SWRAST_LOADER, 1},
185 .getDrawableInfo = ohos_drawable_info,
186 };
187
188 static unsigned
ohos_get_capability(void * loaderPrivate,enum dri_loader_cap cap)189 ohos_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
190 {
191 /* Note: loaderPrivate is _EGLDisplay* */
192 switch (cap) {
193 case DRI_LOADER_CAP_RGBA_ORDERING:
194 return 1;
195 default:
196 return 0;
197 }
198 }
199
200 static const __DRIdri2LoaderExtension dri2_loader_extension = {
201 .base = {__DRI_DRI2_LOADER, 4},
202 .getCapability = ohos_get_capability,
203 };
204
205 static const __DRIextension *image_loader_extensions[] = {
206 &image_lookup_extension.base,
207 &kopper_loader_extension.base,
208 &swrast_loader_extension.base,
209 &dri2_loader_extension.base,
210 NULL,
211 };
212
213 static bool
load_zink_kopper(_EGLDisplay * disp)214 load_zink_kopper(_EGLDisplay *disp)
215 {
216 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
217
218 dri2_dpy->fd_render_gpu = -1;
219 dri2_dpy->fd_display_gpu = -1;
220 dri2_dpy->driver_name = strdup("zink");
221 if (!dri2_dpy->driver_name)
222 return false;
223
224 if (!dri2_load_driver(disp)) {
225 free(dri2_dpy->driver_name);
226 dri2_dpy->driver_name = NULL;
227 return false;
228 }
229
230 dri2_dpy->loader_extensions = image_loader_extensions;
231
232 return true;
233 }
234
235 static void
ohos_add_configs_for_visuals(_EGLDisplay * disp)236 ohos_add_configs_for_visuals(_EGLDisplay *disp)
237 {
238 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
239 static const struct {
240 int hal_format;
241 enum pipe_format pipe_format;
242 } visuals[] = {
243 {PIXEL_FMT_RGBA_8888, PIPE_FORMAT_RGBA8888_UNORM},
244 {PIXEL_FMT_RGBX_8888, PIPE_FORMAT_BGRX8888_UNORM},
245 {PIXEL_FMT_RGB_565, PIPE_FORMAT_B5G6R5_UNORM},
246 /* This must be after HAL_PIXEL_FMT_RGBA_8888, we only keep BGRA
247 * visual if it turns out RGBA visual is not available.
248 */
249 {PIXEL_FMT_BGRA_8888, PIPE_FORMAT_BGRA8888_UNORM},
250 };
251
252 unsigned int format_count[ARRAY_SIZE(visuals)] = {0};
253
254 bool has_rgba = false;
255 for (int i = 0; i < ARRAY_SIZE(visuals); i++) {
256 if (visuals[i].hal_format == PIXEL_FMT_BGRA_8888 && has_rgba)
257 continue;
258 for (int j = 0; dri2_dpy->driver_configs[j]; j++) {
259 const struct gl_config *gl_config =
260 (struct gl_config *)dri2_dpy->driver_configs[j];
261
262 /* Rather than have duplicate table entries for _SRGB formats, just
263 * use the linear version of the format for the comparision:
264 */
265 enum pipe_format linear_format =
266 util_format_linear(gl_config->color_format);
267 if (linear_format != visuals[i].pipe_format)
268 continue;
269
270 const EGLint surface_type = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
271 const EGLint config_attrs[] = {
272 EGL_NATIVE_VISUAL_ID, visuals[i].hal_format, EGL_NATIVE_VISUAL_TYPE,
273 visuals[i].hal_format, EGL_NONE};
274
275 _eglLog(_EGL_DEBUG, "calling dri2_add_config for %x",
276 visuals[i].hal_format);
277 struct dri2_egl_config *dri2_conf = dri2_add_config(
278 disp, dri2_dpy->driver_configs[j], surface_type, config_attrs);
279 if (dri2_conf)
280 format_count[i]++;
281 }
282
283 if (visuals[i].hal_format == PIXEL_FMT_RGBA_8888 && format_count[i])
284 has_rgba = true;
285 }
286
287 for (int i = 0; i < ARRAY_SIZE(format_count); i++) {
288 if (!format_count[i]) {
289 _eglLog(_EGL_DEBUG, "No DRI config supports native format 0x%x",
290 visuals[i].hal_format);
291 }
292 }
293 }
294
295 EGLBoolean
dri2_initialize_ohos(_EGLDisplay * disp)296 dri2_initialize_ohos(_EGLDisplay *disp)
297 {
298 const char *err;
299 struct dri2_egl_display *dri2_dpy = dri2_display_create(disp);
300 if (!dri2_dpy)
301 return EGL_FALSE;
302
303 err = "DRI2: failed to load driver";
304 if (!load_zink_kopper(disp))
305 goto cleanup;
306
307 if (!dri2_create_screen(disp)) {
308 err = "DRI2: failed to create screen";
309 goto cleanup;
310 }
311
312 dri2_setup_screen(disp);
313
314 /* Create configs *after* enabling extensions because presence of DRI
315 * driver extensions can affect the capabilities of EGLConfigs.
316 */
317 ohos_add_configs_for_visuals(disp);
318
319 disp->Extensions.KHR_image = EGL_TRUE;
320
321 /* Fill vtbl last to prevent accidentally calling virtual function during
322 * initialization.
323 */
324 dri2_dpy->vtbl = &dri2_ohos_display_vtbl;
325
326 return EGL_TRUE;
327
328 cleanup:
329 dri2_display_destroy(disp);
330 return _eglError(EGL_NOT_INITIALIZED, err);
331 }
332