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