native_dri2.c revision ba81b0743efd978509b1931d7b4b93f37e8aeb5e
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.8
4 *
5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26#include "util/u_memory.h"
27#include "util/u_math.h"
28#include "util/u_format.h"
29#include "util/u_inlines.h"
30#include "util/u_hash_table.h"
31#include "pipe/p_compiler.h"
32#include "pipe/p_screen.h"
33#include "pipe/p_context.h"
34#include "pipe/p_state.h"
35#include "state_tracker/drm_api.h"
36#include "egllog.h"
37
38#include "native_x11.h"
39#include "x11_screen.h"
40
41enum dri2_surface_type {
42   DRI2_SURFACE_TYPE_WINDOW,
43   DRI2_SURFACE_TYPE_PIXMAP,
44};
45
46struct dri2_display {
47   struct native_display base;
48   Display *dpy;
49   boolean own_dpy;
50
51   struct native_event_handler *event_handler;
52
53   struct drm_api *api;
54   struct x11_screen *xscr;
55   int xscr_number;
56   const char *dri_driver;
57   int dri_major, dri_minor;
58
59   struct dri2_config *configs;
60   int num_configs;
61
62   struct util_hash_table *surfaces;
63};
64
65struct dri2_surface {
66   struct native_surface base;
67   Drawable drawable;
68   enum dri2_surface_type type;
69   enum pipe_format color_format;
70   struct dri2_display *dri2dpy;
71
72   unsigned int server_stamp;
73   unsigned int client_stamp;
74   int width, height;
75   struct pipe_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
84struct dri2_config {
85   struct native_config base;
86};
87
88static INLINE struct dri2_display *
89dri2_display(const struct native_display *ndpy)
90{
91   return (struct dri2_display *) ndpy;
92}
93
94static INLINE struct dri2_surface *
95dri2_surface(const struct native_surface *nsurf)
96{
97   return (struct dri2_surface *) nsurf;
98}
99
100static INLINE struct dri2_config *
101dri2_config(const struct native_config *nconf)
102{
103   return (struct dri2_config *) nconf;
104}
105
106/**
107 * Process the buffers returned by the server.
108 */
109static void
110dri2_surface_process_drawable_buffers(struct native_surface *nsurf,
111                                      struct x11_drawable_buffer *xbufs,
112                                      int num_xbufs)
113{
114   struct dri2_surface *dri2surf = dri2_surface(nsurf);
115   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
116   struct pipe_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 */
190static void
191dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
192{
193   struct dri2_surface *dri2surf = dri2_surface(nsurf);
194   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
195   unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS];
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 */
256static boolean
257dri2_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 */
269static INLINE boolean
270dri2_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
276static boolean
277dri2_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
298static boolean
299dri2_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
326static boolean
327dri2_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
362static void
363dri2_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
375static void
376dri2_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
399static struct dri2_surface *
400dri2_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
436static struct native_surface *
437dri2_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
448static struct native_surface *
449dri2_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
460static int
461choose_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
486static int
487choose_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
516static boolean
517is_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
525static boolean
526dri2_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
592static const struct native_config **
593dri2_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
635static boolean
636dri2_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
650static int
651dri2_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
669static void
670dri2_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
692static void
693dri2_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 */
716static boolean
717dri2_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
755static unsigned
756dri2_display_hash_table_hash(void *key)
757{
758   XID drawable = pointer_to_uintptr(key);
759   return (unsigned) drawable;
760}
761
762static int
763dri2_display_hash_table_compare(void *key1, void *key2)
764{
765   return (key1 - key2);
766}
767
768struct native_display *
769x11_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}
820