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