1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (c) 2021 Huawei Device Co., Ltd. *
5 *
6 * Based on platform_android, which has
7 *
8 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
9 * Copyright (C) 2010-2011 LunarG Inc.
10 *
11 * Based on platform_x11, which has
12 *
13 * Copyright © 2011 Intel Corporation
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included
23 * in all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
32 */
33
34 #include <errno.h>
35 #include <dirent.h>
36 #include <dlfcn.h>
37 #include <fcntl.h>
38 #include <xf86drm.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 //#include <sync/sync.h>
42 #include <sys/types.h>
43 #include <drm-uapi/drm_fourcc.h>
44
45 #include "util/compiler.h"
46 #include "util/os_file.h"
47
48 #include "loader.h"
49 #include "egl_dri2.h"
50 #include "platform_ohos.h"
51 #include "libsync.h"
52 #ifdef HAVE_DRM_GRALLOC
53 #include <gralloc_drm_handle.h>
54 #include "gralloc_drm.h"
55 #endif /* HAVE_DRM_GRALLOC */
56
57 #define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1))
58
59 static int
get_format_bpp(int native)60 get_format_bpp(int native)
61 {
62 int bpp;
63
64 switch (native) {
65 case PIXEL_FMT_RGBA_8888:
66 case PIXEL_FMT_RGBX_8888:
67 case PIXEL_FMT_BGRA_8888:
68 bpp = 4;
69 break;
70 case PIXEL_FMT_RGB_565:
71 bpp = 2;
72 break;
73 default:
74 bpp = 0;
75 break;
76 }
77
78 return bpp;
79 }
80
81 /* returns # of fds, and by reference the actual fds */
82 static unsigned
get_native_buffer_fds(struct ANativeWindowBuffer * buf,int fds[3])83 get_native_buffer_fds(struct ANativeWindowBuffer *buf, int fds[3])
84 {
85 BufferHandle* handle = GetBufferHandleFromNative(buf);
86 if (handle == NULL) {
87 return 0;
88 }
89
90 fds[0] = handle->fd;
91 return 1;
92 }
93
94 /* createImageFromFds requires fourcc format */
get_fourcc(int native)95 static int get_fourcc(int native)
96 {
97 switch (native) {
98 case PIXEL_FMT_RGB_565: return DRM_FORMAT_RGB565;
99 case PIXEL_FMT_BGRA_8888: return DRM_FORMAT_ARGB8888;
100 case PIXEL_FMT_RGBA_8888: return DRM_FORMAT_ABGR8888;
101 case PIXEL_FMT_RGBX_8888: return DRM_FORMAT_XBGR8888;
102 default:
103 _eglLog(_EGL_WARNING, "unsupported native buffer format 0x%x", native);
104 }
105 return -1;
106 }
107
108 static int
native_window_buffer_get_buffer_info(struct dri2_egl_display * dri2_dpy,struct ANativeWindowBuffer * buf,struct buffer_info * out_buf_info)109 native_window_buffer_get_buffer_info(struct dri2_egl_display *dri2_dpy,
110 struct ANativeWindowBuffer *buf,
111 struct buffer_info *out_buf_info)
112 {
113 int num_planes = 0;
114 int drm_fourcc = 0;
115 int pitch = 0;
116 int fds[3];
117 /*
118 * Non-YUV formats could *also* have multiple planes, such as ancillary
119 * color compression state buffer, but the rest of the code isn't ready
120 * yet to deal with modifiers:
121 */
122 num_planes = get_native_buffer_fds(buf, fds);
123 if (num_planes == 0)
124 return -EINVAL;
125
126 assert(num_planes == 1);
127 BufferHandle* bufferHandle;
128 bufferHandle = GetBufferHandleFromNative(buf);
129 drm_fourcc = get_fourcc(bufferHandle->format);
130 if (drm_fourcc == -1) {
131 _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
132 return -EINVAL;
133 }
134 pitch = bufferHandle->stride;
135 if (pitch == 0) {
136 _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
137 return -EINVAL;
138 }
139
140 *out_buf_info = (struct buffer_info){
141 .width = bufferHandle->width,
142 .height = bufferHandle->height,
143 .drm_fourcc = drm_fourcc,
144 .num_planes = num_planes,
145 .fds = { fds[0], -1, -1, -1 },
146 .modifier = DRM_FORMAT_MOD_INVALID,
147 .offsets = { 0, 0, 0, 0 },
148 .pitches = { pitch, 0, 0, 0 },
149 .yuv_color_space = EGL_ITU_REC601_EXT,
150 .sample_range = EGL_YUV_NARROW_RANGE_EXT,
151 .horizontal_siting = EGL_YUV_CHROMA_SITING_0_EXT,
152 .vertical_siting = EGL_YUV_CHROMA_SITING_0_EXT,
153 };
154
155 return 0;
156 }
157
158
159 static __DRIimage *
ohos_create_image_from_buffer_info(struct dri2_egl_display * dri2_dpy,struct buffer_info * buf_info,void * priv)160 ohos_create_image_from_buffer_info(struct dri2_egl_display *dri2_dpy,
161 struct buffer_info *buf_info,
162 void *priv)
163 {
164 unsigned error;
165
166 if (dri2_dpy->image->base.version >= 15 &&
167 dri2_dpy->image->createImageFromDmaBufs2 != NULL) {
168 return dri2_dpy->image->createImageFromDmaBufs2(
169 dri2_dpy->dri_screen, buf_info->width, buf_info->height,
170 buf_info->drm_fourcc, buf_info->modifier, buf_info->fds,
171 buf_info->num_planes, buf_info->pitches, buf_info->offsets,
172 buf_info->yuv_color_space, buf_info->sample_range,
173 buf_info->horizontal_siting, buf_info->vertical_siting, &error,
174 priv);
175 }
176
177 return dri2_dpy->image->createImageFromDmaBufs(
178 dri2_dpy->dri_screen, buf_info->width, buf_info->height,
179 buf_info->drm_fourcc, buf_info->fds, buf_info->num_planes,
180 buf_info->pitches, buf_info->offsets, buf_info->yuv_color_space,
181 buf_info->sample_range, buf_info->horizontal_siting,
182 buf_info->vertical_siting, &error, priv);
183 }
184
185 static __DRIimage *
ohos_create_image_from_native_buffer(_EGLDisplay * disp,struct ANativeWindowBuffer * buf,void * priv)186 ohos_create_image_from_native_buffer(_EGLDisplay *disp,
187 struct ANativeWindowBuffer *buf,
188 void *priv)
189 {
190 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
191 struct buffer_info buf_info;
192 __DRIimage *img = NULL;
193
194 /* If dri driver is gallium virgl, real modifier info queried back from
195 * CrOS info (and potentially mapper metadata if integrated later) cannot
196 * get resolved and the buffer import will fail. Thus the fallback behavior
197 * is preserved down to native_window_buffer_get_buffer_info() so that the
198 * buffer can be imported without modifier info as a last resort.
199 */
200
201 if (!native_window_buffer_get_buffer_info(dri2_dpy, buf, &buf_info)) {
202 img = ohos_create_image_from_buffer_info(dri2_dpy, &buf_info, priv);
203 }
204
205 return img;
206 }
207
208 static EGLBoolean
ohos_window_dequeue_buffer(struct dri2_egl_surface * dri2_surf)209 ohos_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf)
210 {
211 int fence_fd;
212
213 if (ANativeWindow_dequeueBuffer(dri2_surf->window, &dri2_surf->buffer,
214 &fence_fd))
215 return EGL_FALSE;
216
217 /* If access to the buffer is controlled by a sync fence, then block on the
218 * fence.
219 *
220 * It may be more performant to postpone blocking until there is an
221 * immediate need to write to the buffer. But doing so would require adding
222 * hooks to the DRI2 loader.
223 *
224 * From the ANativeWindow_dequeueBuffer documentation:
225 *
226 * The libsync fence file descriptor returned in the int pointed to by
227 * the fenceFd argument will refer to the fence that must signal
228 * before the dequeued buffer may be written to. A value of -1
229 * indicates that the caller may access the buffer immediately without
230 * waiting on a fence. If a valid file descriptor is returned (i.e.
231 * any value except -1) then the caller is responsible for closing the
232 * file descriptor.
233 */
234 if (fence_fd >= 0) {
235 /* From the SYNC_IOC_WAIT documentation in <linux/sync.h>:
236 *
237 * Waits indefinitely if timeout < 0.
238 */
239 int timeout = -1;
240 sync_wait(fence_fd, timeout);
241 close(fence_fd);
242 }
243 /* Record all the buffers created by ANativeWindow and update back buffer
244 * for updating buffer's age in swap_buffers.
245 */
246 EGLBoolean updated = EGL_FALSE;
247 for (int i = 0; i < dri2_surf->color_buffers_count; i++) {
248 if (!dri2_surf->color_buffers[i].buffer) {
249 dri2_surf->color_buffers[i].buffer = dri2_surf->buffer;
250 }
251 if (dri2_surf->color_buffers[i].buffer == dri2_surf->buffer) {
252 dri2_surf->back = &dri2_surf->color_buffers[i];
253 updated = EGL_TRUE;
254 break;
255 }
256 }
257
258 if (!updated) {
259 /* In case of all the buffers were recreated by ANativeWindow, reset
260 * the color_buffers
261 */
262 for (int i = 0; i < dri2_surf->color_buffers_count; i++) {
263 dri2_surf->color_buffers[i].buffer = NULL;
264 dri2_surf->color_buffers[i].age = 0;
265 }
266 dri2_surf->color_buffers[0].buffer = dri2_surf->buffer;
267 dri2_surf->back = &dri2_surf->color_buffers[0];
268 }
269
270 return EGL_TRUE;
271 }
272
273 static EGLBoolean
ohos_window_enqueue_buffer(_EGLDisplay * disp,struct dri2_egl_surface * dri2_surf)274 ohos_window_enqueue_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_surf)
275 {
276 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
277
278 /* To avoid blocking other EGL calls, release the display mutex before
279 * we enter ohos_window_enqueue_buffer() and re-acquire the mutex upon
280 * return.
281 */
282 mtx_unlock(&disp->Mutex);
283
284 /* Queue the buffer with stored out fence fd. The ANativeWindow or buffer
285 * consumer may choose to wait for the fence to signal before accessing
286 * it. If fence fd value is -1, buffer can be accessed by consumer
287 * immediately. Consumer or application shouldn't rely on timestamp
288 * associated with fence if the fence fd is -1.
289 *
290 * Ownership of fd is transferred to consumer after queueBuffer and the
291 * consumer is responsible for closing it. Caller must not use the fd
292 * after passing it to queueBuffer.
293 */
294 int fence_fd = dri2_surf->out_fence_fd;
295 dri2_surf->out_fence_fd = -1;
296 ANativeWindow_queueBuffer(dri2_surf->window, dri2_surf->buffer, fence_fd);
297
298 dri2_surf->buffer = NULL;
299 dri2_surf->back = NULL;
300
301 mtx_lock(&disp->Mutex);
302
303 if (dri2_surf->dri_image_back) {
304 dri2_dpy->image->destroyImage(dri2_surf->dri_image_back);
305 dri2_surf->dri_image_back = NULL;
306 }
307
308 return EGL_TRUE;
309 }
310
311 static void
ohos_window_cancel_buffer(struct dri2_egl_surface * dri2_surf)312 ohos_window_cancel_buffer(struct dri2_egl_surface *dri2_surf)
313 {
314 int ret;
315 int fence_fd = dri2_surf->out_fence_fd;
316
317 dri2_surf->out_fence_fd = -1;
318 ret = ANativeWindow_cancelBuffer(dri2_surf->window, dri2_surf->buffer,
319 fence_fd);
320 dri2_surf->buffer = NULL;
321 if (ret < 0) {
322 _eglLog(_EGL_WARNING, "ANativeWindow_cancelBuffer failed");
323 dri2_surf->base.Lost = EGL_TRUE;
324 }
325 }
326
327 static _EGLSurface *
ohos_create_surface(_EGLDisplay * disp,EGLint type,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)328 ohos_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
329 void *native_window, const EGLint *attrib_list)
330 {
331 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
332 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
333 struct dri2_egl_surface *dri2_surf;
334 struct ANativeWindow *window = native_window;
335 const __DRIconfig *config;
336
337 dri2_surf = calloc(1, sizeof *dri2_surf);
338 if (!dri2_surf) {
339 _eglError(EGL_BAD_ALLOC, "ohos_create_surface");
340 return NULL;
341 }
342
343 if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list,
344 true, native_window))
345 goto cleanup_surface;
346
347 if (type == EGL_WINDOW_BIT) {
348 int format;
349 int buffer_count;
350
351 format = ANativeWindow_getFormat(window);
352 if (format < 0) {
353 _eglError(EGL_BAD_NATIVE_WINDOW, "ohos_create_surface");
354 goto cleanup_surface;
355 }
356
357
358 /* Required buffer caching slots. */
359 buffer_count = 3; // default use 3 buffer
360
361 dri2_surf->color_buffers = calloc(buffer_count,
362 sizeof(*dri2_surf->color_buffers));
363 if (!dri2_surf->color_buffers) {
364 _eglError(EGL_BAD_ALLOC, "ohos_create_surface");
365 goto cleanup_surface;
366 }
367 dri2_surf->color_buffers_count = buffer_count;
368
369 if (format != dri2_conf->base.NativeVisualID) {
370 _eglLog(_EGL_WARNING, "Native format mismatch: 0x%x != 0x%x",
371 format, dri2_conf->base.NativeVisualID);
372 }
373
374 NativeWindowHandleOpt(window, GET_BUFFER_GEOMETRY, &dri2_surf->base.Height, &dri2_surf->base.Width);
375 }
376
377 config = dri2_get_dri_config(dri2_conf, type,
378 dri2_surf->base.GLColorspace);
379 if (!config) {
380 _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
381 goto cleanup_surface;
382 }
383
384 if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
385 goto cleanup_surface;
386
387 if (window) {
388 ANativeWindow_acquire(window);
389 dri2_surf->window = window;
390 }
391
392 return &dri2_surf->base;
393
394 cleanup_surface:
395 if (dri2_surf->color_buffers_count)
396 free(dri2_surf->color_buffers);
397 free(dri2_surf);
398
399 return NULL;
400 }
401
402 static _EGLSurface *
ohos_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)403 ohos_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
404 void *native_window, const EGLint *attrib_list)
405 {
406 return ohos_create_surface(disp, EGL_WINDOW_BIT, conf,
407 native_window, attrib_list);
408 }
409
410 static _EGLSurface *
ohos_create_pbuffer_surface(_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)411 ohos_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
412 const EGLint *attrib_list)
413 {
414 return ohos_create_surface(disp, EGL_PBUFFER_BIT, conf,
415 NULL, attrib_list);
416 }
417
418 static EGLBoolean
ohos_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)419 ohos_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
420 {
421 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
422 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
423
424 dri2_egl_surface_free_local_buffers(dri2_surf);
425
426 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
427 if (dri2_surf->buffer)
428 ohos_window_cancel_buffer(dri2_surf);
429
430 ANativeWindow_release(dri2_surf->window);
431 }
432
433 if (dri2_surf->dri_image_back) {
434 _eglLog(_EGL_DEBUG, "%s : %d : destroy dri_image_back", __func__, __LINE__);
435 dri2_dpy->image->destroyImage(dri2_surf->dri_image_back);
436 dri2_surf->dri_image_back = NULL;
437 }
438
439 if (dri2_surf->dri_image_front) {
440 _eglLog(_EGL_DEBUG, "%s : %d : destroy dri_image_front", __func__, __LINE__);
441 dri2_dpy->image->destroyImage(dri2_surf->dri_image_front);
442 dri2_surf->dri_image_front = NULL;
443 }
444
445 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
446
447 dri2_fini_surface(surf);
448 free(dri2_surf->color_buffers);
449 free(dri2_surf);
450
451 return EGL_TRUE;
452 }
453
454 static int
update_buffers(struct dri2_egl_surface * dri2_surf)455 update_buffers(struct dri2_egl_surface *dri2_surf)
456 {
457 if (dri2_surf->base.Lost)
458 return -1;
459
460 if (dri2_surf->base.Type != EGL_WINDOW_BIT)
461 return 0;
462
463 /* try to dequeue the next back buffer */
464 if (!dri2_surf->buffer && !ohos_window_dequeue_buffer(dri2_surf)) {
465 _eglLog(_EGL_WARNING, "Could not dequeue buffer from native window");
466 dri2_surf->base.Lost = EGL_TRUE;
467 return -1;
468 }
469 BufferHandle* handle = GetBufferHandleFromNative(dri2_surf->buffer);
470 /* free outdated buffers and update the surface size */
471 if (dri2_surf->base.Width != handle->width ||
472 dri2_surf->base.Height != handle->height) {
473 dri2_egl_surface_free_local_buffers(dri2_surf);
474 dri2_surf->base.Width = handle->width;
475 dri2_surf->base.Height = handle->height;
476 }
477
478 return 0;
479 }
480
481 static int
get_front_bo(struct dri2_egl_surface * dri2_surf,unsigned int format)482 get_front_bo(struct dri2_egl_surface *dri2_surf, unsigned int format)
483 {
484 struct dri2_egl_display *dri2_dpy =
485 dri2_egl_display(dri2_surf->base.Resource.Display);
486
487 if (dri2_surf->dri_image_front)
488 return 0;
489
490 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
491 /* According current EGL spec, front buffer rendering
492 * for window surface is not supported now.
493 * and mesa doesn't have the implementation of this case.
494 * Add warning message, but not treat it as error.
495 */
496 _eglLog(_EGL_DEBUG, "DRI driver requested unsupported front buffer for window surface");
497 } else if (dri2_surf->base.Type == EGL_PBUFFER_BIT) {
498 dri2_surf->dri_image_front =
499 dri2_dpy->image->createImage(dri2_dpy->dri_screen,
500 dri2_surf->base.Width,
501 dri2_surf->base.Height,
502 format,
503 0,
504 NULL);
505 if (!dri2_surf->dri_image_front) {
506 _eglLog(_EGL_WARNING, "dri2_image_front allocation failed");
507 return -1;
508 }
509 }
510
511 return 0;
512 }
513
514 static int
get_back_bo(struct dri2_egl_surface * dri2_surf)515 get_back_bo(struct dri2_egl_surface *dri2_surf)
516 {
517 _EGLDisplay *disp = dri2_surf->base.Resource.Display;
518
519 if (dri2_surf->dri_image_back)
520 return 0;
521
522 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
523 if (!dri2_surf->buffer) {
524 _eglLog(_EGL_WARNING, "Could not get native buffer");
525 return -1;
526 }
527
528 dri2_surf->dri_image_back =
529 ohos_create_image_from_native_buffer(disp, dri2_surf->buffer, NULL);
530 if (!dri2_surf->dri_image_back) {
531 _eglLog(_EGL_WARNING, "failed to create DRI image from FD");
532 return -1;
533 }
534 } else if (dri2_surf->base.Type == EGL_PBUFFER_BIT) {
535 /* The EGL 1.5 spec states that pbuffers are single-buffered. Specifically,
536 * the spec states that they have a back buffer but no front buffer, in
537 * contrast to pixmaps, which have a front buffer but no back buffer.
538 *
539 * Single-buffered surfaces with no front buffer confuse Mesa; so we deviate
540 * from the spec, following the precedent of Mesa's EGL X11 platform. The
541 * X11 platform correctly assigns pbuffers to single-buffered configs, but
542 * assigns the pbuffer a front buffer instead of a back buffer.
543 *
544 * Pbuffers in the X11 platform mostly work today, so let's just copy its
545 * behavior instead of trying to fix (and hence potentially breaking) the
546 * world.
547 */
548 _eglLog(_EGL_DEBUG, "DRI driver requested unsupported back buffer for pbuffer surface");
549 }
550
551 return 0;
552 }
553
554 /* Some drivers will pass multiple bits in buffer_mask.
555 * For such case, will go through all the bits, and
556 * will not return error when unsupported buffer is requested, only
557 * return error when the allocation for supported buffer failed.
558 */
559 static int
ohos_image_get_buffers(__DRIdrawable * driDrawable,unsigned int format,uint32_t * stamp,void * loaderPrivate,uint32_t buffer_mask,struct __DRIimageList * images)560 ohos_image_get_buffers(__DRIdrawable *driDrawable,
561 unsigned int format,
562 uint32_t *stamp,
563 void *loaderPrivate,
564 uint32_t buffer_mask,
565 struct __DRIimageList *images)
566 {
567 struct dri2_egl_surface *dri2_surf = loaderPrivate;
568
569 images->image_mask = 0;
570 images->front = NULL;
571 images->back = NULL;
572
573 if (update_buffers(dri2_surf) < 0)
574 return 0;
575
576 if (_eglSurfaceInSharedBufferMode(&dri2_surf->base)) {
577 if (get_back_bo(dri2_surf) < 0)
578 return 0;
579
580 /* We have dri_image_back because this is a window surface and
581 * get_back_bo() succeeded.
582 */
583 assert(dri2_surf->dri_image_back);
584 images->back = dri2_surf->dri_image_back;
585 images->image_mask |= __DRI_IMAGE_BUFFER_SHARED;
586
587 /* There exists no accompanying back nor front buffer. */
588 return 1;
589 }
590
591 if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
592 if (get_front_bo(dri2_surf, format) < 0)
593 return 0;
594
595 if (dri2_surf->dri_image_front) {
596 images->front = dri2_surf->dri_image_front;
597 images->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
598 }
599 }
600
601 if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
602 if (get_back_bo(dri2_surf) < 0)
603 return 0;
604
605 if (dri2_surf->dri_image_back) {
606 images->back = dri2_surf->dri_image_back;
607 images->image_mask |= __DRI_IMAGE_BUFFER_BACK;
608 }
609 }
610
611 return 1;
612 }
613
614 static EGLint
ohos_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surface)615 ohos_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
616 {
617 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
618
619 if (update_buffers(dri2_surf) < 0) {
620 _eglError(EGL_BAD_ALLOC, "ohos_query_buffer_age");
621 return -1;
622 }
623
624 return dri2_surf->back ? dri2_surf->back->age : 0;
625 }
626
627 static EGLBoolean
ohos_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)628 ohos_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
629 {
630 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
631 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
632 const bool has_mutable_rb = _eglSurfaceHasMutableRenderBuffer(draw);
633
634 /* From the EGL_KHR_mutable_render_buffer spec (v12):
635 *
636 * If surface is a single-buffered window, pixmap, or pbuffer surface
637 * for which there is no pending change to the EGL_RENDER_BUFFER
638 * attribute, eglSwapBuffers has no effect.
639 */
640 if (has_mutable_rb &&
641 draw->RequestedRenderBuffer == EGL_SINGLE_BUFFER &&
642 draw->ActiveRenderBuffer == EGL_SINGLE_BUFFER) {
643 _eglLog(_EGL_DEBUG, "%s: remain in shared buffer mode", __func__);
644 return EGL_TRUE;
645 }
646
647 for (int i = 0; i < dri2_surf->color_buffers_count; i++) {
648 if (dri2_surf->color_buffers[i].age > 0)
649 dri2_surf->color_buffers[i].age++;
650 }
651
652 /* "XXX: we don't use get_back_bo() since it causes regressions in
653 * several dEQP tests.
654 */
655 if (dri2_surf->back)
656 dri2_surf->back->age = 1;
657
658 dri2_flush_drawable_for_swapbuffers(disp, draw);
659
660 /* dri2_surf->buffer can be null even when no error has occured. For
661 * example, if the user has called no GL rendering commands since the
662 * previous eglSwapBuffers, then the driver may have not triggered
663 * a callback to ANativeWindow_dequeueBuffer, in which case
664 * dri2_surf->buffer remains null.
665 */
666 if (dri2_surf->buffer)
667 ohos_window_enqueue_buffer(disp, dri2_surf);
668
669 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
670
671 return EGL_TRUE;
672 }
673
674 static EGLBoolean
ohos_query_surface(_EGLDisplay * disp,_EGLSurface * surf,EGLint attribute,EGLint * value)675 ohos_query_surface(_EGLDisplay *disp, _EGLSurface *surf,
676 EGLint attribute, EGLint *value)
677 {
678 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
679 EGLint dummy;
680 switch (attribute) {
681 case EGL_WIDTH:
682 if (dri2_surf->base.Type == EGL_WINDOW_BIT && dri2_surf->window) {
683 NativeWindowHandleOpt(dri2_surf->window,
684 GET_BUFFER_GEOMETRY, &dummy, value);
685 return EGL_TRUE;
686 }
687 break;
688 case EGL_HEIGHT:
689 if (dri2_surf->base.Type == EGL_WINDOW_BIT && dri2_surf->window) {
690 NativeWindowHandleOpt(dri2_surf->window,
691 GET_BUFFER_GEOMETRY, value, &dummy);
692 return EGL_TRUE;
693 }
694 break;
695 default:
696 break;
697 }
698 return _eglQuerySurface(disp, surf, attribute, value);
699 }
700
701 static _EGLImage *
dri2_create_image_ohos_native_buffer(_EGLDisplay * disp,_EGLContext * ctx,struct ANativeWindowBuffer * buf)702 dri2_create_image_ohos_native_buffer(_EGLDisplay *disp,
703 _EGLContext *ctx,
704 struct ANativeWindowBuffer *buf)
705 {
706 if (ctx != NULL) {
707 /* From the EGL_OHOS_image_native_buffer spec:
708 *
709 * * If <target> is EGL_NATIVE_BUFFER_OHOS and <ctx> is not
710 * EGL_NO_CONTEXT, the error EGL_BAD_CONTEXT is generated.
711 */
712 _eglError(EGL_BAD_CONTEXT, "eglCreateEGLImageKHR: for "
713 "EGL_NATIVE_BUFFER_OHOS, the context must be "
714 "EGL_NO_CONTEXT");
715 return NULL;
716 }
717 __DRIimage *dri_image =
718 ohos_create_image_from_native_buffer(disp, buf, buf);
719
720 if (dri_image) {
721 return dri2_create_image_from_dri(disp, dri_image);
722 }
723
724 return NULL;
725 }
726
727 static _EGLImage *
ohos_create_image_khr(_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)728 ohos_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
729 EGLClientBuffer buffer, const EGLint *attr_list)
730 {
731 switch (target) {
732 case EGL_NATIVE_BUFFER_OHOS:
733 return dri2_create_image_ohos_native_buffer(disp, ctx,
734 (struct ANativeWindowBuffer *) buffer);
735 default:
736 return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
737 }
738 }
739
740 static void
ohos_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)741 ohos_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
742 {
743 }
744
745 #ifdef HAVE_DRM_GRALLOC
746 static int
ohos_get_buffers_parse_attachments(struct dri2_egl_surface * dri2_surf,unsigned int * attachments,int count)747 ohos_get_buffers_parse_attachments(struct dri2_egl_surface *dri2_surf,
748 unsigned int *attachments, int count)
749 {
750 int num_buffers = 0;
751
752 /* fill dri2_surf->buffers */
753 for (int i = 0; i < count * 2; i += 2) {
754 __DRIbuffer *buf, *local;
755
756 assert(num_buffers < ARRAY_SIZE(dri2_surf->buffers));
757 buf = &dri2_surf->buffers[num_buffers];
758
759 switch (attachments[i]) {
760 case __DRI_BUFFER_BACK_LEFT:
761 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
762 buf->attachment = attachments[i];
763 buf->name = get_native_buffer_name(dri2_surf->buffer);
764 buf->cpp = get_format_bpp(dri2_surf->buffer->format);
765 buf->pitch = dri2_surf->buffer->stride * buf->cpp;
766 buf->flags = 0;
767
768 if (buf->name)
769 num_buffers++;
770
771 break;
772 }
773 FALLTHROUGH; /* for pbuffers */
774 case __DRI_BUFFER_DEPTH:
775 case __DRI_BUFFER_STENCIL:
776 case __DRI_BUFFER_ACCUM:
777 case __DRI_BUFFER_DEPTH_STENCIL:
778 case __DRI_BUFFER_HIZ:
779 local = dri2_egl_surface_alloc_local_buffer(dri2_surf,
780 attachments[i], attachments[i + 1]);
781
782 if (local) {
783 *buf = *local;
784 num_buffers++;
785 }
786 break;
787 case __DRI_BUFFER_FRONT_LEFT:
788 case __DRI_BUFFER_FRONT_RIGHT:
789 case __DRI_BUFFER_FAKE_FRONT_LEFT:
790 case __DRI_BUFFER_FAKE_FRONT_RIGHT:
791 case __DRI_BUFFER_BACK_RIGHT:
792 default:
793 /* no front or right buffers */
794 break;
795 }
796 }
797
798 return num_buffers;
799 }
800
801 static __DRIbuffer *
ohos_get_buffers_with_format(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)802 ohos_get_buffers_with_format(__DRIdrawable * driDrawable,
803 int *width, int *height,
804 unsigned int *attachments, int count,
805 int *out_count, void *loaderPrivate)
806 {
807 struct dri2_egl_surface *dri2_surf = loaderPrivate;
808
809 if (update_buffers(dri2_surf) < 0)
810 return NULL;
811
812 *out_count = ohos_get_buffers_parse_attachments(dri2_surf, attachments, count);
813
814 if (width)
815 *width = dri2_surf->base.Width;
816 if (height)
817 *height = dri2_surf->base.Height;
818
819 return dri2_surf->buffers;
820 }
821 #endif /* HAVE_DRM_GRALLOC */
822
823 static unsigned
ohos_get_capability(void * loaderPrivate,enum dri_loader_cap cap)824 ohos_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
825 {
826 /* Note: loaderPrivate is _EGLDisplay* */
827 switch (cap) {
828 case DRI_LOADER_CAP_RGBA_ORDERING:
829 return 1;
830 default:
831 return 0;
832 }
833 }
834
835 static void
ohos_destroy_loader_image_state(void * loaderPrivate)836 ohos_destroy_loader_image_state(void *loaderPrivate)
837 {
838 }
839
840 static EGLBoolean
ohos_add_configs_for_visuals(_EGLDisplay * disp)841 ohos_add_configs_for_visuals(_EGLDisplay *disp)
842 {
843 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
844 static const struct {
845 int format;
846 int rgba_shifts[4];
847 unsigned int rgba_sizes[4];
848 } visuals[] = {
849 { PIXEL_FMT_RGBA_8888, { 0, 8, 16, 24 }, { 8, 8, 8, 8 } },
850 { PIXEL_FMT_RGBX_8888, { 0, 8, 16, -1 }, { 8, 8, 8, 0 } },
851 { PIXEL_FMT_RGB_565, { 11, 5, 0, -1 }, { 5, 6, 5, 0 } },
852 /* This must be after PIXEL_FMT_RGBA_8888, we only keep BGRA
853 * visual if it turns out RGBA visual is not available.
854 */
855 { PIXEL_FMT_BGRA_8888, { 16, 8, 0, 24 }, { 8, 8, 8, 8 } },
856 };
857
858 unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 };
859 int config_count = 0;
860
861 bool has_rgba = false;
862 for (int i = 0; i < ARRAY_SIZE(visuals); i++) {
863 if (visuals[i].format == PIXEL_FMT_BGRA_8888 && has_rgba)
864 continue;
865 for (int j = 0; dri2_dpy->driver_configs[j]; j++) {
866 const EGLint surface_type = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
867
868 const EGLint config_attrs[] = {
869 EGL_NATIVE_VISUAL_ID, visuals[i].format,
870 EGL_NATIVE_VISUAL_TYPE, visuals[i].format,
871 EGL_NONE
872 };
873
874 struct dri2_egl_config *dri2_conf =
875 dri2_add_config(disp, dri2_dpy->driver_configs[j],
876 config_count + 1, surface_type, config_attrs,
877 visuals[i].rgba_shifts, visuals[i].rgba_sizes);
878 if (dri2_conf) {
879 if (dri2_conf->base.ConfigID == config_count + 1)
880 config_count++;
881 format_count[i]++;
882 }
883 }
884 if (visuals[i].format == PIXEL_FMT_RGBA_8888 && format_count[i])
885 has_rgba = true;
886 }
887
888 for (int i = 0; i < ARRAY_SIZE(format_count); i++) {
889 if (!format_count[i]) {
890 _eglLog(_EGL_DEBUG, "No DRI config supports native format 0x%x",
891 visuals[i].format);
892 }
893 }
894
895 return (config_count != 0);
896 }
897
898 static const struct dri2_egl_display_vtbl ohos_display_vtbl = {
899 .authenticate = NULL,
900 .create_window_surface = ohos_create_window_surface,
901 .create_pbuffer_surface = ohos_create_pbuffer_surface,
902 .destroy_surface = ohos_destroy_surface,
903 .create_image = ohos_create_image_khr,
904 .swap_buffers = ohos_swap_buffers,
905 .swap_interval = NULL,
906 .query_buffer_age = ohos_query_buffer_age,
907 .query_surface = ohos_query_surface,
908 .get_dri_drawable = dri2_surface_get_dri_drawable,
909 };
910
911 static const __DRIimageLoaderExtension ohos_image_loader_extension = {
912 .base = { __DRI_IMAGE_LOADER, 4 },
913
914 .getBuffers = ohos_image_get_buffers,
915 .flushFrontBuffer = ohos_flush_front_buffer,
916 .getCapability = ohos_get_capability,
917 .flushSwapBuffers = NULL,
918 .destroyLoaderImageState = ohos_destroy_loader_image_state,
919 };
920
921 static void
ohos_display_shared_buffer(__DRIdrawable * driDrawable,int fence_fd,void * loaderPrivate)922 ohos_display_shared_buffer(__DRIdrawable *driDrawable, int fence_fd,
923 void *loaderPrivate)
924 {
925 struct dri2_egl_surface *dri2_surf = loaderPrivate;
926 struct ANativeWindowBuffer *old_buffer UNUSED = dri2_surf->buffer;
927
928 if (!_eglSurfaceInSharedBufferMode(&dri2_surf->base)) {
929 _eglLog(_EGL_WARNING, "%s: internal error: buffer is not shared",
930 __func__);
931 return;
932 }
933
934 if (fence_fd >= 0) {
935 /* The driver's fence is more recent than the surface's out fence, if it
936 * exists at all. So use the driver's fence.
937 */
938 if (dri2_surf->out_fence_fd >= 0) {
939 close(dri2_surf->out_fence_fd);
940 dri2_surf->out_fence_fd = -1;
941 }
942 } else if (dri2_surf->out_fence_fd >= 0) {
943 fence_fd = dri2_surf->out_fence_fd;
944 dri2_surf->out_fence_fd = -1;
945 }
946
947 if (ANativeWindow_queueBuffer(dri2_surf->window, dri2_surf->buffer,
948 fence_fd)) {
949 _eglLog(_EGL_WARNING, "%s: ANativeWindow_queueBuffer failed", __func__);
950 close(fence_fd);
951 return;
952 }
953
954 fence_fd = -1;
955
956 if (ANativeWindow_dequeueBuffer(dri2_surf->window, &dri2_surf->buffer,
957 &fence_fd)) {
958 /* Tear down the surface because it no longer has a back buffer. */
959 struct dri2_egl_display *dri2_dpy =
960 dri2_egl_display(dri2_surf->base.Resource.Display);
961
962 _eglLog(_EGL_WARNING, "%s: ANativeWindow_dequeueBuffer failed", __func__);
963
964 dri2_surf->base.Lost = true;
965 dri2_surf->buffer = NULL;
966 dri2_surf->back = NULL;
967
968 if (dri2_surf->dri_image_back) {
969 dri2_dpy->image->destroyImage(dri2_surf->dri_image_back);
970 dri2_surf->dri_image_back = NULL;
971 }
972
973 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
974 return;
975 }
976
977 if (fence_fd < 0)
978 return;
979
980 /* Access to the buffer is controlled by a sync fence. Block on it.
981 *
982 * Ideally, we would submit the fence to the driver, and the driver would
983 * postpone command execution until it signalled. But DRI lacks API for
984 * that (as of 2018-04-11).
985 *
986 * SYNC_IOC_WAIT waits forever if timeout < 0
987 */
988 sync_wait(fence_fd, -1);
989 close(fence_fd);
990 }
991
992 static const __DRImutableRenderBufferLoaderExtension ohos_mutable_render_buffer_extension = {
993 .base = { __DRI_MUTABLE_RENDER_BUFFER_LOADER, 1 },
994 .displaySharedBuffer = ohos_display_shared_buffer,
995 };
996
997 static const __DRIextension *ohos_image_loader_extensions[] = {
998 &ohos_image_loader_extension.base,
999 &image_lookup_extension.base,
1000 &use_invalidate.base,
1001 &ohos_mutable_render_buffer_extension.base,
1002 NULL,
1003 };
1004
1005 static EGLBoolean
ohos_load_driver(_EGLDisplay * disp,bool swrast)1006 ohos_load_driver(_EGLDisplay *disp, bool swrast)
1007 {
1008 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1009
1010 dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
1011 if (dri2_dpy->driver_name == NULL)
1012 return false;
1013
1014 #ifdef HAVE_DRM_GRALLOC
1015 /* Handle control nodes using __DRI_DRI2_LOADER extension and GEM names
1016 * for backwards compatibility with drm_gralloc. (Do not use on new
1017 * systems.) */
1018 dri2_dpy->loader_extensions = ohos_dri2_loader_extensions;
1019 if (!dri2_load_driver(disp)) {
1020 goto error;
1021 }
1022 #else
1023 if (swrast) {
1024 /* Use kms swrast only with vgem / virtio_gpu.
1025 * virtio-gpu fallbacks to software rendering when 3D features
1026 * are unavailable since 6c5ab.
1027 */
1028 if (strcmp(dri2_dpy->driver_name, "vgem") == 0 ||
1029 strcmp(dri2_dpy->driver_name, "virtio_gpu") == 0) {
1030 free(dri2_dpy->driver_name);
1031 dri2_dpy->driver_name = strdup("kms_swrast");
1032 } else {
1033 goto error;
1034 }
1035 }
1036
1037 dri2_dpy->loader_extensions = ohos_image_loader_extensions;
1038 if (!dri2_load_driver_dri3(disp)) {
1039 goto error;
1040 }
1041 #endif
1042
1043 return true;
1044
1045 error:
1046 free(dri2_dpy->driver_name);
1047 dri2_dpy->driver_name = NULL;
1048 return false;
1049 }
1050
1051 static void
ohos_unload_driver(_EGLDisplay * disp)1052 ohos_unload_driver(_EGLDisplay *disp)
1053 {
1054 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1055
1056 dlclose(dri2_dpy->driver);
1057 dri2_dpy->driver = NULL;
1058 free(dri2_dpy->driver_name);
1059 dri2_dpy->driver_name = NULL;
1060 }
1061
1062 static int
ohos_filter_device(_EGLDisplay * disp,int fd,const char * vendor)1063 ohos_filter_device(_EGLDisplay *disp, int fd, const char *vendor)
1064 {
1065 drmVersionPtr ver = drmGetVersion(fd);
1066 if (!ver)
1067 return -1;
1068
1069 if (strcmp(vendor, ver->name) != 0) {
1070 drmFreeVersion(ver);
1071 return -1;
1072 }
1073
1074 drmFreeVersion(ver);
1075 return 0;
1076 }
1077
1078 static EGLBoolean
ohos_probe_device(_EGLDisplay * disp,bool swrast)1079 ohos_probe_device(_EGLDisplay *disp, bool swrast)
1080 {
1081 /* Check that the device is supported, by attempting to:
1082 * - load the dri module
1083 * - and, create a screen
1084 */
1085 if (!ohos_load_driver(disp, swrast))
1086 return EGL_FALSE;
1087
1088 if (!dri2_create_screen(disp)) {
1089 _eglLog(_EGL_WARNING, "DRI2: failed to create screen");
1090 ohos_unload_driver(disp);
1091 return EGL_FALSE;
1092 }
1093 return EGL_TRUE;
1094 }
1095
1096 #ifdef HAVE_DRM_GRALLOC
1097 static EGLBoolean
ohos_open_device(_EGLDisplay * disp,bool swrast)1098 ohos_open_device(_EGLDisplay *disp, bool swrast)
1099 {
1100 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1101 int fd = -1, err = -EINVAL;
1102
1103 if (swrast)
1104 return EGL_FALSE;
1105
1106 if (dri2_dpy->gralloc->perform)
1107 err = dri2_dpy->gralloc->perform(dri2_dpy->gralloc,
1108 GRALLOC_MODULE_PERFORM_GET_DRM_FD,
1109 &fd);
1110 if (err || fd < 0) {
1111 _eglLog(_EGL_WARNING, "fail to get drm fd");
1112 return EGL_FALSE;
1113 }
1114
1115 dri2_dpy->fd = os_dupfd_cloexec(fd);
1116 if (dri2_dpy->fd < 0)
1117 return EGL_FALSE;
1118
1119 if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER)
1120 return EGL_FALSE;
1121
1122 return ohos_probe_device(disp, swrast);
1123 }
1124 #else
1125 static EGLBoolean
ohos_open_device(_EGLDisplay * disp,bool swrast)1126 ohos_open_device(_EGLDisplay *disp, bool swrast)
1127 {
1128 #define MAX_DRM_DEVICES 64
1129 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1130 drmDevicePtr device, devices[MAX_DRM_DEVICES] = { NULL };
1131 int num_devices;
1132
1133 char *vendor_name = NULL;
1134 // char vendor_buf[PROPERTY_VALUE_MAX];
1135
1136 #ifdef EGL_FORCE_RENDERNODE
1137 const unsigned node_type = DRM_NODE_RENDER;
1138 #else
1139 const unsigned node_type = swrast ? DRM_NODE_PRIMARY : DRM_NODE_RENDER;
1140 #endif
1141
1142 // if (property_get("drm.gpu.vendor_name", vendor_buf, NULL) > 0)
1143 // vendor_name = vendor_buf;
1144
1145 num_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
1146 if (num_devices < 0)
1147 return EGL_FALSE;
1148
1149 for (int i = 0; i < num_devices; i++) {
1150 device = devices[i];
1151
1152 if (!(device->available_nodes & (1 << node_type)))
1153 continue;
1154
1155 dri2_dpy->fd = loader_open_device(device->nodes[node_type]);
1156 if (dri2_dpy->fd < 0) {
1157 _eglLog(_EGL_WARNING, "%s() Failed to open DRM device %s",
1158 __func__, device->nodes[node_type]);
1159 continue;
1160 }
1161
1162 /* If a vendor is explicitly provided, we use only that.
1163 * Otherwise we fall-back the first device that is supported.
1164 */
1165 if (vendor_name) {
1166 if (ohos_filter_device(disp, dri2_dpy->fd, vendor_name)) {
1167 /* Device does not match - try next device */
1168 close(dri2_dpy->fd);
1169 dri2_dpy->fd = -1;
1170 continue;
1171 }
1172 /* If the requested device matches - use it. Regardless if
1173 * init fails, do not fall-back to any other device.
1174 */
1175 if (!ohos_probe_device(disp, false)) {
1176 close(dri2_dpy->fd);
1177 dri2_dpy->fd = -1;
1178 }
1179
1180 break;
1181 }
1182 if (ohos_probe_device(disp, swrast))
1183 break;
1184
1185 /* No explicit request - attempt the next device */
1186 close(dri2_dpy->fd);
1187 dri2_dpy->fd = -1;
1188 }
1189 drmFreeDevices(devices, num_devices);
1190
1191 if (dri2_dpy->fd < 0) {
1192 _eglLog(_EGL_WARNING, "Failed to open %s DRM device",
1193 vendor_name ? "desired": "any");
1194 return EGL_FALSE;
1195 }
1196
1197 return EGL_TRUE;
1198 #undef MAX_DRM_DEVICES
1199 }
1200
1201 #endif
1202
1203 EGLBoolean
dri2_initialize_ohos(_EGLDisplay * disp)1204 dri2_initialize_ohos(_EGLDisplay *disp)
1205 {
1206 _EGLDevice *dev;
1207 bool device_opened = false;
1208 struct dri2_egl_display *dri2_dpy;
1209 const char *err;
1210
1211 dri2_dpy = calloc(1, sizeof(*dri2_dpy));
1212 if (!dri2_dpy)
1213 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1214
1215 dri2_dpy->fd = -1;
1216
1217 disp->DriverData = (void *) dri2_dpy;
1218 device_opened = ohos_open_device(disp, disp->Options.ForceSoftware);
1219
1220 if (!device_opened) {
1221 err = "DRI2: failed to open device";
1222 goto cleanup;
1223 }
1224
1225 dev = _eglAddDevice(dri2_dpy->fd, false);
1226 if (!dev) {
1227 err = "DRI2: failed to find EGLDevice";
1228 goto cleanup;
1229 }
1230
1231 disp->Device = dev;
1232
1233 if (!dri2_setup_extensions(disp)) {
1234 err = "DRI2: failed to setup extensions";
1235 goto cleanup;
1236 }
1237
1238 dri2_setup_screen(disp);
1239
1240 dri2_setup_swap_interval(disp, 1);
1241
1242 disp->Extensions.KHR_image = EGL_TRUE;
1243
1244 /* Create configs *after* enabling extensions because presence of DRI
1245 * driver extensions can affect the capabilities of EGLConfigs.
1246 */
1247 if (!ohos_add_configs_for_visuals(disp)) {
1248 err = "DRI2: failed to add configs";
1249 goto cleanup;
1250 }
1251
1252 /* Fill vtbl last to prevent accidentally calling virtual function during
1253 * initialization.
1254 */
1255 dri2_dpy->vtbl = &ohos_display_vtbl;
1256
1257 return EGL_TRUE;
1258
1259 cleanup:
1260 dri2_display_destroy(disp);
1261 return _eglError(EGL_NOT_INITIALIZED, err);
1262 }
1263