7f0acf3238c0fbe6d253badc6311d0ac08312292
[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_texture *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_texture 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_texture_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.tex_usage = PIPE_TEXTURE_USAGE_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->texture_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];
196    int num_ins, num_outs, att;
197    struct x11_drawable_buffer *xbufs;
198
199    /* prepare the attachments */
200    num_ins = 0;
201    for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
202       if (native_attachment_mask_test(buffer_mask, att)) {
203          unsigned int dri2att;
204
205          switch (att) {
206          case NATIVE_ATTACHMENT_FRONT_LEFT:
207             dri2att = DRI2BufferFrontLeft;
208             break;
209          case NATIVE_ATTACHMENT_BACK_LEFT:
210             dri2att = DRI2BufferBackLeft;
211             break;
212          case NATIVE_ATTACHMENT_FRONT_RIGHT:
213             dri2att = DRI2BufferFrontRight;
214             break;
215          case NATIVE_ATTACHMENT_BACK_RIGHT:
216             dri2att = DRI2BufferBackRight;
217             break;
218          default:
219             assert(0);
220             dri2att = 0;
221             break;
222          }
223
224          dri2atts[num_ins] = dri2att;
225          num_ins++;
226       }
227    }
228
229    xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable,
230                                     &dri2surf->width, &dri2surf->height,
231                                     dri2atts, FALSE, num_ins, &num_outs);
232
233    /* we should be able to do better... */
234    if (xbufs && dri2surf->last_num_xbufs == num_outs &&
235        memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) {
236       free(xbufs);
237       dri2surf->client_stamp = dri2surf->server_stamp;
238       return;
239    }
240
241    dri2_surface_process_drawable_buffers(&dri2surf->base, xbufs, num_outs);
242
243    dri2surf->server_stamp++;
244    dri2surf->client_stamp = dri2surf->server_stamp;
245
246    if (dri2surf->last_xbufs)
247       free(dri2surf->last_xbufs);
248    dri2surf->last_xbufs = xbufs;
249    dri2surf->last_num_xbufs = num_outs;
250 }
251
252 /**
253  * Update the buffers of the surface.  This is a slow function due to the
254  * round-trip to the server.
255  */
256 static boolean
257 dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
258 {
259    struct dri2_surface *dri2surf = dri2_surface(nsurf);
260
261    dri2_surface_get_buffers(&dri2surf->base, buffer_mask);
262
263    return ((dri2surf->valid_mask & buffer_mask) == buffer_mask);
264 }
265
266 /**
267  * Return TRUE if the surface receives DRI2_InvalidateBuffers events.
268  */
269 static INLINE boolean
270 dri2_surface_receive_events(struct native_surface *nsurf)
271 {
272    struct dri2_surface *dri2surf = dri2_surface(nsurf);
273    return (dri2surf->dri2dpy->dri_minor >= 3);
274 }
275
276 static boolean
277 dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
278 {
279    struct dri2_surface *dri2surf = dri2_surface(nsurf);
280    struct dri2_display *dri2dpy = dri2surf->dri2dpy;
281
282    /* copy to real front buffer */
283    if (dri2surf->have_fake)
284       x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
285             0, 0, dri2surf->width, dri2surf->height,
286             DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
287
288    /* force buffers to be updated in next validation call */
289    if (!dri2_surface_receive_events(&dri2surf->base)) {
290       dri2surf->server_stamp++;
291       dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
292             &dri2surf->base, dri2surf->server_stamp);
293    }
294
295    return TRUE;
296 }
297
298 static boolean
299 dri2_surface_swap_buffers(struct native_surface *nsurf)
300 {
301    struct dri2_surface *dri2surf = dri2_surface(nsurf);
302    struct dri2_display *dri2dpy = dri2surf->dri2dpy;
303
304    /* copy to front buffer */
305    if (dri2surf->have_back)
306       x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
307             0, 0, dri2surf->width, dri2surf->height,
308             DRI2BufferBackLeft, DRI2BufferFrontLeft);
309
310    /* and update fake front buffer */
311    if (dri2surf->have_fake)
312       x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
313             0, 0, dri2surf->width, dri2surf->height,
314             DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
315
316    /* force buffers to be updated in next validation call */
317    if (!dri2_surface_receive_events(&dri2surf->base)) {
318       dri2surf->server_stamp++;
319       dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
320             &dri2surf->base, dri2surf->server_stamp);
321    }
322
323    return TRUE;
324 }
325
326 static boolean
327 dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
328                       unsigned int *seq_num, struct pipe_texture **textures,
329                       int *width, int *height)
330 {
331    struct dri2_surface *dri2surf = dri2_surface(nsurf);
332
333    if (dri2surf->server_stamp != dri2surf->client_stamp ||
334        (dri2surf->valid_mask & attachment_mask) != attachment_mask) {
335       if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
336          return FALSE;
337    }
338
339    if (seq_num)
340       *seq_num = dri2surf->client_stamp;
341
342    if (textures) {
343       int att;
344       for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
345          if (native_attachment_mask_test(attachment_mask, att)) {
346             struct pipe_texture *ptex = dri2surf->textures[att];
347
348             textures[att] = NULL;
349             pipe_texture_reference(&textures[att], ptex);
350          }
351       }
352    }
353
354    if (width)
355       *width = dri2surf->width;
356    if (height)
357       *height = dri2surf->height;
358
359    return TRUE;
360 }
361
362 static void
363 dri2_surface_wait(struct native_surface *nsurf)
364 {
365    struct dri2_surface *dri2surf = dri2_surface(nsurf);
366    struct dri2_display *dri2dpy = dri2surf->dri2dpy;
367
368    if (dri2surf->have_fake) {
369       x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
370             0, 0, dri2surf->width, dri2surf->height,
371             DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
372    }
373 }
374
375 static void
376 dri2_surface_destroy(struct native_surface *nsurf)
377 {
378    struct dri2_surface *dri2surf = dri2_surface(nsurf);
379    int i;
380
381    if (dri2surf->last_xbufs)
382       free(dri2surf->last_xbufs);
383
384    for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
385       struct pipe_texture *ptex = dri2surf->textures[i];
386       pipe_texture_reference(&ptex, NULL);
387    }
388
389    if (dri2surf->drawable) {
390       x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr,
391             dri2surf->drawable, FALSE);
392
393       util_hash_table_remove(dri2surf->dri2dpy->surfaces,
394             (void *) dri2surf->drawable);
395    }
396    free(dri2surf);
397 }
398
399 static struct dri2_surface *
400 dri2_display_create_surface(struct native_display *ndpy,
401                             enum dri2_surface_type type,
402                             Drawable drawable,
403                             const struct native_config *nconf)
404 {
405    struct dri2_display *dri2dpy = dri2_display(ndpy);
406    struct dri2_config *dri2conf = dri2_config(nconf);
407    struct dri2_surface *dri2surf;
408
409    dri2surf = CALLOC_STRUCT(dri2_surface);
410    if (!dri2surf)
411       return NULL;
412
413    dri2surf->dri2dpy = dri2dpy;
414    dri2surf->type = type;
415    dri2surf->drawable = drawable;
416    dri2surf->color_format = dri2conf->base.color_format;
417
418    dri2surf->base.destroy = dri2_surface_destroy;
419    dri2surf->base.swap_buffers = dri2_surface_swap_buffers;
420    dri2surf->base.flush_frontbuffer = dri2_surface_flush_frontbuffer;
421    dri2surf->base.validate = dri2_surface_validate;
422    dri2surf->base.wait = dri2_surface_wait;
423
424    if (drawable) {
425       x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
426       /* initialize the geometry */
427       dri2_surface_update_buffers(&dri2surf->base, 0x0);
428
429       util_hash_table_set(dri2surf->dri2dpy->surfaces,
430             (void *) dri2surf->drawable, (void *) &dri2surf->base);
431    }
432
433    return dri2surf;
434 }
435
436 static struct native_surface *
437 dri2_display_create_window_surface(struct native_display *ndpy,
438                                    EGLNativeWindowType win,
439                                    const struct native_config *nconf)
440 {
441    struct dri2_surface *dri2surf;
442
443    dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_WINDOW,
444          (Drawable) win, nconf);
445    return (dri2surf) ? &dri2surf->base : NULL;
446 }
447
448 static struct native_surface *
449 dri2_display_create_pixmap_surface(struct native_display *ndpy,
450                                    EGLNativePixmapType pix,
451                                    const struct native_config *nconf)
452 {
453    struct dri2_surface *dri2surf;
454
455    dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_PIXMAP,
456          (Drawable) pix, nconf);
457    return (dri2surf) ? &dri2surf->base : NULL;
458 }
459
460 static int
461 choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32])
462 {
463    int count = 0;
464
465    switch (mode->rgbBits) {
466    case 32:
467       formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
468       formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
469       break;
470    case 24:
471       formats[count++] = PIPE_FORMAT_B8G8R8X8_UNORM;
472       formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM;
473       formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
474       formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
475       break;
476    case 16:
477       formats[count++] = PIPE_FORMAT_B5G6R5_UNORM;
478       break;
479    default:
480       break;
481    }
482
483    return count;
484 }
485
486 static int
487 choose_depth_stencil_format(const __GLcontextModes *mode,
488                             enum pipe_format formats[32])
489 {
490    int count = 0;
491
492    switch (mode->depthBits) {
493    case 32:
494       formats[count++] = PIPE_FORMAT_Z32_UNORM;
495       break;
496    case 24:
497       if (mode->stencilBits) {
498          formats[count++] = PIPE_FORMAT_Z24_UNORM_S8_USCALED;
499          formats[count++] = PIPE_FORMAT_S8_USCALED_Z24_UNORM;
500       }
501       else {
502          formats[count++] = PIPE_FORMAT_Z24X8_UNORM;
503          formats[count++] = PIPE_FORMAT_X8Z24_UNORM;
504       }
505       break;
506    case 16:
507       formats[count++] = PIPE_FORMAT_Z16_UNORM;
508       break;
509    default:
510       break;
511    }
512
513    return count;
514 }
515
516 static boolean
517 is_format_supported(struct pipe_screen *screen,
518                     enum pipe_format fmt, boolean is_color)
519 {
520    return screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D,
521          (is_color) ? PIPE_TEXTURE_USAGE_RENDER_TARGET :
522          PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0);
523 }
524
525 static boolean
526 dri2_display_convert_config(struct native_display *ndpy,
527                             const __GLcontextModes *mode,
528                             struct native_config *nconf)
529 {
530    enum pipe_format formats[32];
531    int num_formats, i;
532
533    if (!(mode->renderType & GLX_RGBA_BIT) || !mode->rgbMode)
534       return FALSE;
535
536    /* skip single-buffered configs */
537    if (!mode->doubleBufferMode)
538       return FALSE;
539
540    nconf->mode = *mode;
541    nconf->mode.renderType = GLX_RGBA_BIT;
542    nconf->mode.rgbMode = TRUE;
543    /* pbuffer is always supported */
544    nconf->mode.drawableType |= GLX_PBUFFER_BIT;
545    /* the swap method is always copy */
546    nconf->mode.swapMethod = GLX_SWAP_COPY_OML;
547
548    /* fix up */
549    nconf->mode.rgbBits =
550       nconf->mode.redBits + nconf->mode.greenBits +
551       nconf->mode.blueBits + nconf->mode.alphaBits;
552    if (!(nconf->mode.drawableType & GLX_WINDOW_BIT)) {
553       nconf->mode.visualID = 0;
554       nconf->mode.visualType = GLX_NONE;
555    }
556    if (!(nconf->mode.drawableType & GLX_PBUFFER_BIT)) {
557       nconf->mode.bindToTextureRgb = FALSE;
558       nconf->mode.bindToTextureRgba = FALSE;
559    }
560
561    nconf->color_format = PIPE_FORMAT_NONE;
562    nconf->depth_format = PIPE_FORMAT_NONE;
563    nconf->stencil_format = PIPE_FORMAT_NONE;
564
565    /* choose color format */
566    num_formats = choose_color_format(mode, formats);
567    for (i = 0; i < num_formats; i++) {
568       if (is_format_supported(ndpy->screen, formats[i], TRUE)) {
569          nconf->color_format = formats[i];
570          break;
571       }
572    }
573    if (nconf->color_format == PIPE_FORMAT_NONE)
574       return FALSE;
575
576    /* choose depth/stencil format */
577    num_formats = choose_depth_stencil_format(mode, formats);
578    for (i = 0; i < num_formats; i++) {
579       if (is_format_supported(ndpy->screen, formats[i], FALSE)) {
580          nconf->depth_format = formats[i];
581          nconf->stencil_format = formats[i];
582          break;
583       }
584    }
585    if ((nconf->mode.depthBits && nconf->depth_format == PIPE_FORMAT_NONE) ||
586        (nconf->mode.stencilBits && nconf->stencil_format == PIPE_FORMAT_NONE))
587       return FALSE;
588
589    return TRUE;
590 }
591
592 static const struct native_config **
593 dri2_display_get_configs(struct native_display *ndpy, int *num_configs)
594 {
595    struct dri2_display *dri2dpy = dri2_display(ndpy);
596    const struct native_config **configs;
597    int i;
598
599    /* first time */
600    if (!dri2dpy->configs) {
601       const __GLcontextModes *modes;
602       int num_modes, count;
603
604       modes = x11_screen_get_glx_configs(dri2dpy->xscr);
605       if (!modes)
606          return NULL;
607       num_modes = x11_context_modes_count(modes);
608
609       dri2dpy->configs = calloc(num_modes, sizeof(*dri2dpy->configs));
610       if (!dri2dpy->configs)
611          return NULL;
612
613       count = 0;
614       for (i = 0; i < num_modes; i++) {
615          struct native_config *nconf = &dri2dpy->configs[count].base;
616          if (dri2_display_convert_config(&dri2dpy->base, modes, nconf))
617             count++;
618          modes = modes->next;
619       }
620
621       dri2dpy->num_configs = count;
622    }
623
624    configs = malloc(dri2dpy->num_configs * sizeof(*configs));
625    if (configs) {
626       for (i = 0; i < dri2dpy->num_configs; i++)
627          configs[i] = (const struct native_config *) &dri2dpy->configs[i];
628       if (num_configs)
629          *num_configs = dri2dpy->num_configs;
630    }
631
632    return configs;
633 }
634
635 static boolean
636 dri2_display_is_pixmap_supported(struct native_display *ndpy,
637                                  EGLNativePixmapType pix,
638                                  const struct native_config *nconf)
639 {
640    struct dri2_display *dri2dpy = dri2_display(ndpy);
641    uint depth, nconf_depth;
642
643    depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
644    nconf_depth = util_format_get_blocksizebits(nconf->color_format);
645
646    /* simple depth match for now */
647    return (depth == nconf_depth || (depth == 24 && depth + 8 == nconf_depth));
648 }
649
650 static int
651 dri2_display_get_param(struct native_display *ndpy,
652                        enum native_param_type param)
653 {
654    int val;
655
656    switch (param) {
657    case NATIVE_PARAM_USE_NATIVE_BUFFER:
658       /* DRI2GetBuffers use the native buffers */
659       val = TRUE;
660       break;
661    default:
662       val = 0;
663       break;
664    }
665
666    return val;
667 }
668
669 static void
670 dri2_display_destroy(struct native_display *ndpy)
671 {
672    struct dri2_display *dri2dpy = dri2_display(ndpy);
673
674    if (dri2dpy->configs)
675       free(dri2dpy->configs);
676
677    if (dri2dpy->base.screen)
678       dri2dpy->base.screen->destroy(dri2dpy->base.screen);
679
680    if (dri2dpy->surfaces)
681       util_hash_table_destroy(dri2dpy->surfaces);
682
683    if (dri2dpy->xscr)
684       x11_screen_destroy(dri2dpy->xscr);
685    if (dri2dpy->own_dpy)
686       XCloseDisplay(dri2dpy->dpy);
687    if (dri2dpy->api && dri2dpy->api->destroy)
688       dri2dpy->api->destroy(dri2dpy->api);
689    free(dri2dpy);
690 }
691
692 static void
693 dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable,
694                                 void *user_data)
695 {
696    struct native_display *ndpy = (struct native_display* ) user_data;
697    struct dri2_display *dri2dpy = dri2_display(ndpy);
698    struct native_surface *nsurf;
699    struct dri2_surface *dri2surf;
700
701    nsurf = (struct native_surface *)
702       util_hash_table_get(dri2dpy->surfaces, (void *) drawable);
703    if (!nsurf)
704       return;
705
706    dri2surf = dri2_surface(nsurf);
707
708    dri2surf->server_stamp++;
709    dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
710          &dri2surf->base, dri2surf->server_stamp);
711 }
712
713 /**
714  * Initialize DRI2 and pipe screen.
715  */
716 static boolean
717 dri2_display_init_screen(struct native_display *ndpy)
718 {
719    struct dri2_display *dri2dpy = dri2_display(ndpy);
720    const char *driver = dri2dpy->api->name;
721    struct drm_create_screen_arg arg;
722    int fd;
723
724    if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) ||
725        !x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_GLX)) {
726       _eglLog(_EGL_WARNING, "GLX/DRI2 is not supported");
727       return FALSE;
728    }
729
730    dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr,
731          &dri2dpy->dri_major, &dri2dpy->dri_minor);
732    if (!dri2dpy->dri_driver || !driver ||
733        strcmp(dri2dpy->dri_driver, driver) != 0) {
734       _eglLog(_EGL_WARNING, "Driver mismatch: %s != %s",
735             dri2dpy->dri_driver, dri2dpy->api->name);
736       return FALSE;
737    }
738
739    fd = x11_screen_enable_dri2(dri2dpy->xscr,
740          dri2_display_invalidate_buffers, &dri2dpy->base);
741    if (fd < 0)
742       return FALSE;
743
744    memset(&arg, 0, sizeof(arg));
745    arg.mode = DRM_CREATE_NORMAL;
746    dri2dpy->base.screen = dri2dpy->api->create_screen(dri2dpy->api, fd, &arg);
747    if (!dri2dpy->base.screen) {
748       _eglLog(_EGL_WARNING, "failed to create DRM screen");
749       return FALSE;
750    }
751
752    return TRUE;
753 }
754
755 static unsigned
756 dri2_display_hash_table_hash(void *key)
757 {
758    XID drawable = pointer_to_uintptr(key);
759    return (unsigned) drawable;
760 }
761
762 static int
763 dri2_display_hash_table_compare(void *key1, void *key2)
764 {
765    return (key1 - key2);
766 }
767
768 struct native_display *
769 x11_create_dri2_display(EGLNativeDisplayType dpy,
770                         struct native_event_handler *event_handler,
771                         struct drm_api *api)
772 {
773    struct dri2_display *dri2dpy;
774
775    dri2dpy = CALLOC_STRUCT(dri2_display);
776    if (!dri2dpy)
777       return NULL;
778
779    dri2dpy->event_handler = event_handler;
780    dri2dpy->api = api;
781
782    dri2dpy->dpy = dpy;
783    if (!dri2dpy->dpy) {
784       dri2dpy->dpy = XOpenDisplay(NULL);
785       if (!dri2dpy->dpy) {
786          dri2_display_destroy(&dri2dpy->base);
787          return NULL;
788       }
789       dri2dpy->own_dpy = TRUE;
790    }
791
792    dri2dpy->xscr_number = DefaultScreen(dri2dpy->dpy);
793    dri2dpy->xscr = x11_screen_create(dri2dpy->dpy, dri2dpy->xscr_number);
794    if (!dri2dpy->xscr) {
795       dri2_display_destroy(&dri2dpy->base);
796       return NULL;
797    }
798
799    if (!dri2_display_init_screen(&dri2dpy->base)) {
800       dri2_display_destroy(&dri2dpy->base);
801       return NULL;
802    }
803
804    dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash,
805          dri2_display_hash_table_compare);
806    if (!dri2dpy->surfaces) {
807       dri2_display_destroy(&dri2dpy->base);
808       return NULL;
809    }
810
811    dri2dpy->base.destroy = dri2_display_destroy;
812    dri2dpy->base.get_param = dri2_display_get_param;
813    dri2dpy->base.get_configs = dri2_display_get_configs;
814    dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported;
815    dri2dpy->base.create_window_surface = dri2_display_create_window_surface;
816    dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface;
817
818    return &dri2dpy->base;
819 }