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