1/*
2 * Mesa 3-D graphics library
3 * Version:  7.8
4 *
5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26#include "util/u_memory.h"
27#include "util/u_math.h"
28#include "util/u_format.h"
29#include "util/u_inlines.h"
30#include "util/u_hash_table.h"
31#include "pipe/p_compiler.h"
32#include "pipe/p_screen.h"
33#include "pipe/p_context.h"
34#include "pipe/p_state.h"
35#include "state_tracker/drm_driver.h"
36#include "egllog.h"
37
38#include "native_x11.h"
39#include "x11_screen.h"
40
41#include "common/native_helper.h"
42#ifdef HAVE_WAYLAND_BACKEND
43#include "common/native_wayland_drm_bufmgr_helper.h"
44#endif
45
46#ifdef GLX_DIRECT_RENDERING
47
48struct dri2_display {
49   struct native_display base;
50   Display *dpy;
51   boolean own_dpy;
52
53   const struct native_event_handler *event_handler;
54
55   struct x11_screen *xscr;
56   int xscr_number;
57   const char *dri_driver;
58   int dri_major, dri_minor;
59
60   struct dri2_config *configs;
61   int num_configs;
62
63   struct util_hash_table *surfaces;
64#ifdef HAVE_WAYLAND_BACKEND
65   struct wl_drm *wl_server_drm; /* for EGL_WL_bind_wayland_display */
66#endif
67};
68
69struct dri2_surface {
70   struct native_surface base;
71   Drawable drawable;
72   enum pipe_format color_format;
73   struct dri2_display *dri2dpy;
74
75   unsigned int server_stamp;
76   unsigned int client_stamp;
77   int width, height;
78   struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
79   uint valid_mask;
80
81   boolean have_back, have_fake;
82
83   struct x11_drawable_buffer *last_xbufs;
84   int last_num_xbufs;
85};
86
87struct dri2_config {
88   struct native_config base;
89};
90
91static INLINE struct dri2_display *
92dri2_display(const struct native_display *ndpy)
93{
94   return (struct dri2_display *) ndpy;
95}
96
97static INLINE struct dri2_surface *
98dri2_surface(const struct native_surface *nsurf)
99{
100   return (struct dri2_surface *) nsurf;
101}
102
103static INLINE struct dri2_config *
104dri2_config(const struct native_config *nconf)
105{
106   return (struct dri2_config *) nconf;
107}
108
109/**
110 * Process the buffers returned by the server.
111 */
112static void
113dri2_surface_process_drawable_buffers(struct native_surface *nsurf,
114                                      struct x11_drawable_buffer *xbufs,
115                                      int num_xbufs)
116{
117   struct dri2_surface *dri2surf = dri2_surface(nsurf);
118   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
119   struct pipe_resource templ;
120   struct winsys_handle whandle;
121   uint valid_mask;
122   int i;
123
124   /* free the old textures */
125   for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
126      pipe_resource_reference(&dri2surf->textures[i], NULL);
127   dri2surf->valid_mask = 0x0;
128
129   dri2surf->have_back = FALSE;
130   dri2surf->have_fake = FALSE;
131
132   if (!xbufs)
133      return;
134
135   memset(&templ, 0, sizeof(templ));
136   templ.target = PIPE_TEXTURE_2D;
137   templ.last_level = 0;
138   templ.width0 = dri2surf->width;
139   templ.height0 = dri2surf->height;
140   templ.depth0 = 1;
141   templ.array_size = 1;
142   templ.format = dri2surf->color_format;
143   templ.bind = PIPE_BIND_RENDER_TARGET;
144
145   valid_mask = 0x0;
146   for (i = 0; i < num_xbufs; i++) {
147      struct x11_drawable_buffer *xbuf = &xbufs[i];
148      const char *desc;
149      enum native_attachment natt;
150
151      switch (xbuf->attachment) {
152      case DRI2BufferFrontLeft:
153         natt = NATIVE_ATTACHMENT_FRONT_LEFT;
154         desc = "DRI2 Front Buffer";
155         break;
156      case DRI2BufferFakeFrontLeft:
157         natt = NATIVE_ATTACHMENT_FRONT_LEFT;
158         desc = "DRI2 Fake Front Buffer";
159         dri2surf->have_fake = TRUE;
160         break;
161      case DRI2BufferBackLeft:
162         natt = NATIVE_ATTACHMENT_BACK_LEFT;
163         desc = "DRI2 Back Buffer";
164         dri2surf->have_back = TRUE;
165         break;
166      default:
167         desc = NULL;
168         break;
169      }
170
171      if (!desc || dri2surf->textures[natt]) {
172         if (!desc)
173            _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment);
174         else
175            _eglLog(_EGL_WARNING, "both real and fake front buffers are listed");
176         continue;
177      }
178
179      memset(&whandle, 0, sizeof(whandle));
180      whandle.stride = xbuf->pitch;
181      whandle.handle = xbuf->name;
182      dri2surf->textures[natt] = dri2dpy->base.screen->resource_from_handle(
183         dri2dpy->base.screen, &templ, &whandle);
184      if (dri2surf->textures[natt])
185         valid_mask |= 1 << natt;
186   }
187
188   dri2surf->valid_mask = valid_mask;
189}
190
191/**
192 * Get the buffers from the server.
193 */
194static void
195dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
196{
197   struct dri2_surface *dri2surf = dri2_surface(nsurf);
198   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
199   unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS * 2];
200   int num_ins, num_outs, att;
201   struct x11_drawable_buffer *xbufs;
202   uint bpp = util_format_get_blocksizebits(dri2surf->color_format);
203   boolean with_format = FALSE; /* never ask for depth/stencil */
204
205   /* We must get the front on servers which doesn't support with format
206    * due to a silly bug in core dri2. You can't copy to/from a buffer
207    * that you haven't requested and you recive BadValue errors */
208   if (dri2surf->dri2dpy->dri_minor < 1) {
209      with_format = FALSE;
210      buffer_mask |= (1 << NATIVE_ATTACHMENT_FRONT_LEFT);
211   }
212
213   /* prepare the attachments */
214   num_ins = 0;
215   for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
216      if (native_attachment_mask_test(buffer_mask, att)) {
217         unsigned int dri2att;
218
219         switch (att) {
220         case NATIVE_ATTACHMENT_FRONT_LEFT:
221            dri2att = DRI2BufferFrontLeft;
222            break;
223         case NATIVE_ATTACHMENT_BACK_LEFT:
224            dri2att = DRI2BufferBackLeft;
225            break;
226         case NATIVE_ATTACHMENT_FRONT_RIGHT:
227            dri2att = DRI2BufferFrontRight;
228            break;
229         case NATIVE_ATTACHMENT_BACK_RIGHT:
230            dri2att = DRI2BufferBackRight;
231            break;
232         default:
233            assert(0);
234            dri2att = 0;
235            break;
236         }
237
238         dri2atts[num_ins++] = dri2att;
239         if (with_format)
240            dri2atts[num_ins++] = bpp;
241      }
242   }
243   if (with_format)
244      num_ins /= 2;
245
246   xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable,
247                                    &dri2surf->width, &dri2surf->height,
248                                    dri2atts, with_format, num_ins, &num_outs);
249
250   /* we should be able to do better... */
251   if (xbufs && dri2surf->last_num_xbufs == num_outs &&
252       memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) {
253      FREE(xbufs);
254      dri2surf->client_stamp = dri2surf->server_stamp;
255      return;
256   }
257
258   dri2_surface_process_drawable_buffers(&dri2surf->base, xbufs, num_outs);
259
260   dri2surf->server_stamp++;
261   dri2surf->client_stamp = dri2surf->server_stamp;
262
263   if (dri2surf->last_xbufs)
264      FREE(dri2surf->last_xbufs);
265   dri2surf->last_xbufs = xbufs;
266   dri2surf->last_num_xbufs = num_outs;
267}
268
269/**
270 * Update the buffers of the surface.  This is a slow function due to the
271 * round-trip to the server.
272 */
273static boolean
274dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
275{
276   struct dri2_surface *dri2surf = dri2_surface(nsurf);
277
278   dri2_surface_get_buffers(&dri2surf->base, buffer_mask);
279
280   return ((dri2surf->valid_mask & buffer_mask) == buffer_mask);
281}
282
283/**
284 * Return TRUE if the surface receives DRI2_InvalidateBuffers events.
285 */
286static INLINE boolean
287dri2_surface_receive_events(struct native_surface *nsurf)
288{
289   struct dri2_surface *dri2surf = dri2_surface(nsurf);
290   return (dri2surf->dri2dpy->dri_minor >= 3);
291}
292
293static boolean
294dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
295{
296   struct dri2_surface *dri2surf = dri2_surface(nsurf);
297   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
298
299   /* copy to real front buffer */
300   if (dri2surf->have_fake)
301      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
302            0, 0, dri2surf->width, dri2surf->height,
303            DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
304
305   /* force buffers to be updated in next validation call */
306   if (!dri2_surface_receive_events(&dri2surf->base)) {
307      dri2surf->server_stamp++;
308      dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
309            &dri2surf->base, dri2surf->server_stamp);
310   }
311
312   return TRUE;
313}
314
315static boolean
316dri2_surface_swap_buffers(struct native_surface *nsurf, int num_rects,
317                          const int *rects)
318{
319   struct dri2_surface *dri2surf = dri2_surface(nsurf);
320   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
321
322   /* copy to front buffer */
323   if (dri2surf->have_back) {
324      if (num_rects > 0)
325         x11_drawable_copy_buffers_region(dri2dpy->xscr, dri2surf->drawable,
326               num_rects, rects,
327               DRI2BufferBackLeft, DRI2BufferFrontLeft);
328      else
329         x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
330               0, 0, dri2surf->width, dri2surf->height,
331               DRI2BufferBackLeft, DRI2BufferFrontLeft);
332   }
333
334   /* and update fake front buffer */
335   if (dri2surf->have_fake) {
336      if (num_rects > 0)
337         x11_drawable_copy_buffers_region(dri2dpy->xscr, dri2surf->drawable,
338               num_rects, rects,
339               DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
340      else
341         x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
342               0, 0, dri2surf->width, dri2surf->height,
343               DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
344   }
345
346   /* force buffers to be updated in next validation call */
347   if (!dri2_surface_receive_events(&dri2surf->base)) {
348      dri2surf->server_stamp++;
349      dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
350            &dri2surf->base, dri2surf->server_stamp);
351   }
352
353   return TRUE;
354}
355
356static boolean
357dri2_surface_present(struct native_surface *nsurf,
358                     const struct native_present_control *ctrl)
359{
360   boolean ret;
361
362   if (ctrl->swap_interval)
363      return FALSE;
364
365   switch (ctrl->natt) {
366   case NATIVE_ATTACHMENT_FRONT_LEFT:
367      ret = dri2_surface_flush_frontbuffer(nsurf);
368      break;
369   case NATIVE_ATTACHMENT_BACK_LEFT:
370      ret = dri2_surface_swap_buffers(nsurf, ctrl->num_rects, ctrl->rects);
371      break;
372   default:
373      ret = FALSE;
374      break;
375   }
376
377   return ret;
378}
379
380static boolean
381dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
382                      unsigned int *seq_num, struct pipe_resource **textures,
383                      int *width, int *height)
384{
385   struct dri2_surface *dri2surf = dri2_surface(nsurf);
386
387   if (dri2surf->server_stamp != dri2surf->client_stamp ||
388       (dri2surf->valid_mask & attachment_mask) != attachment_mask) {
389      if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
390         return FALSE;
391   }
392
393   if (seq_num)
394      *seq_num = dri2surf->client_stamp;
395
396   if (textures) {
397      int att;
398      for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
399         if (native_attachment_mask_test(attachment_mask, att)) {
400            struct pipe_resource *ptex = dri2surf->textures[att];
401
402            textures[att] = NULL;
403            pipe_resource_reference(&textures[att], ptex);
404         }
405      }
406   }
407
408   if (width)
409      *width = dri2surf->width;
410   if (height)
411      *height = dri2surf->height;
412
413   return TRUE;
414}
415
416static void
417dri2_surface_wait(struct native_surface *nsurf)
418{
419   struct dri2_surface *dri2surf = dri2_surface(nsurf);
420   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
421
422   if (dri2surf->have_fake) {
423      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
424            0, 0, dri2surf->width, dri2surf->height,
425            DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
426   }
427}
428
429static void
430dri2_surface_destroy(struct native_surface *nsurf)
431{
432   struct dri2_surface *dri2surf = dri2_surface(nsurf);
433   int i;
434
435   if (dri2surf->last_xbufs)
436      FREE(dri2surf->last_xbufs);
437
438   for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
439      struct pipe_resource *ptex = dri2surf->textures[i];
440      pipe_resource_reference(&ptex, NULL);
441   }
442
443   if (dri2surf->drawable) {
444      x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr,
445            dri2surf->drawable, FALSE);
446
447      util_hash_table_remove(dri2surf->dri2dpy->surfaces,
448            (void *) dri2surf->drawable);
449   }
450   FREE(dri2surf);
451}
452
453static struct dri2_surface *
454dri2_display_create_surface(struct native_display *ndpy,
455                            Drawable drawable,
456                            enum pipe_format color_format)
457{
458   struct dri2_display *dri2dpy = dri2_display(ndpy);
459   struct dri2_surface *dri2surf;
460
461   dri2surf = CALLOC_STRUCT(dri2_surface);
462   if (!dri2surf)
463      return NULL;
464
465   dri2surf->dri2dpy = dri2dpy;
466   dri2surf->drawable = drawable;
467   dri2surf->color_format = color_format;
468
469   dri2surf->base.destroy = dri2_surface_destroy;
470   dri2surf->base.present = dri2_surface_present;
471   dri2surf->base.validate = dri2_surface_validate;
472   dri2surf->base.wait = dri2_surface_wait;
473
474   if (drawable) {
475      x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
476      /* initialize the geometry */
477      dri2_surface_update_buffers(&dri2surf->base, 0x0);
478
479      util_hash_table_set(dri2surf->dri2dpy->surfaces,
480            (void *) dri2surf->drawable, (void *) &dri2surf->base);
481   }
482
483   return dri2surf;
484}
485
486static struct native_surface *
487dri2_display_create_window_surface(struct native_display *ndpy,
488                                   EGLNativeWindowType win,
489                                   const struct native_config *nconf)
490{
491   struct dri2_surface *dri2surf;
492
493   dri2surf = dri2_display_create_surface(ndpy,
494         (Drawable) win, nconf->color_format);
495   return (dri2surf) ? &dri2surf->base : NULL;
496}
497
498static struct native_surface *
499dri2_display_create_pixmap_surface(struct native_display *ndpy,
500                                   EGLNativePixmapType pix,
501                                   const struct native_config *nconf)
502{
503   struct dri2_surface *dri2surf;
504
505   if (!nconf) {
506      struct dri2_display *dri2dpy = dri2_display(ndpy);
507      uint depth, nconf_depth;
508      int i;
509
510      depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
511      for (i = 0; i < dri2dpy->num_configs; i++) {
512         nconf_depth = util_format_get_blocksizebits(
513               dri2dpy->configs[i].base.color_format);
514         /* simple depth match for now */
515         if (depth == nconf_depth ||
516             (depth == 24 && depth + 8 == nconf_depth)) {
517            nconf = &dri2dpy->configs[i].base;
518            break;
519         }
520      }
521
522      if (!nconf)
523         return NULL;
524   }
525
526   dri2surf = dri2_display_create_surface(ndpy,
527         (Drawable) pix, nconf->color_format);
528   return (dri2surf) ? &dri2surf->base : NULL;
529}
530
531static int
532choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32])
533{
534   int count = 0;
535
536   switch (mode->rgbBits) {
537   case 32:
538      formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
539      formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
540      break;
541   case 24:
542      formats[count++] = PIPE_FORMAT_B8G8R8X8_UNORM;
543      formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM;
544      formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
545      formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
546      break;
547   case 16:
548      formats[count++] = PIPE_FORMAT_B5G6R5_UNORM;
549      break;
550   default:
551      break;
552   }
553
554   return count;
555}
556
557static boolean
558is_format_supported(struct pipe_screen *screen,
559                    enum pipe_format fmt, unsigned sample_count, boolean is_color)
560{
561   return screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D, sample_count,
562         (is_color) ? PIPE_BIND_RENDER_TARGET :
563         PIPE_BIND_DEPTH_STENCIL);
564}
565
566static boolean
567dri2_display_convert_config(struct native_display *ndpy,
568                            const __GLcontextModes *mode,
569                            struct native_config *nconf)
570{
571   enum pipe_format formats[32];
572   int num_formats, i;
573   int sample_count = 0;
574
575   if (!(mode->renderType & GLX_RGBA_BIT) || !mode->rgbMode)
576      return FALSE;
577
578   /* only interested in native renderable configs */
579   if (!mode->xRenderable || !mode->drawableType)
580      return FALSE;
581
582   /* fast/slow configs are probably not relevant */
583   if (mode->visualRating == GLX_SLOW_CONFIG)
584      return FALSE;
585
586   nconf->buffer_mask = 1 << NATIVE_ATTACHMENT_FRONT_LEFT;
587   if (mode->doubleBufferMode)
588      nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_LEFT;
589   if (mode->stereoMode) {
590      nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_FRONT_RIGHT;
591      if (mode->doubleBufferMode)
592         nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_RIGHT;
593   }
594
595   /* choose color format */
596   num_formats = choose_color_format(mode, formats);
597   for (i = 0; i < num_formats; i++) {
598      if (is_format_supported(ndpy->screen, formats[i], sample_count, TRUE)) {
599         nconf->color_format = formats[i];
600         break;
601      }
602   }
603   if (nconf->color_format == PIPE_FORMAT_NONE)
604      return FALSE;
605
606   if ((mode->drawableType & GLX_WINDOW_BIT) && mode->visualID)
607      nconf->window_bit = TRUE;
608   if (mode->drawableType & GLX_PIXMAP_BIT)
609      nconf->pixmap_bit = TRUE;
610
611   nconf->native_visual_id = mode->visualID;
612   switch (mode->visualType) {
613   case GLX_TRUE_COLOR:
614      nconf->native_visual_type = TrueColor;
615      break;
616   case GLX_DIRECT_COLOR:
617      nconf->native_visual_type = DirectColor;
618      break;
619   case GLX_PSEUDO_COLOR:
620      nconf->native_visual_type = PseudoColor;
621      break;
622   case GLX_STATIC_COLOR:
623      nconf->native_visual_type = StaticColor;
624      break;
625   case GLX_GRAY_SCALE:
626      nconf->native_visual_type = GrayScale;
627      break;
628   case GLX_STATIC_GRAY:
629      nconf->native_visual_type = StaticGray;
630      break;
631   }
632   nconf->level = mode->level;
633
634   if (mode->transparentPixel == GLX_TRANSPARENT_RGB) {
635      nconf->transparent_rgb = TRUE;
636      nconf->transparent_rgb_values[0] = mode->transparentRed;
637      nconf->transparent_rgb_values[1] = mode->transparentGreen;
638      nconf->transparent_rgb_values[2] = mode->transparentBlue;
639   }
640
641   return TRUE;
642}
643
644static const struct native_config **
645dri2_display_get_configs(struct native_display *ndpy, int *num_configs)
646{
647   struct dri2_display *dri2dpy = dri2_display(ndpy);
648   const struct native_config **configs;
649   int i;
650
651   /* first time */
652   if (!dri2dpy->configs) {
653      const __GLcontextModes *modes;
654      int num_modes, count;
655
656      modes = x11_screen_get_glx_configs(dri2dpy->xscr);
657      if (!modes)
658         return NULL;
659      num_modes = x11_context_modes_count(modes);
660
661      dri2dpy->configs = CALLOC(num_modes, sizeof(*dri2dpy->configs));
662      if (!dri2dpy->configs)
663         return NULL;
664
665      count = 0;
666      for (i = 0; i < num_modes; i++) {
667         struct native_config *nconf = &dri2dpy->configs[count].base;
668
669         if (dri2_display_convert_config(&dri2dpy->base, modes, nconf)) {
670            int j;
671            /* look for duplicates */
672            for (j = 0; j < count; j++) {
673               if (memcmp(&dri2dpy->configs[j], nconf, sizeof(*nconf)) == 0)
674                  break;
675            }
676            if (j == count)
677               count++;
678         }
679         modes = modes->next;
680      }
681
682      dri2dpy->num_configs = count;
683   }
684
685   configs = MALLOC(dri2dpy->num_configs * sizeof(*configs));
686   if (configs) {
687      for (i = 0; i < dri2dpy->num_configs; i++)
688         configs[i] = (const struct native_config *) &dri2dpy->configs[i];
689      if (num_configs)
690         *num_configs = dri2dpy->num_configs;
691   }
692
693   return configs;
694}
695
696static boolean
697dri2_display_get_pixmap_format(struct native_display *ndpy,
698                               EGLNativePixmapType pix,
699                               enum pipe_format *format)
700{
701   struct dri2_display *dri2dpy = dri2_display(ndpy);
702   boolean ret = EGL_TRUE;
703   uint depth;
704
705   depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
706   switch (depth) {
707   case 32:
708   case 24:
709      *format = PIPE_FORMAT_B8G8R8A8_UNORM;
710      break;
711   case 16:
712      *format = PIPE_FORMAT_B5G6R5_UNORM;
713      break;
714   default:
715      *format = PIPE_FORMAT_NONE;
716      ret = EGL_FALSE;
717      break;
718   }
719
720   return ret;
721}
722
723static int
724dri2_display_get_param(struct native_display *ndpy,
725                       enum native_param_type param)
726{
727   int val;
728
729   switch (param) {
730   case NATIVE_PARAM_USE_NATIVE_BUFFER:
731      /* DRI2GetBuffers uses the native buffers */
732      val = TRUE;
733      break;
734   case NATIVE_PARAM_PRESERVE_BUFFER:
735      /* DRI2CopyRegion is used */
736      val = TRUE;
737      break;
738   case NATIVE_PARAM_PRESENT_REGION:
739      val = TRUE;
740      break;
741   case NATIVE_PARAM_MAX_SWAP_INTERVAL:
742   default:
743      val = 0;
744      break;
745   }
746
747   return val;
748}
749
750static void
751dri2_display_destroy(struct native_display *ndpy)
752{
753   struct dri2_display *dri2dpy = dri2_display(ndpy);
754
755   if (dri2dpy->configs)
756      FREE(dri2dpy->configs);
757
758   if (dri2dpy->base.screen)
759      dri2dpy->base.screen->destroy(dri2dpy->base.screen);
760
761   if (dri2dpy->surfaces)
762      util_hash_table_destroy(dri2dpy->surfaces);
763
764   if (dri2dpy->xscr)
765      x11_screen_destroy(dri2dpy->xscr);
766   if (dri2dpy->own_dpy)
767      XCloseDisplay(dri2dpy->dpy);
768   FREE(dri2dpy);
769}
770
771static void
772dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable,
773                                void *user_data)
774{
775   struct native_display *ndpy = (struct native_display* ) user_data;
776   struct dri2_display *dri2dpy = dri2_display(ndpy);
777   struct native_surface *nsurf;
778   struct dri2_surface *dri2surf;
779
780   nsurf = (struct native_surface *)
781      util_hash_table_get(dri2dpy->surfaces, (void *) drawable);
782   if (!nsurf)
783      return;
784
785   dri2surf = dri2_surface(nsurf);
786
787   dri2surf->server_stamp++;
788   dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
789         &dri2surf->base, dri2surf->server_stamp);
790}
791
792/**
793 * Initialize DRI2 and pipe screen.
794 */
795static boolean
796dri2_display_init_screen(struct native_display *ndpy)
797{
798   struct dri2_display *dri2dpy = dri2_display(ndpy);
799   int fd;
800
801   if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) ||
802       !x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_GLX)) {
803      _eglLog(_EGL_WARNING, "GLX/DRI2 is not supported");
804      return FALSE;
805   }
806
807   dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr,
808         &dri2dpy->dri_major, &dri2dpy->dri_minor);
809
810   fd = x11_screen_enable_dri2(dri2dpy->xscr,
811         dri2_display_invalidate_buffers, &dri2dpy->base);
812   if (fd < 0)
813      return FALSE;
814
815   dri2dpy->base.screen =
816      dri2dpy->event_handler->new_drm_screen(&dri2dpy->base,
817            dri2dpy->dri_driver, fd);
818   if (!dri2dpy->base.screen) {
819      _eglLog(_EGL_DEBUG, "failed to create DRM screen");
820      return FALSE;
821   }
822
823   return TRUE;
824}
825
826static unsigned
827dri2_display_hash_table_hash(void *key)
828{
829   XID drawable = pointer_to_uintptr(key);
830   return (unsigned) drawable;
831}
832
833static int
834dri2_display_hash_table_compare(void *key1, void *key2)
835{
836   return ((char *) key1 - (char *) key2);
837}
838
839#ifdef HAVE_WAYLAND_BACKEND
840
841static int
842dri2_display_authenticate(void *user_data, uint32_t magic)
843{
844   struct native_display *ndpy = user_data;
845   struct dri2_display *dri2dpy = dri2_display(ndpy);
846
847   return x11_screen_authenticate(dri2dpy->xscr, magic);
848}
849
850static struct wayland_drm_callbacks wl_drm_callbacks = {
851   dri2_display_authenticate,
852   egl_g3d_wl_drm_helper_reference_buffer,
853   egl_g3d_wl_drm_helper_unreference_buffer
854};
855
856static boolean
857dri2_display_bind_wayland_display(struct native_display *ndpy,
858                                  struct wl_display *wl_dpy)
859{
860   struct dri2_display *dri2dpy = dri2_display(ndpy);
861
862   if (dri2dpy->wl_server_drm)
863      return FALSE;
864
865   dri2dpy->wl_server_drm = wayland_drm_init(wl_dpy,
866         x11_screen_get_device_name(dri2dpy->xscr),
867         &wl_drm_callbacks, ndpy);
868
869   if (!dri2dpy->wl_server_drm)
870      return FALSE;
871
872   return TRUE;
873}
874
875static boolean
876dri2_display_unbind_wayland_display(struct native_display *ndpy,
877                                    struct wl_display *wl_dpy)
878{
879   struct dri2_display *dri2dpy = dri2_display(ndpy);
880
881   if (!dri2dpy->wl_server_drm)
882      return FALSE;
883
884   wayland_drm_uninit(dri2dpy->wl_server_drm);
885   dri2dpy->wl_server_drm = NULL;
886
887   return TRUE;
888}
889
890static struct native_display_wayland_bufmgr dri2_display_wayland_bufmgr = {
891   dri2_display_bind_wayland_display,
892   dri2_display_unbind_wayland_display,
893   egl_g3d_wl_drm_common_wl_buffer_get_resource,
894   egl_g3d_wl_drm_common_query_buffer
895};
896
897#endif /* HAVE_WAYLAND_BACKEND */
898
899struct native_display *
900x11_create_dri2_display(Display *dpy,
901                        const struct native_event_handler *event_handler)
902{
903   struct dri2_display *dri2dpy;
904
905   dri2dpy = CALLOC_STRUCT(dri2_display);
906   if (!dri2dpy)
907      return NULL;
908
909   dri2dpy->event_handler = event_handler;
910
911   dri2dpy->dpy = dpy;
912   if (!dri2dpy->dpy) {
913      dri2dpy->dpy = XOpenDisplay(NULL);
914      if (!dri2dpy->dpy) {
915         dri2_display_destroy(&dri2dpy->base);
916         return NULL;
917      }
918      dri2dpy->own_dpy = TRUE;
919   }
920
921   dri2dpy->xscr_number = DefaultScreen(dri2dpy->dpy);
922   dri2dpy->xscr = x11_screen_create(dri2dpy->dpy, dri2dpy->xscr_number);
923   if (!dri2dpy->xscr) {
924      dri2_display_destroy(&dri2dpy->base);
925      return NULL;
926   }
927
928   dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash,
929         dri2_display_hash_table_compare);
930   if (!dri2dpy->surfaces) {
931      dri2_display_destroy(&dri2dpy->base);
932      return NULL;
933   }
934
935   dri2dpy->base.init_screen = dri2_display_init_screen;
936   dri2dpy->base.destroy = dri2_display_destroy;
937   dri2dpy->base.get_param = dri2_display_get_param;
938   dri2dpy->base.get_configs = dri2_display_get_configs;
939   dri2dpy->base.get_pixmap_format = dri2_display_get_pixmap_format;
940   dri2dpy->base.copy_to_pixmap = native_display_copy_to_pixmap;
941   dri2dpy->base.create_window_surface = dri2_display_create_window_surface;
942   dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface;
943#ifdef HAVE_WAYLAND_BACKEND
944   dri2dpy->base.wayland_bufmgr = &dri2_display_wayland_bufmgr;
945#endif
946
947   return &dri2dpy->base;
948}
949
950#else /* GLX_DIRECT_RENDERING */
951
952struct native_display *
953x11_create_dri2_display(Display *dpy,
954                        const struct native_event_handler *event_handler)
955{
956   return NULL;
957}
958
959#endif /* GLX_DIRECT_RENDERING */
960