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