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