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