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