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