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 <stdint.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <xf86drm.h>
33 #include <dlfcn.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 
39 #include "egl_dri2.h"
40 #include "egl_dri2_fallbacks.h"
41 #include "loader.h"
42 
43 static struct gbm_bo *
lock_front_buffer(struct gbm_surface * _surf)44 lock_front_buffer(struct gbm_surface *_surf)
45 {
46    struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
47    struct dri2_egl_surface *dri2_surf = surf->dri_private;
48    struct gbm_dri_device *device = (struct gbm_dri_device *) _surf->gbm;
49    struct gbm_bo *bo;
50 
51    if (dri2_surf->current == NULL) {
52       _eglError(EGL_BAD_SURFACE, "no front buffer");
53       return NULL;
54    }
55 
56    bo = dri2_surf->current->bo;
57 
58    if (device->dri2) {
59       dri2_surf->current->locked = true;
60       dri2_surf->current = NULL;
61    }
62 
63    return bo;
64 }
65 
66 static void
release_buffer(struct gbm_surface * _surf,struct gbm_bo * bo)67 release_buffer(struct gbm_surface *_surf, struct gbm_bo *bo)
68 {
69    struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
70    struct dri2_egl_surface *dri2_surf = surf->dri_private;
71 
72    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
73       if (dri2_surf->color_buffers[i].bo == bo) {
74 	 dri2_surf->color_buffers[i].locked = false;
75 	 break;
76       }
77    }
78 }
79 
80 static int
has_free_buffers(struct gbm_surface * _surf)81 has_free_buffers(struct gbm_surface *_surf)
82 {
83    struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
84    struct dri2_egl_surface *dri2_surf = surf->dri_private;
85 
86    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
87       if (!dri2_surf->color_buffers[i].locked)
88 	 return 1;
89 
90    return 0;
91 }
92 
93 static _EGLSurface *
dri2_drm_create_window_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLConfig * conf,void * native_surface,const EGLint * attrib_list)94 dri2_drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
95                                _EGLConfig *conf, void *native_surface,
96                                const EGLint *attrib_list)
97 {
98    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
99    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
100    struct dri2_egl_surface *dri2_surf;
101    struct gbm_surface *surface = native_surface;
102    struct gbm_dri_surface *surf;
103    const __DRIconfig *config;
104 
105    (void) drv;
106 
107    dri2_surf = calloc(1, sizeof *dri2_surf);
108    if (!dri2_surf) {
109       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
110       return NULL;
111    }
112 
113    if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, false))
114       goto cleanup_surf;
115 
116    surf = gbm_dri_surface(surface);
117    dri2_surf->gbm_surf = surf;
118    dri2_surf->base.Width =  surf->base.width;
119    dri2_surf->base.Height = surf->base.height;
120    surf->dri_private = dri2_surf;
121 
122    config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
123                                 dri2_surf->base.GLColorspace);
124 
125    if (dri2_dpy->dri2) {
126       dri2_surf->dri_drawable =
127          dri2_dpy->dri2->createNewDrawable(dri2_dpy->dri_screen, config,
128                                            dri2_surf->gbm_surf);
129 
130    } else {
131       assert(dri2_dpy->swrast != NULL);
132 
133       dri2_surf->dri_drawable =
134          dri2_dpy->swrast->createNewDrawable(dri2_dpy->dri_screen, config,
135                                              dri2_surf->gbm_surf);
136 
137    }
138    if (dri2_surf->dri_drawable == NULL) {
139       _eglError(EGL_BAD_ALLOC, "createNewDrawable()");
140       goto cleanup_surf;
141    }
142 
143    return &dri2_surf->base;
144 
145  cleanup_surf:
146    free(dri2_surf);
147 
148    return NULL;
149 }
150 
151 static _EGLSurface *
dri2_drm_create_pixmap_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)152 dri2_drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
153                                _EGLConfig *conf, void *native_window,
154                                const EGLint *attrib_list)
155 {
156    /* From the EGL_MESA_platform_gbm spec, version 5:
157     *
158     *  It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
159     *  that belongs to the GBM platform. Any such call fails and generates
160     *  EGL_BAD_PARAMETER.
161     */
162    _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on GBM");
163    return NULL;
164 }
165 
166 static EGLBoolean
dri2_drm_destroy_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surf)167 dri2_drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
168 {
169    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
170    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
171 
172    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
173 
174    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
175       if (dri2_surf->color_buffers[i].bo)
176 	 gbm_bo_destroy(dri2_surf->color_buffers[i].bo);
177    }
178 
179    dri2_egl_surface_free_local_buffers(dri2_surf);
180 
181    dri2_fini_surface(surf);
182    free(surf);
183 
184    return EGL_TRUE;
185 }
186 
187 static int
get_back_bo(struct dri2_egl_surface * dri2_surf)188 get_back_bo(struct dri2_egl_surface *dri2_surf)
189 {
190    struct dri2_egl_display *dri2_dpy =
191       dri2_egl_display(dri2_surf->base.Resource.Display);
192    struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
193    int age = 0;
194 
195    if (dri2_surf->back == NULL) {
196       for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
197 	 if (!dri2_surf->color_buffers[i].locked &&
198 	      dri2_surf->color_buffers[i].age >= age) {
199 	    dri2_surf->back = &dri2_surf->color_buffers[i];
200 	    age = dri2_surf->color_buffers[i].age;
201 	 }
202       }
203    }
204 
205    if (dri2_surf->back == NULL)
206       return -1;
207    if (dri2_surf->back->bo == NULL) {
208       if (surf->base.modifiers)
209          dri2_surf->back->bo = gbm_bo_create_with_modifiers(&dri2_dpy->gbm_dri->base,
210                                                             surf->base.width,
211                                                             surf->base.height,
212                                                             surf->base.format,
213                                                             surf->base.modifiers,
214                                                             surf->base.count);
215       else
216          dri2_surf->back->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base,
217                                              surf->base.width,
218                                              surf->base.height,
219                                              surf->base.format,
220                                              surf->base.flags);
221 
222    }
223    if (dri2_surf->back->bo == NULL)
224       return -1;
225 
226    return 0;
227 }
228 
229 static int
get_swrast_front_bo(struct dri2_egl_surface * dri2_surf)230 get_swrast_front_bo(struct dri2_egl_surface *dri2_surf)
231 {
232    struct dri2_egl_display *dri2_dpy =
233       dri2_egl_display(dri2_surf->base.Resource.Display);
234    struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
235 
236    if (dri2_surf->current == NULL) {
237       assert(!dri2_surf->color_buffers[0].locked);
238       dri2_surf->current = &dri2_surf->color_buffers[0];
239    }
240 
241    if (dri2_surf->current->bo == NULL)
242       dri2_surf->current->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base,
243                                              surf->base.width, surf->base.height,
244                                              surf->base.format, surf->base.flags);
245    if (dri2_surf->current->bo == NULL)
246       return -1;
247 
248    return 0;
249 }
250 
251 static void
back_bo_to_dri_buffer(struct dri2_egl_surface * dri2_surf,__DRIbuffer * buffer)252 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
253 {
254    struct dri2_egl_display *dri2_dpy =
255       dri2_egl_display(dri2_surf->base.Resource.Display);
256    struct gbm_dri_bo *bo;
257    int name, pitch;
258 
259    bo = (struct gbm_dri_bo *) dri2_surf->back->bo;
260 
261    dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_NAME, &name);
262    dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
263 
264    buffer->attachment = __DRI_BUFFER_BACK_LEFT;
265    buffer->name = name;
266    buffer->pitch = pitch;
267    buffer->cpp = 4;
268    buffer->flags = 0;
269 }
270 
271 static __DRIbuffer *
dri2_drm_get_buffers_with_format(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)272 dri2_drm_get_buffers_with_format(__DRIdrawable *driDrawable,
273                                  int *width, int *height,
274                                  unsigned int *attachments, int count,
275                                  int *out_count, void *loaderPrivate)
276 {
277    struct dri2_egl_surface *dri2_surf = loaderPrivate;
278    int i, j;
279 
280    for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
281       __DRIbuffer *local;
282 
283       assert(attachments[i] < __DRI_BUFFER_COUNT);
284       assert(j < ARRAY_SIZE(dri2_surf->buffers));
285 
286       switch (attachments[i]) {
287       case __DRI_BUFFER_BACK_LEFT:
288 	 if (get_back_bo(dri2_surf) < 0) {
289 	    _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
290 	    return NULL;
291 	 }
292          back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
293 	 break;
294       default:
295 	 local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i],
296                                                      attachments[i + 1]);
297 
298 	 if (!local) {
299 	    _eglError(EGL_BAD_ALLOC, "failed to allocate local buffer");
300 	    return NULL;
301 	 }
302 	 dri2_surf->buffers[j] = *local;
303 	 break;
304       }
305    }
306 
307    *out_count = j;
308    if (j == 0)
309       return NULL;
310 
311    *width = dri2_surf->base.Width;
312    *height = dri2_surf->base.Height;
313 
314    return dri2_surf->buffers;
315 }
316 
317 static __DRIbuffer *
dri2_drm_get_buffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)318 dri2_drm_get_buffers(__DRIdrawable * driDrawable,
319                      int *width, int *height,
320                      unsigned int *attachments, int count,
321                      int *out_count, void *loaderPrivate)
322 {
323    unsigned int *attachments_with_format;
324    __DRIbuffer *buffer;
325    const unsigned int format = 32;
326 
327    attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
328    if (!attachments_with_format) {
329       *out_count = 0;
330       return NULL;
331    }
332 
333    for (int i = 0; i < count; ++i) {
334       attachments_with_format[2*i] = attachments[i];
335       attachments_with_format[2*i + 1] = format;
336    }
337 
338    buffer =
339       dri2_drm_get_buffers_with_format(driDrawable,
340                                        width, height,
341                                        attachments_with_format, count,
342                                        out_count, loaderPrivate);
343 
344    free(attachments_with_format);
345 
346    return buffer;
347 }
348 
349 static int
dri2_drm_image_get_buffers(__DRIdrawable * driDrawable,unsigned int format,uint32_t * stamp,void * loaderPrivate,uint32_t buffer_mask,struct __DRIimageList * buffers)350 dri2_drm_image_get_buffers(__DRIdrawable *driDrawable,
351                            unsigned int format,
352                            uint32_t *stamp,
353                            void *loaderPrivate,
354                            uint32_t buffer_mask,
355                            struct __DRIimageList *buffers)
356 {
357    struct dri2_egl_surface *dri2_surf = loaderPrivate;
358    struct gbm_dri_bo *bo;
359 
360    if (get_back_bo(dri2_surf) < 0)
361       return 0;
362 
363    bo = (struct gbm_dri_bo *) dri2_surf->back->bo;
364    buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
365    buffers->back = bo->image;
366 
367    return 1;
368 }
369 
370 static void
dri2_drm_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)371 dri2_drm_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
372 {
373    (void) driDrawable;
374    (void) loaderPrivate;
375 }
376 
377 static EGLBoolean
dri2_drm_swap_buffers(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw)378 dri2_drm_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
379 {
380    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
381    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
382 
383    if (!dri2_dpy->flush) {
384       dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
385       return EGL_TRUE;
386    }
387 
388    if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
389       if (dri2_surf->current)
390          _eglError(EGL_BAD_SURFACE, "dri2_swap_buffers");
391       for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
392          if (dri2_surf->color_buffers[i].age > 0)
393             dri2_surf->color_buffers[i].age++;
394 
395       /* Make sure we have a back buffer in case we're swapping without
396        * ever rendering. */
397       if (get_back_bo(dri2_surf) < 0)
398          return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
399 
400       dri2_surf->current = dri2_surf->back;
401       dri2_surf->current->age = 1;
402       dri2_surf->back = NULL;
403    }
404 
405    dri2_flush_drawable_for_swapbuffers(disp, draw);
406    dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
407 
408    return EGL_TRUE;
409 }
410 
411 static EGLint
dri2_drm_query_buffer_age(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surface)412 dri2_drm_query_buffer_age(_EGLDriver *drv,
413                           _EGLDisplay *disp, _EGLSurface *surface)
414 {
415    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
416 
417    if (get_back_bo(dri2_surf) < 0) {
418       _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
419       return -1;
420    }
421 
422    return dri2_surf->back->age;
423 }
424 
425 static _EGLImage *
dri2_drm_create_image_khr_pixmap(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)426 dri2_drm_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
427                                  EGLClientBuffer buffer, const EGLint *attr_list)
428 {
429    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
430    struct gbm_dri_bo *dri_bo = gbm_dri_bo((struct gbm_bo *) buffer);
431    struct dri2_egl_image *dri2_img;
432 
433    dri2_img = malloc(sizeof *dri2_img);
434    if (!dri2_img) {
435       _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
436       return NULL;
437    }
438 
439    _eglInitImage(&dri2_img->base, disp);
440 
441    dri2_img->dri_image = dri2_dpy->image->dupImage(dri_bo->image, dri2_img);
442    if (dri2_img->dri_image == NULL) {
443       free(dri2_img);
444       _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
445       return NULL;
446    }
447 
448    return &dri2_img->base;
449 }
450 
451 static _EGLImage *
dri2_drm_create_image_khr(_EGLDriver * drv,_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)452 dri2_drm_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
453                           _EGLContext *ctx, EGLenum target,
454                           EGLClientBuffer buffer, const EGLint *attr_list)
455 {
456    (void) drv;
457 
458    switch (target) {
459    case EGL_NATIVE_PIXMAP_KHR:
460       return dri2_drm_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
461    default:
462       return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
463    }
464 }
465 
466 static int
dri2_drm_authenticate(_EGLDisplay * disp,uint32_t id)467 dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id)
468 {
469    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
470 
471    return drmAuthMagic(dri2_dpy->fd, id);
472 }
473 
474 static void
swrast_put_image2(__DRIdrawable * driDrawable,int op,int x,int y,int width,int height,int stride,char * data,void * loaderPrivate)475 swrast_put_image2(__DRIdrawable *driDrawable,
476                   int            op,
477                   int            x,
478                   int            y,
479                   int            width,
480                   int            height,
481                   int            stride,
482                   char          *data,
483                   void          *loaderPrivate)
484 {
485    struct dri2_egl_surface *dri2_surf = loaderPrivate;
486    int internal_stride;
487    struct gbm_dri_bo *bo;
488    uint32_t bpp;
489    int x_bytes, width_bytes;
490    char *src, *dst;
491 
492    if (op != __DRI_SWRAST_IMAGE_OP_DRAW &&
493        op != __DRI_SWRAST_IMAGE_OP_SWAP)
494       return;
495 
496    if (get_swrast_front_bo(dri2_surf) < 0)
497       return;
498 
499    bo = gbm_dri_bo(dri2_surf->current->bo);
500 
501    bpp = gbm_bo_get_bpp(&bo->base);
502    if (bpp == 0)
503       return;
504 
505    x_bytes = x * (bpp >> 3);
506    width_bytes = width * (bpp >> 3);
507 
508    if (gbm_dri_bo_map_dumb(bo) == NULL)
509       return;
510 
511    internal_stride = bo->base.stride;
512 
513    dst = bo->map + x_bytes + (y * internal_stride);
514    src = data;
515 
516    for (int i = 0; i < height; i++) {
517       memcpy(dst, src, width_bytes);
518       dst += internal_stride;
519       src += stride;
520    }
521 
522    gbm_dri_bo_unmap_dumb(bo);
523 }
524 
525 static void
swrast_get_image(__DRIdrawable * driDrawable,int x,int y,int width,int height,char * data,void * loaderPrivate)526 swrast_get_image(__DRIdrawable *driDrawable,
527                  int            x,
528                  int            y,
529                  int            width,
530                  int            height,
531                  char          *data,
532                  void          *loaderPrivate)
533 {
534    struct dri2_egl_surface *dri2_surf = loaderPrivate;
535    int internal_stride, stride;
536    struct gbm_dri_bo *bo;
537    uint32_t bpp;
538    int x_bytes, width_bytes;
539    char *src, *dst;
540 
541    if (get_swrast_front_bo(dri2_surf) < 0)
542       return;
543 
544    bo = gbm_dri_bo(dri2_surf->current->bo);
545 
546    bpp = gbm_bo_get_bpp(&bo->base);
547    if (bpp == 0)
548       return;
549 
550    x_bytes = x * (bpp >> 3);
551    width_bytes = width * (bpp >> 3);
552 
553    internal_stride = bo->base.stride;
554    stride = width_bytes;
555 
556    if (gbm_dri_bo_map_dumb(bo) == NULL)
557       return;
558 
559    dst = data;
560    src = bo->map + x_bytes + (y * internal_stride);
561 
562    for (int i = 0; i < height; i++) {
563       memcpy(dst, src, width_bytes);
564       dst += stride;
565       src += internal_stride;
566    }
567 
568    gbm_dri_bo_unmap_dumb(bo);
569 }
570 
571 static EGLBoolean
drm_add_configs_for_visuals(_EGLDriver * drv,_EGLDisplay * disp)572 drm_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp)
573 {
574    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
575    static const struct {
576       int format;
577       unsigned int red_mask;
578       unsigned int alpha_mask;
579    } visuals[] = {
580       { GBM_FORMAT_XRGB2101010, 0x3ff00000, 0x00000000 },
581       { GBM_FORMAT_ARGB2101010, 0x3ff00000, 0xc0000000 },
582       { GBM_FORMAT_XRGB8888,    0x00ff0000, 0x00000000 },
583       { GBM_FORMAT_ARGB8888,    0x00ff0000, 0xff000000 },
584       { GBM_FORMAT_RGB565,      0x0000f800, 0x00000000 },
585    };
586 
587    unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 };
588    unsigned int config_count = 0;
589 
590    for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
591       unsigned int red, alpha;
592 
593       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
594                                       __DRI_ATTRIB_RED_MASK, &red);
595       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
596                                       __DRI_ATTRIB_ALPHA_MASK, &alpha);
597 
598       for (unsigned j = 0; j < ARRAY_SIZE(visuals); j++) {
599          struct dri2_egl_config *dri2_conf;
600 
601          if (visuals[j].red_mask != red || visuals[j].alpha_mask != alpha)
602             continue;
603 
604          const EGLint attr_list[] = {
605             EGL_NATIVE_VISUAL_ID,  visuals[j].format,
606             EGL_NONE,
607          };
608 
609          dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
610                config_count + 1, EGL_WINDOW_BIT, attr_list, NULL);
611          if (dri2_conf) {
612             if (dri2_conf->base.ConfigID == config_count + 1)
613                config_count++;
614             format_count[j]++;
615          }
616       }
617    }
618 
619    for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
620       if (!format_count[i]) {
621          _eglLog(_EGL_DEBUG, "No DRI config supports native format 0x%x",
622                  visuals[i].format);
623       }
624    }
625 
626    return (config_count != 0);
627 }
628 
629 static const struct dri2_egl_display_vtbl dri2_drm_display_vtbl = {
630    .authenticate = dri2_drm_authenticate,
631    .create_window_surface = dri2_drm_create_window_surface,
632    .create_pixmap_surface = dri2_drm_create_pixmap_surface,
633    .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
634    .destroy_surface = dri2_drm_destroy_surface,
635    .create_image = dri2_drm_create_image_khr,
636    .swap_buffers = dri2_drm_swap_buffers,
637    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
638    .swap_buffers_region = dri2_fallback_swap_buffers_region,
639    .set_damage_region = dri2_fallback_set_damage_region,
640    .post_sub_buffer = dri2_fallback_post_sub_buffer,
641    .copy_buffers = dri2_fallback_copy_buffers,
642    .query_buffer_age = dri2_drm_query_buffer_age,
643    .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
644    .get_sync_values = dri2_fallback_get_sync_values,
645    .get_dri_drawable = dri2_surface_get_dri_drawable,
646 };
647 
648 EGLBoolean
dri2_initialize_drm(_EGLDriver * drv,_EGLDisplay * disp)649 dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp)
650 {
651    struct dri2_egl_display *dri2_dpy;
652    struct gbm_device *gbm;
653    const char *err;
654 
655    /* Not supported yet */
656    if (disp->Options.ForceSoftware)
657       return EGL_FALSE;
658 
659    loader_set_logger(_eglLog);
660 
661    dri2_dpy = calloc(1, sizeof *dri2_dpy);
662    if (!dri2_dpy)
663       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
664 
665    dri2_dpy->fd = -1;
666    disp->DriverData = (void *) dri2_dpy;
667 
668    gbm = disp->PlatformDisplay;
669    if (gbm == NULL) {
670       char buf[64];
671       int n = snprintf(buf, sizeof(buf), DRM_DEV_NAME, DRM_DIR_NAME, 0);
672       if (n != -1 && n < sizeof(buf))
673          dri2_dpy->fd = loader_open_device(buf);
674       gbm = gbm_create_device(dri2_dpy->fd);
675       if (gbm == NULL) {
676          err = "DRI2: failed to create gbm device";
677          goto cleanup;
678       }
679       dri2_dpy->own_device = true;
680    } else {
681       dri2_dpy->fd = fcntl(gbm_device_get_fd(gbm), F_DUPFD_CLOEXEC, 3);
682       if (dri2_dpy->fd < 0) {
683          err = "DRI2: failed to fcntl() existing gbm device";
684          goto cleanup;
685       }
686    }
687 
688    if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) {
689       err = "DRI2: gbm device using incorrect/incompatible backend";
690       goto cleanup;
691    }
692 
693    dri2_dpy->gbm_dri = gbm_dri_device(gbm);
694    dri2_dpy->driver_name = strdup(dri2_dpy->gbm_dri->driver_name);
695 
696    dri2_dpy->dri_screen = dri2_dpy->gbm_dri->screen;
697    dri2_dpy->core = dri2_dpy->gbm_dri->core;
698    dri2_dpy->dri2 = dri2_dpy->gbm_dri->dri2;
699    dri2_dpy->swrast = dri2_dpy->gbm_dri->swrast;
700    dri2_dpy->driver_configs = dri2_dpy->gbm_dri->driver_configs;
701 
702    dri2_dpy->gbm_dri->lookup_image = dri2_lookup_egl_image;
703    dri2_dpy->gbm_dri->lookup_user_data = disp;
704 
705    dri2_dpy->gbm_dri->get_buffers = dri2_drm_get_buffers;
706    dri2_dpy->gbm_dri->flush_front_buffer = dri2_drm_flush_front_buffer;
707    dri2_dpy->gbm_dri->get_buffers_with_format = dri2_drm_get_buffers_with_format;
708    dri2_dpy->gbm_dri->image_get_buffers = dri2_drm_image_get_buffers;
709    dri2_dpy->gbm_dri->swrast_put_image2 = swrast_put_image2;
710    dri2_dpy->gbm_dri->swrast_get_image = swrast_get_image;
711 
712    dri2_dpy->gbm_dri->base.surface_lock_front_buffer = lock_front_buffer;
713    dri2_dpy->gbm_dri->base.surface_release_buffer = release_buffer;
714    dri2_dpy->gbm_dri->base.surface_has_free_buffers = has_free_buffers;
715 
716    if (!dri2_setup_extensions(disp)) {
717       err = "DRI2: failed to find required DRI extensions";
718       goto cleanup;
719    }
720 
721    dri2_setup_screen(disp);
722 
723    if (!drm_add_configs_for_visuals(drv, disp)) {
724       err = "DRI2: failed to add configs";
725       goto cleanup;
726    }
727 
728    disp->Extensions.KHR_image_pixmap = EGL_TRUE;
729    if (dri2_dpy->dri2)
730       disp->Extensions.EXT_buffer_age = EGL_TRUE;
731 
732 #ifdef HAVE_WAYLAND_PLATFORM
733    dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
734 #endif
735    dri2_set_WL_bind_wayland_display(drv, disp);
736 
737    /* Fill vtbl last to prevent accidentally calling virtual function during
738     * initialization.
739     */
740    dri2_dpy->vtbl = &dri2_drm_display_vtbl;
741 
742    return EGL_TRUE;
743 
744 cleanup:
745    dri2_display_destroy(disp);
746    return _eglError(EGL_NOT_INITIALIZED, err);
747 }
748 
749 void
dri2_teardown_drm(struct dri2_egl_display * dri2_dpy)750 dri2_teardown_drm(struct dri2_egl_display *dri2_dpy)
751 {
752    if (dri2_dpy->own_device)
753       gbm_device_destroy(&dri2_dpy->gbm_dri->base);
754 }
755