• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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