xref: /aosp_15_r20/external/mesa3d/src/egl/drivers/dri2/platform_drm.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2011 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Kristian Høgsberg <[email protected]>
26  */
27 
28 #include <dlfcn.h>
29 #include <fcntl.h>
30 #include <stdint.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <xf86drm.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 
39 #include "util/os_file.h"
40 
41 #include "main/glconfig.h"
42 
43 #include "egl_dri2.h"
44 #include "egldevice.h"
45 #include "eglglobals.h"
46 #include "loader.h"
47 #include "dri_util.h"
48 
49 static struct gbm_bo *
lock_front_buffer(struct gbm_surface * _surf)50 lock_front_buffer(struct gbm_surface *_surf)
51 {
52    struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
53    struct dri2_egl_surface *dri2_surf = surf->dri_private;
54    struct gbm_dri_device *device = gbm_dri_device(_surf->gbm);
55    struct gbm_bo *bo;
56 
57    if (dri2_surf->current == NULL) {
58       _eglError(EGL_BAD_SURFACE, "no front buffer");
59       return NULL;
60    }
61 
62    bo = dri2_surf->current->bo;
63 
64    if (!device->swrast) {
65       dri2_surf->current->locked = true;
66       dri2_surf->current = NULL;
67    }
68 
69    return bo;
70 }
71 
72 static void
release_buffer(struct gbm_surface * _surf,struct gbm_bo * bo)73 release_buffer(struct gbm_surface *_surf, struct gbm_bo *bo)
74 {
75    struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
76    struct dri2_egl_surface *dri2_surf = surf->dri_private;
77 
78    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
79       if (dri2_surf->color_buffers[i].bo == bo) {
80          dri2_surf->color_buffers[i].locked = false;
81          break;
82       }
83    }
84 }
85 
86 static int
has_free_buffers(struct gbm_surface * _surf)87 has_free_buffers(struct gbm_surface *_surf)
88 {
89    struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
90    struct dri2_egl_surface *dri2_surf = surf->dri_private;
91 
92    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
93       if (!dri2_surf->color_buffers[i].locked)
94          return 1;
95 
96    return 0;
97 }
98 
99 static bool
dri2_drm_config_is_compatible(struct dri2_egl_display * dri2_dpy,const __DRIconfig * config,struct gbm_surface * surface)100 dri2_drm_config_is_compatible(struct dri2_egl_display *dri2_dpy,
101                               const __DRIconfig *config,
102                               struct gbm_surface *surface)
103 {
104    const struct gl_config *gl_config = (struct gl_config *) config;
105    const struct gbm_dri_visual *visual = NULL;
106    int i;
107 
108    /* Check that the EGLConfig being used to render to the surface is
109     * compatible with the surface format. Since mixing ARGB and XRGB of
110     * otherwise-compatible formats is relatively common, explicitly allow
111     * this.
112     */
113    for (i = 0; i < dri2_dpy->gbm_dri->num_visuals; i++) {
114       visual = &dri2_dpy->gbm_dri->visual_table[i];
115       if (visual->gbm_format == surface->v0.format)
116          break;
117    }
118 
119    if (i == dri2_dpy->gbm_dri->num_visuals)
120       return false;
121 
122 
123    const struct util_format_description *fmt_c =
124       util_format_description(gl_config->color_format);
125    const struct util_format_description *fmt_s =
126       util_format_description(visual->dri_image_format);
127 
128    if (util_is_format_compatible(fmt_c, fmt_s) ||
129        util_is_format_compatible(fmt_s, fmt_c))
130       return true;
131 
132    return false;
133 }
134 
135 static _EGLSurface *
dri2_drm_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_surface,const EGLint * attrib_list)136 dri2_drm_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
137                                void *native_surface, const EGLint *attrib_list)
138 {
139    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
140    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
141    struct dri2_egl_surface *dri2_surf;
142    struct gbm_surface *surface = native_surface;
143    struct gbm_dri_surface *surf;
144    const __DRIconfig *config;
145 
146    dri2_surf = calloc(1, sizeof *dri2_surf);
147    if (!dri2_surf) {
148       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
149       return NULL;
150    }
151 
152    if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf,
153                           attrib_list, false, native_surface))
154       goto cleanup_surf;
155 
156    config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
157                                 dri2_surf->base.GLColorspace);
158 
159    if (!config) {
160       _eglError(EGL_BAD_MATCH,
161                 "Unsupported surfacetype/colorspace configuration");
162       goto cleanup_surf;
163    }
164 
165    if (!dri2_drm_config_is_compatible(dri2_dpy, config, surface)) {
166       _eglError(EGL_BAD_MATCH, "EGL config not compatible with GBM format");
167       goto cleanup_surf;
168    }
169 
170    surf = gbm_dri_surface(surface);
171    dri2_surf->gbm_surf = surf;
172    dri2_surf->base.Width = surf->base.v0.width;
173    dri2_surf->base.Height = surf->base.v0.height;
174    surf->dri_private = dri2_surf;
175 
176    if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf->gbm_surf))
177       goto cleanup_surf;
178 
179    return &dri2_surf->base;
180 
181 cleanup_surf:
182    free(dri2_surf);
183 
184    return NULL;
185 }
186 
187 static _EGLSurface *
dri2_drm_create_pixmap_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)188 dri2_drm_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
189                                void *native_window, const EGLint *attrib_list)
190 {
191    /* From the EGL_MESA_platform_gbm spec, version 5:
192     *
193     *  It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
194     *  that belongs to the GBM platform. Any such call fails and generates
195     *  EGL_BAD_PARAMETER.
196     */
197    _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on GBM");
198    return NULL;
199 }
200 
201 static EGLBoolean
dri2_drm_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)202 dri2_drm_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
203 {
204    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
205 
206    driDestroyDrawable(dri2_surf->dri_drawable);
207 
208    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
209       if (dri2_surf->color_buffers[i].bo)
210          gbm_bo_destroy(dri2_surf->color_buffers[i].bo);
211    }
212 
213    dri2_fini_surface(surf);
214    free(surf);
215 
216    return EGL_TRUE;
217 }
218 
219 static int
get_back_bo(struct dri2_egl_surface * dri2_surf)220 get_back_bo(struct dri2_egl_surface *dri2_surf)
221 {
222    struct dri2_egl_display *dri2_dpy =
223       dri2_egl_display(dri2_surf->base.Resource.Display);
224    struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
225    int age = 0;
226 
227    if (dri2_surf->back == NULL) {
228       for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
229          if (!dri2_surf->color_buffers[i].locked &&
230              dri2_surf->color_buffers[i].age >= age) {
231             dri2_surf->back = &dri2_surf->color_buffers[i];
232             age = dri2_surf->color_buffers[i].age;
233          }
234       }
235    }
236 
237    if (dri2_surf->back == NULL)
238       return -1;
239    if (dri2_surf->back->bo == NULL) {
240       if (surf->base.v0.modifiers && surf->base.v0.flags)
241          dri2_surf->back->bo = gbm_bo_create_with_modifiers2(
242             &dri2_dpy->gbm_dri->base, surf->base.v0.width, surf->base.v0.height,
243             surf->base.v0.format, surf->base.v0.modifiers, surf->base.v0.count,
244             surf->base.v0.flags);
245       else if (surf->base.v0.modifiers)
246          dri2_surf->back->bo = gbm_bo_create_with_modifiers(
247             &dri2_dpy->gbm_dri->base, surf->base.v0.width, surf->base.v0.height,
248             surf->base.v0.format, surf->base.v0.modifiers, surf->base.v0.count);
249       else {
250          unsigned flags = surf->base.v0.flags;
251          if (dri2_surf->base.ProtectedContent)
252             flags |= GBM_BO_USE_PROTECTED;
253          dri2_surf->back->bo =
254             gbm_bo_create(&dri2_dpy->gbm_dri->base, surf->base.v0.width,
255                           surf->base.v0.height, surf->base.v0.format, flags);
256       }
257    }
258    if (dri2_surf->back->bo == NULL)
259       return -1;
260 
261    return 0;
262 }
263 
264 static int
get_swrast_front_bo(struct dri2_egl_surface * dri2_surf)265 get_swrast_front_bo(struct dri2_egl_surface *dri2_surf)
266 {
267    struct dri2_egl_display *dri2_dpy =
268       dri2_egl_display(dri2_surf->base.Resource.Display);
269    struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
270 
271    if (dri2_surf->current == NULL) {
272       assert(!dri2_surf->color_buffers[0].locked);
273       dri2_surf->current = &dri2_surf->color_buffers[0];
274    }
275 
276    if (dri2_surf->current->bo == NULL)
277       dri2_surf->current->bo = gbm_bo_create(
278          &dri2_dpy->gbm_dri->base, surf->base.v0.width, surf->base.v0.height,
279          surf->base.v0.format, surf->base.v0.flags);
280    if (dri2_surf->current->bo == NULL)
281       return -1;
282 
283    return 0;
284 }
285 
286 static int
dri2_drm_image_get_buffers(__DRIdrawable * driDrawable,unsigned int format,uint32_t * stamp,void * loaderPrivate,uint32_t buffer_mask,struct __DRIimageList * buffers)287 dri2_drm_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format,
288                            uint32_t *stamp, void *loaderPrivate,
289                            uint32_t buffer_mask, struct __DRIimageList *buffers)
290 {
291    struct dri2_egl_surface *dri2_surf = loaderPrivate;
292    struct gbm_dri_bo *bo;
293 
294    if (get_back_bo(dri2_surf) < 0)
295       return 0;
296 
297    bo = gbm_dri_bo(dri2_surf->back->bo);
298    buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
299    buffers->back = bo->image;
300 
301    return 1;
302 }
303 
304 static void
dri2_drm_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)305 dri2_drm_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
306 {
307    (void)driDrawable;
308    (void)loaderPrivate;
309 }
310 
311 static EGLBoolean
dri2_drm_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)312 dri2_drm_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
313 {
314    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
315    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
316 
317    if (dri2_dpy->swrast_not_kms) {
318       driSwapBuffers(dri2_surf->dri_drawable);
319       return EGL_TRUE;
320    }
321 
322    if (dri2_surf->current)
323       _eglError(EGL_BAD_SURFACE, "dri2_swap_buffers");
324    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
325       if (dri2_surf->color_buffers[i].age > 0)
326          dri2_surf->color_buffers[i].age++;
327 
328    /* Flushing must be done before get_back_bo to make sure glthread's
329     * unmarshalling thread is idle otherwise it might concurrently
330     * call get_back_bo (eg: through dri2_drm_image_get_buffers).
331     */
332    dri2_flush_drawable_for_swapbuffers(disp, draw);
333    dri_invalidate_drawable(dri2_surf->dri_drawable);
334 
335    /* Make sure we have a back buffer in case we're swapping without
336     * ever rendering. */
337    if (get_back_bo(dri2_surf) < 0)
338       return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
339 
340    dri2_surf->current = dri2_surf->back;
341    dri2_surf->current->age = 1;
342    dri2_surf->back = NULL;
343 
344    return EGL_TRUE;
345 }
346 
347 static EGLint
dri2_drm_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surface)348 dri2_drm_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
349 {
350    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
351 
352    if (get_back_bo(dri2_surf) < 0) {
353       _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
354       return -1;
355    }
356 
357    return dri2_surf->back->age;
358 }
359 
360 static _EGLImage *
dri2_drm_create_image_khr_pixmap(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)361 dri2_drm_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
362                                  EGLClientBuffer buffer,
363                                  const EGLint *attr_list)
364 {
365    struct gbm_dri_bo *dri_bo = gbm_dri_bo((struct gbm_bo *)buffer);
366    struct dri2_egl_image *dri2_img;
367 
368    dri2_img = malloc(sizeof *dri2_img);
369    if (!dri2_img) {
370       _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
371       return NULL;
372    }
373 
374    _eglInitImage(&dri2_img->base, disp);
375 
376    dri2_img->dri_image = dri2_dup_image(dri_bo->image, dri2_img);
377    if (dri2_img->dri_image == NULL) {
378       free(dri2_img);
379       _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
380       return NULL;
381    }
382 
383    return &dri2_img->base;
384 }
385 
386 static _EGLImage *
dri2_drm_create_image_khr(_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)387 dri2_drm_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
388                           EGLClientBuffer buffer, const EGLint *attr_list)
389 {
390    switch (target) {
391    case EGL_NATIVE_PIXMAP_KHR:
392       return dri2_drm_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
393    default:
394       return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
395    }
396 }
397 
398 static int
dri2_drm_authenticate(_EGLDisplay * disp,uint32_t id)399 dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id)
400 {
401    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
402 
403    return drmAuthMagic(dri2_dpy->fd_render_gpu, id);
404 }
405 
406 static void
swrast_put_image2(__DRIdrawable * driDrawable,int op,int x,int y,int width,int height,int stride,char * data,void * loaderPrivate)407 swrast_put_image2(__DRIdrawable *driDrawable, int op, int x, int y, int width,
408                   int height, int stride, char *data, void *loaderPrivate)
409 {
410    struct dri2_egl_surface *dri2_surf = loaderPrivate;
411    int internal_stride;
412    struct gbm_dri_bo *bo;
413    uint32_t bpp;
414    int x_bytes, width_bytes;
415    char *src, *dst;
416 
417    if (op != __DRI_SWRAST_IMAGE_OP_DRAW && op != __DRI_SWRAST_IMAGE_OP_SWAP)
418       return;
419 
420    if (get_swrast_front_bo(dri2_surf) < 0)
421       return;
422 
423    bo = gbm_dri_bo(dri2_surf->current->bo);
424 
425    bpp = gbm_bo_get_bpp(&bo->base);
426    if (bpp == 0)
427       return;
428 
429    x_bytes = x * (bpp >> 3);
430    width_bytes = width * (bpp >> 3);
431 
432    if (gbm_dri_bo_map_dumb(bo) == NULL)
433       return;
434 
435    internal_stride = bo->base.v0.stride;
436 
437    dst = bo->map + x_bytes + (y * internal_stride);
438    src = data;
439 
440    for (int i = 0; i < height; i++) {
441       memcpy(dst, src, width_bytes);
442       dst += internal_stride;
443       src += stride;
444    }
445 
446    gbm_dri_bo_unmap_dumb(bo);
447 }
448 
449 static void
swrast_get_image(__DRIdrawable * driDrawable,int x,int y,int width,int height,char * data,void * loaderPrivate)450 swrast_get_image(__DRIdrawable *driDrawable, int x, int y, int width,
451                  int height, char *data, void *loaderPrivate)
452 {
453    struct dri2_egl_surface *dri2_surf = loaderPrivate;
454    int internal_stride, stride;
455    struct gbm_dri_bo *bo;
456    uint32_t bpp;
457    int x_bytes, width_bytes;
458    char *src, *dst;
459 
460    if (get_swrast_front_bo(dri2_surf) < 0)
461       return;
462 
463    bo = gbm_dri_bo(dri2_surf->current->bo);
464 
465    bpp = gbm_bo_get_bpp(&bo->base);
466    if (bpp == 0)
467       return;
468 
469    x_bytes = x * (bpp >> 3);
470    width_bytes = width * (bpp >> 3);
471 
472    internal_stride = bo->base.v0.stride;
473    stride = width_bytes;
474 
475    if (gbm_dri_bo_map_dumb(bo) == NULL)
476       return;
477 
478    dst = data;
479    src = bo->map + x_bytes + (y * internal_stride);
480 
481    for (int i = 0; i < height; i++) {
482       memcpy(dst, src, width_bytes);
483       dst += stride;
484       src += internal_stride;
485    }
486 
487    gbm_dri_bo_unmap_dumb(bo);
488 }
489 
490 static void
drm_add_configs_for_visuals(_EGLDisplay * disp)491 drm_add_configs_for_visuals(_EGLDisplay *disp)
492 {
493    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
494    const struct gbm_dri_visual *visuals = dri2_dpy->gbm_dri->visual_table;
495    int num_visuals = dri2_dpy->gbm_dri->num_visuals;
496    unsigned int format_count[num_visuals];
497 
498    memset(format_count, 0, num_visuals * sizeof(unsigned int));
499 
500    for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
501       const __DRIconfig *config = dri2_dpy->driver_configs[i];
502       struct gl_config *gl_config = (struct gl_config *) config;
503 
504       for (unsigned j = 0; j < num_visuals; j++) {
505          struct dri2_egl_config *dri2_conf;
506 
507          if (visuals[j].dri_image_format != gl_config->color_format)
508             continue;
509 
510          const EGLint attr_list[] = {
511             EGL_NATIVE_VISUAL_ID,
512             visuals[j].gbm_format,
513             EGL_NONE,
514          };
515 
516          dri2_conf =
517             dri2_add_config(disp, dri2_dpy->driver_configs[i], EGL_WINDOW_BIT,
518                             attr_list);
519          if (dri2_conf)
520             format_count[j]++;
521       }
522    }
523 
524    for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
525       if (!format_count[i]) {
526          struct gbm_format_name_desc desc;
527          _eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
528                  gbm_format_get_name(visuals[i].gbm_format, &desc));
529       }
530    }
531 }
532 
533 static const struct dri2_egl_display_vtbl dri2_drm_display_vtbl = {
534    .authenticate = dri2_drm_authenticate,
535    .create_window_surface = dri2_drm_create_window_surface,
536    .create_pixmap_surface = dri2_drm_create_pixmap_surface,
537    .destroy_surface = dri2_drm_destroy_surface,
538    .create_image = dri2_drm_create_image_khr,
539    .swap_buffers = dri2_drm_swap_buffers,
540    .query_buffer_age = dri2_drm_query_buffer_age,
541    .get_dri_drawable = dri2_surface_get_dri_drawable,
542 };
543 
544 static int
get_fd_render_gpu_drm(struct gbm_dri_device * gbm_dri,int fd_display_gpu)545 get_fd_render_gpu_drm(struct gbm_dri_device *gbm_dri, int fd_display_gpu)
546 {
547    /* This doesn't make sense for the software case. */
548    assert(!gbm_dri->software);
549 
550    /* Render-capable device, so just return the same fd. */
551    if (loader_is_device_render_capable(fd_display_gpu))
552       return fd_display_gpu;
553 
554    /* Display-only device, so return a compatible render-only device. */
555    return dri_query_compatible_render_only_device_fd(fd_display_gpu);
556 }
557 
558 EGLBoolean
dri2_initialize_drm(_EGLDisplay * disp)559 dri2_initialize_drm(_EGLDisplay *disp)
560 {
561    struct gbm_device *gbm;
562    const char *err;
563    struct dri2_egl_display *dri2_dpy = dri2_display_create();
564    if (!dri2_dpy)
565       return EGL_FALSE;
566 
567    disp->DriverData = (void *)dri2_dpy;
568 
569    gbm = disp->PlatformDisplay;
570    if (gbm == NULL) {
571       if (disp->Device) {
572          drmDevicePtr drm = _eglDeviceDrm(disp->Device);
573 
574          if (!_eglDeviceSupports(disp->Device, _EGL_DEVICE_DRM)) {
575             err = "DRI2: Device isn't of _EGL_DEVICE_DRM type";
576             goto cleanup;
577          }
578 
579          if (!(drm->available_nodes & (1 << DRM_NODE_PRIMARY))) {
580             err = "DRI2: Device does not have DRM_NODE_PRIMARY node";
581             goto cleanup;
582          }
583 
584          dri2_dpy->fd_display_gpu =
585             loader_open_device(drm->nodes[DRM_NODE_PRIMARY]);
586       } else {
587          _EGLDevice *dev_list = _eglGlobal.DeviceList;
588          drmDevicePtr drm;
589          while (dev_list) {
590             if (!_eglDeviceSupports(dev_list, _EGL_DEVICE_DRM))
591                goto next;
592 
593             drm = _eglDeviceDrm(dev_list);
594 
595             if (!(drm->available_nodes & (1 << DRM_NODE_PRIMARY)))
596                goto next;
597 
598             dri2_dpy->fd_display_gpu =
599                loader_open_device(drm->nodes[DRM_NODE_PRIMARY]);
600             if (dri2_dpy->fd_display_gpu < 0)
601                goto next;
602 
603             break;
604          next:
605             dev_list = _eglDeviceNext(dev_list);
606          }
607       }
608 
609       gbm = gbm_create_device(dri2_dpy->fd_display_gpu);
610       if (gbm == NULL) {
611          err = "DRI2: failed to create gbm device";
612          goto cleanup;
613       }
614       dri2_dpy->own_device = true;
615    } else {
616       dri2_dpy->fd_display_gpu = os_dupfd_cloexec(gbm_device_get_fd(gbm));
617       if (dri2_dpy->fd_display_gpu < 0) {
618          err = "DRI2: failed to fcntl() existing gbm device";
619          goto cleanup;
620       }
621    }
622    dri2_dpy->gbm_dri = gbm_dri_device(gbm);
623    if (!dri2_dpy->gbm_dri->software) {
624       dri2_dpy->fd_render_gpu =
625          get_fd_render_gpu_drm(dri2_dpy->gbm_dri, dri2_dpy->fd_display_gpu);
626       if (dri2_dpy->fd_render_gpu < 0) {
627          err = "DRI2: failed to get compatible render device";
628          goto cleanup;
629       }
630    }
631 
632    if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) {
633       err = "DRI2: gbm device using incorrect/incompatible backend";
634       goto cleanup;
635    }
636 
637    dri2_dpy->driver_name = strdup(dri2_dpy->gbm_dri->driver_name);
638 
639    if (!dri2_load_driver(disp)) {
640       err = "DRI3: failed to load driver";
641       goto cleanup;
642    }
643 
644    dri2_dpy->dri_screen_render_gpu = dri2_dpy->gbm_dri->screen;
645    dri2_dpy->driver_configs = dri2_dpy->gbm_dri->driver_configs;
646 
647    dri2_dpy->gbm_dri->validate_image = dri2_validate_egl_image;
648    dri2_dpy->gbm_dri->lookup_image_validated = dri2_lookup_egl_image_validated;
649    dri2_dpy->gbm_dri->lookup_user_data = disp;
650 
651    dri2_dpy->gbm_dri->flush_front_buffer = dri2_drm_flush_front_buffer;
652    dri2_dpy->gbm_dri->image_get_buffers = dri2_drm_image_get_buffers;
653    dri2_dpy->gbm_dri->swrast_put_image2 = swrast_put_image2;
654    dri2_dpy->gbm_dri->swrast_get_image = swrast_get_image;
655 
656    dri2_dpy->gbm_dri->base.v0.surface_lock_front_buffer = lock_front_buffer;
657    dri2_dpy->gbm_dri->base.v0.surface_release_buffer = release_buffer;
658    dri2_dpy->gbm_dri->base.v0.surface_has_free_buffers = has_free_buffers;
659 
660    if (!dri2_setup_device(disp, dri2_dpy->gbm_dri->software)) {
661       err = "DRI2: failed to setup EGLDevice";
662       goto cleanup;
663    }
664 
665    dri2_setup_screen(disp);
666 
667    drm_add_configs_for_visuals(disp);
668 
669    disp->Extensions.KHR_image_pixmap = EGL_TRUE;
670    disp->Extensions.EXT_buffer_age = EGL_TRUE;
671 
672 #ifdef HAVE_WAYLAND_PLATFORM
673    dri2_dpy->device_name =
674       loader_get_device_name_for_fd(dri2_dpy->fd_render_gpu);
675 #endif
676    dri2_set_WL_bind_wayland_display(disp);
677 
678    /* Fill vtbl last to prevent accidentally calling virtual function during
679     * initialization.
680     */
681    dri2_dpy->vtbl = &dri2_drm_display_vtbl;
682 
683    return EGL_TRUE;
684 
685 cleanup:
686    dri2_display_destroy(disp);
687    return _eglError(EGL_NOT_INITIALIZED, err);
688 }
689 
690 void
dri2_teardown_drm(struct dri2_egl_display * dri2_dpy)691 dri2_teardown_drm(struct dri2_egl_display *dri2_dpy)
692 {
693    if (dri2_dpy->own_device)
694       gbm_device_destroy(&dri2_dpy->gbm_dri->base);
695 }
696