st/egl: adapt to interface changes
[profile/ivi/mesa.git] / src / gallium / state_trackers / egl / x11 / native_dri2.c
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
41 enum dri2_surface_type {
42    DRI2_SURFACE_TYPE_WINDOW,
43    DRI2_SURFACE_TYPE_PIXMAP,
44 };
45
46 struct 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
65 struct 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
84 struct dri2_config {
85    struct native_config base;
86 };
87
88 static INLINE struct dri2_display *
89 dri2_display(const struct native_display *ndpy)
90 {
91    return (struct dri2_display *) ndpy;
92 }
93
94 static INLINE struct dri2_surface *
95 dri2_surface(const struct native_surface *nsurf)
96 {
97    return (struct dri2_surface *) nsurf;
98 }
99
100 static INLINE struct dri2_config *
101 dri2_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  */
109 static void
110 dri2_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  */
190 static void
191 dri2_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  */
269 static boolean
270 dri2_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  */
282 static INLINE boolean
283 dri2_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
289 static boolean
290 dri2_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
311 static boolean
312 dri2_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
339 static boolean
340 dri2_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
375 static void
376 dri2_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
388 static void
389 dri2_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
412 static struct dri2_surface *
413 dri2_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
449 static struct native_surface *
450 dri2_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
461 static struct native_surface *
462 dri2_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
473 static int
474 choose_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
499 static boolean
500 is_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
508 static boolean
509 dri2_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
570 static const struct native_config **
571 dri2_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
613 static boolean
614 dri2_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
628 static int
629 dri2_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
647 static void
648 dri2_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
670 static void
671 dri2_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  */
694 static boolean
695 dri2_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
730 static unsigned
731 dri2_display_hash_table_hash(void *key)
732 {
733    XID drawable = pointer_to_uintptr(key);
734    return (unsigned) drawable;
735 }
736
737 static int
738 dri2_display_hash_table_compare(void *key1, void *key2)
739 {
740    return (key1 - key2);
741 }
742
743 struct native_display *
744 x11_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 }