platform_x11.c revision d26890688fc4efdec64e8fef33b54049f9c690bf
1/*
2 * Copyright © 2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Kristian Høgsberg <krh@bitplanet.net>
26 */
27
28#include <stdlib.h>
29#include <string.h>
30#include <stdio.h>
31#include <limits.h>
32#include <dlfcn.h>
33#include <fcntl.h>
34#include <errno.h>
35#include <unistd.h>
36#include <xf86drm.h>
37#include <sys/types.h>
38#include <sys/stat.h>
39
40#include "egl_dri2.h"
41
42static void
43swrastCreateDrawable(struct dri2_egl_display * dri2_dpy,
44                     struct dri2_egl_surface * dri2_surf,
45                     int depth)
46{
47   uint32_t           mask;
48   const uint32_t     function = GXcopy;
49   uint32_t           valgc[2];
50
51   /* create GC's */
52   dri2_surf->gc = xcb_generate_id(dri2_dpy->conn);
53   mask = XCB_GC_FUNCTION;
54   xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask, &function);
55
56   dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn);
57   mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES;
58   valgc[0] = function;
59   valgc[1] = False;
60   xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask, valgc);
61   dri2_surf->depth = depth;
62   switch (depth) {
63      case 32:
64      case 24:
65         dri2_surf->bytes_per_pixel = 4;
66         break;
67      case 16:
68         dri2_surf->bytes_per_pixel = 2;
69         break;
70      case 8:
71         dri2_surf->bytes_per_pixel = 1;
72         break;
73      case 0:
74         dri2_surf->bytes_per_pixel = 0;
75         break;
76      default:
77         _eglLog(_EGL_WARNING, "unsupported depth %d", depth);
78   }
79}
80
81static void
82swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy,
83                      struct dri2_egl_surface * dri2_surf)
84{
85   xcb_free_gc(dri2_dpy->conn, dri2_surf->gc);
86   xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc);
87}
88
89static void
90swrastGetDrawableInfo(__DRIdrawable * draw,
91                      int *x, int *y, int *w, int *h,
92                      void *loaderPrivate)
93{
94   struct dri2_egl_surface *dri2_surf = loaderPrivate;
95   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
96
97   xcb_get_geometry_cookie_t cookie;
98   xcb_get_geometry_reply_t *reply;
99   xcb_generic_error_t *error;
100
101   *w = *h = 0;
102   cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
103   reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
104   if (reply == NULL)
105      return;
106
107   if (error != NULL) {
108      _eglLog(_EGL_WARNING, "error in xcb_get_geometry");
109      free(error);
110   } else {
111      *w = reply->width;
112      *h = reply->height;
113   }
114   free(reply);
115}
116
117static void
118swrastPutImage(__DRIdrawable * draw, int op,
119               int x, int y, int w, int h,
120               char *data, void *loaderPrivate)
121{
122   struct dri2_egl_surface *dri2_surf = loaderPrivate;
123   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
124
125   xcb_gcontext_t gc;
126
127   switch (op) {
128   case __DRI_SWRAST_IMAGE_OP_DRAW:
129      gc = dri2_surf->gc;
130      break;
131   case __DRI_SWRAST_IMAGE_OP_SWAP:
132      gc = dri2_surf->swapgc;
133      break;
134   default:
135      return;
136   }
137
138   xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable,
139                 gc, w, h, x, y, 0, dri2_surf->depth,
140                 w*h*dri2_surf->bytes_per_pixel, (const uint8_t *)data);
141}
142
143static void
144swrastGetImage(__DRIdrawable * read,
145               int x, int y, int w, int h,
146               char *data, void *loaderPrivate)
147{
148   struct dri2_egl_surface *dri2_surf = loaderPrivate;
149   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
150
151   xcb_get_image_cookie_t cookie;
152   xcb_get_image_reply_t *reply;
153   xcb_generic_error_t *error;
154
155   cookie = xcb_get_image (dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
156                           dri2_surf->drawable, x, y, w, h, ~0);
157   reply = xcb_get_image_reply (dri2_dpy->conn, cookie, &error);
158   if (reply == NULL)
159      return;
160
161   if (error != NULL) {
162      _eglLog(_EGL_WARNING, "error in xcb_get_image");
163      free(error);
164   } else {
165      uint32_t bytes = xcb_get_image_data_length(reply);
166      uint8_t *idata = xcb_get_image_data(reply);
167      memcpy(data, idata, bytes);
168   }
169   free(reply);
170}
171
172
173/**
174 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
175 */
176static _EGLSurface *
177dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
178		    _EGLConfig *conf, EGLNativeWindowType window,
179		    const EGLint *attrib_list)
180{
181   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
182   struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
183   struct dri2_egl_surface *dri2_surf;
184   xcb_get_geometry_cookie_t cookie;
185   xcb_get_geometry_reply_t *reply;
186   xcb_screen_iterator_t s;
187   xcb_generic_error_t *error;
188
189   (void) drv;
190
191   dri2_surf = malloc(sizeof *dri2_surf);
192   if (!dri2_surf) {
193      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
194      return NULL;
195   }
196
197   if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
198      goto cleanup_surf;
199
200   dri2_surf->region = XCB_NONE;
201   if (type == EGL_PBUFFER_BIT) {
202      dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
203      s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
204      xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
205			dri2_surf->drawable, s.data->root,
206			dri2_surf->base.Width, dri2_surf->base.Height);
207   } else {
208      dri2_surf->drawable = window;
209   }
210
211   if (dri2_dpy->dri2) {
212      dri2_surf->dri_drawable =
213	 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
214					       type == EGL_WINDOW_BIT ?
215					       dri2_conf->dri_double_config :
216					       dri2_conf->dri_single_config,
217					       dri2_surf);
218   } else {
219      assert(dri2_dpy->swrast);
220      dri2_surf->dri_drawable =
221	 (*dri2_dpy->swrast->createNewDrawable) (dri2_dpy->dri_screen,
222						 dri2_conf->dri_double_config,
223						 dri2_surf);
224   }
225
226   if (dri2_surf->dri_drawable == NULL) {
227      _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
228      goto cleanup_pixmap;
229   }
230
231   if (dri2_dpy->dri2) {
232      xcb_dri2_create_drawable (dri2_dpy->conn, dri2_surf->drawable);
233   } else {
234      swrastCreateDrawable(dri2_dpy, dri2_surf, _eglGetConfigKey(conf, EGL_BUFFER_SIZE));
235   }
236
237   if (type != EGL_PBUFFER_BIT) {
238      cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
239      reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
240      if (reply == NULL || error != NULL) {
241	 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
242	 free(error);
243	 goto cleanup_dri_drawable;
244      }
245
246      dri2_surf->base.Width = reply->width;
247      dri2_surf->base.Height = reply->height;
248      free(reply);
249   }
250
251   /* we always copy the back buffer to front */
252   dri2_surf->base.PostSubBufferSupportedNV = EGL_TRUE;
253
254   return &dri2_surf->base;
255
256 cleanup_dri_drawable:
257   dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
258 cleanup_pixmap:
259   if (type == EGL_PBUFFER_BIT)
260      xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);
261 cleanup_surf:
262   free(dri2_surf);
263
264   return NULL;
265}
266
267/**
268 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
269 */
270static _EGLSurface *
271dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
272			   _EGLConfig *conf, EGLNativeWindowType window,
273			   const EGLint *attrib_list)
274{
275   return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
276			      window, attrib_list);
277}
278
279static _EGLSurface *
280dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
281			   _EGLConfig *conf, EGLNativePixmapType pixmap,
282			   const EGLint *attrib_list)
283{
284   return dri2_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
285			      pixmap, attrib_list);
286}
287
288static _EGLSurface *
289dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
290			    _EGLConfig *conf, const EGLint *attrib_list)
291{
292   return dri2_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
293			      XCB_WINDOW_NONE, attrib_list);
294}
295
296static EGLBoolean
297dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
298{
299   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
300   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
301
302   (void) drv;
303
304   if (!_eglPutSurface(surf))
305      return EGL_TRUE;
306
307   (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
308
309   if (dri2_dpy->dri2) {
310      xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
311   } else {
312      assert(dri2_dpy->swrast);
313      swrastDestroyDrawable(dri2_dpy, dri2_surf);
314   }
315
316   if (surf->Type == EGL_PBUFFER_BIT)
317      xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
318
319   free(surf);
320
321   return EGL_TRUE;
322}
323
324/**
325 * Process list of buffer received from the server
326 *
327 * Processes the list of buffers received in a reply from the server to either
328 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
329 */
330static void
331dri2_process_buffers(struct dri2_egl_surface *dri2_surf,
332		     xcb_dri2_dri2_buffer_t *buffers, unsigned count)
333{
334   struct dri2_egl_display *dri2_dpy =
335      dri2_egl_display(dri2_surf->base.Resource.Display);
336   xcb_rectangle_t rectangle;
337   unsigned i;
338
339   dri2_surf->buffer_count = count;
340   dri2_surf->have_fake_front = 0;
341
342   /* This assumes the DRI2 buffer attachment tokens matches the
343    * __DRIbuffer tokens. */
344   for (i = 0; i < count; i++) {
345      dri2_surf->buffers[i].attachment = buffers[i].attachment;
346      dri2_surf->buffers[i].name = buffers[i].name;
347      dri2_surf->buffers[i].pitch = buffers[i].pitch;
348      dri2_surf->buffers[i].cpp = buffers[i].cpp;
349      dri2_surf->buffers[i].flags = buffers[i].flags;
350
351      /* We only use the DRI drivers single buffer configs.  This
352       * means that if we try to render to a window, DRI2 will give us
353       * the fake front buffer, which we'll use as a back buffer.
354       * Note that EGL doesn't require that several clients rendering
355       * to the same window must see the same aux buffers. */
356      if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
357         dri2_surf->have_fake_front = 1;
358   }
359
360   if (dri2_surf->region != XCB_NONE)
361      xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region);
362
363   rectangle.x = 0;
364   rectangle.y = 0;
365   rectangle.width = dri2_surf->base.Width;
366   rectangle.height = dri2_surf->base.Height;
367   dri2_surf->region = xcb_generate_id(dri2_dpy->conn);
368   xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle);
369}
370
371static __DRIbuffer *
372dri2_get_buffers(__DRIdrawable * driDrawable,
373		int *width, int *height,
374		unsigned int *attachments, int count,
375		int *out_count, void *loaderPrivate)
376{
377   struct dri2_egl_surface *dri2_surf = loaderPrivate;
378   struct dri2_egl_display *dri2_dpy =
379      dri2_egl_display(dri2_surf->base.Resource.Display);
380   xcb_dri2_dri2_buffer_t *buffers;
381   xcb_dri2_get_buffers_reply_t *reply;
382   xcb_dri2_get_buffers_cookie_t cookie;
383
384   (void) driDrawable;
385
386   cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
387					    dri2_surf->drawable,
388					    count, count, attachments);
389   reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL);
390   buffers = xcb_dri2_get_buffers_buffers (reply);
391   if (buffers == NULL)
392      return NULL;
393
394   *out_count = reply->count;
395   dri2_surf->base.Width = *width = reply->width;
396   dri2_surf->base.Height = *height = reply->height;
397   dri2_process_buffers(dri2_surf, buffers, *out_count);
398
399   free(reply);
400
401   return dri2_surf->buffers;
402}
403
404static __DRIbuffer *
405dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
406			     int *width, int *height,
407			     unsigned int *attachments, int count,
408			     int *out_count, void *loaderPrivate)
409{
410   struct dri2_egl_surface *dri2_surf = loaderPrivate;
411   struct dri2_egl_display *dri2_dpy =
412      dri2_egl_display(dri2_surf->base.Resource.Display);
413   xcb_dri2_dri2_buffer_t *buffers;
414   xcb_dri2_get_buffers_with_format_reply_t *reply;
415   xcb_dri2_get_buffers_with_format_cookie_t cookie;
416   xcb_dri2_attach_format_t *format_attachments;
417
418   (void) driDrawable;
419
420   format_attachments = (xcb_dri2_attach_format_t *) attachments;
421   cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn,
422							dri2_surf->drawable,
423							count, count,
424							format_attachments);
425
426   reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn,
427						   cookie, NULL);
428   if (reply == NULL)
429      return NULL;
430
431   buffers = xcb_dri2_get_buffers_with_format_buffers (reply);
432   dri2_surf->base.Width = *width = reply->width;
433   dri2_surf->base.Height = *height = reply->height;
434   *out_count = reply->count;
435   dri2_process_buffers(dri2_surf, buffers, *out_count);
436
437   free(reply);
438
439   return dri2_surf->buffers;
440}
441
442static void
443dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
444{
445   (void) driDrawable;
446
447   /* FIXME: Does EGL support front buffer rendering at all? */
448
449#if 0
450   struct dri2_egl_surface *dri2_surf = loaderPrivate;
451
452   dri2WaitGL(dri2_surf);
453#else
454   (void) loaderPrivate;
455#endif
456}
457
458static char *
459dri2_strndup(const char *s, int length)
460{
461   char *d;
462
463   d = malloc(length + 1);
464   if (d == NULL)
465      return NULL;
466
467   memcpy(d, s, length);
468   d[length] = '\0';
469
470   return d;
471}
472
473static EGLBoolean
474dri2_connect(struct dri2_egl_display *dri2_dpy)
475{
476   xcb_xfixes_query_version_reply_t *xfixes_query;
477   xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
478   xcb_dri2_query_version_reply_t *dri2_query;
479   xcb_dri2_query_version_cookie_t dri2_query_cookie;
480   xcb_dri2_connect_reply_t *connect;
481   xcb_dri2_connect_cookie_t connect_cookie;
482   xcb_generic_error_t *error;
483   xcb_screen_iterator_t s;
484   char *driver_name, *device_name;
485   const xcb_query_extension_reply_t *extension;
486
487   xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
488   xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
489
490   extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
491   if (!(extension && extension->present))
492      return EGL_FALSE;
493
494   extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri2_id);
495   if (!(extension && extension->present))
496      return EGL_FALSE;
497
498   xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
499						  XCB_XFIXES_MAJOR_VERSION,
500						  XCB_XFIXES_MINOR_VERSION);
501
502   dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn,
503					       XCB_DRI2_MAJOR_VERSION,
504					       XCB_DRI2_MINOR_VERSION);
505
506   s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
507   connect_cookie = xcb_dri2_connect_unchecked (dri2_dpy->conn,
508						s.data->root,
509						XCB_DRI2_DRIVER_TYPE_DRI);
510
511   xfixes_query =
512      xcb_xfixes_query_version_reply (dri2_dpy->conn,
513				      xfixes_query_cookie, &error);
514   if (xfixes_query == NULL ||
515       error != NULL || xfixes_query->major_version < 2) {
516      _eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version");
517      free(error);
518      return EGL_FALSE;
519   }
520   free(xfixes_query);
521
522   dri2_query =
523      xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);
524   if (dri2_query == NULL || error != NULL) {
525      _eglLog(_EGL_WARNING, "DRI2: failed to query version");
526      free(error);
527      return EGL_FALSE;
528   }
529   dri2_dpy->dri2_major = dri2_query->major_version;
530   dri2_dpy->dri2_minor = dri2_query->minor_version;
531   free(dri2_query);
532
533   connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);
534   if (connect == NULL ||
535       connect->driver_name_length + connect->device_name_length == 0) {
536      _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
537      return EGL_FALSE;
538   }
539
540   driver_name = xcb_dri2_connect_driver_name (connect);
541   dri2_dpy->driver_name =
542      dri2_strndup(driver_name,
543		   xcb_dri2_connect_driver_name_length (connect));
544
545#if XCB_DRI2_CONNECT_DEVICE_NAME_BROKEN
546   device_name = driver_name + ((connect->driver_name_length + 3) & ~3);
547#else
548   device_name = xcb_dri2_connect_device_name (connect);
549#endif
550
551   dri2_dpy->device_name =
552      dri2_strndup(device_name,
553		   xcb_dri2_connect_device_name_length (connect));
554
555   if (dri2_dpy->device_name == NULL || dri2_dpy->driver_name == NULL) {
556      free(dri2_dpy->device_name);
557      free(dri2_dpy->driver_name);
558      free(connect);
559      return EGL_FALSE;
560   }
561   free(connect);
562
563   return EGL_TRUE;
564}
565
566static int
567dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id)
568{
569   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
570   xcb_dri2_authenticate_reply_t *authenticate;
571   xcb_dri2_authenticate_cookie_t authenticate_cookie;
572   xcb_screen_iterator_t s;
573   int ret = 0;
574
575   s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
576   authenticate_cookie =
577      xcb_dri2_authenticate_unchecked(dri2_dpy->conn, s.data->root, id);
578   authenticate =
579      xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);
580
581   if (authenticate == NULL || !authenticate->authenticated)
582      ret = -1;
583
584   if (authenticate)
585      free(authenticate);
586
587   return ret;
588}
589
590static EGLBoolean
591dri2_authenticate(_EGLDisplay *disp)
592{
593   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
594   drm_magic_t magic;
595
596   if (drmGetMagic(dri2_dpy->fd, &magic)) {
597      _eglLog(_EGL_WARNING, "DRI2: failed to get drm magic");
598      return EGL_FALSE;
599   }
600
601   if (dri2_x11_authenticate(disp, magic) < 0) {
602      _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
603      return EGL_FALSE;
604   }
605
606   return EGL_TRUE;
607}
608
609static EGLBoolean
610dri2_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
611			     _EGLDisplay *disp)
612{
613   xcb_screen_iterator_t s;
614   xcb_depth_iterator_t d;
615   xcb_visualtype_t *visuals;
616   int i, j, id;
617   EGLint surface_type;
618   EGLint config_attrs[] = {
619	   EGL_NATIVE_VISUAL_ID,   0,
620	   EGL_NATIVE_VISUAL_TYPE, 0,
621	   EGL_NONE
622   };
623
624   s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
625   d = xcb_screen_allowed_depths_iterator(s.data);
626   id = 1;
627
628   surface_type =
629      EGL_WINDOW_BIT |
630      EGL_PIXMAP_BIT |
631      EGL_PBUFFER_BIT |
632      EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
633
634   while (d.rem > 0) {
635      EGLBoolean class_added[6] = { 0, };
636
637      visuals = xcb_depth_visuals(d.data);
638      for (i = 0; i < xcb_depth_visuals_length(d.data); i++) {
639	 if (class_added[visuals[i]._class])
640	    continue;
641
642	 class_added[visuals[i]._class] = EGL_TRUE;
643	 for (j = 0; dri2_dpy->driver_configs[j]; j++) {
644            config_attrs[1] = visuals[i].visual_id;
645            config_attrs[3] = visuals[i]._class;
646
647	    dri2_add_config(disp, dri2_dpy->driver_configs[j], id++,
648			    d.data->depth, surface_type, config_attrs, NULL);
649	 }
650      }
651
652      xcb_depth_next(&d);
653   }
654
655   if (!_eglGetArraySize(disp->Configs)) {
656      _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
657      return EGL_FALSE;
658   }
659
660   return EGL_TRUE;
661}
662
663static EGLBoolean
664dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp,
665		 _EGLSurface *draw, xcb_xfixes_region_t region)
666{
667   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
668   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
669   enum xcb_dri2_attachment_t render_attachment;
670   xcb_dri2_copy_region_cookie_t cookie;
671
672   /* No-op for a pixmap or pbuffer surface */
673   if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
674      return EGL_TRUE;
675
676#ifdef __DRI2_FLUSH
677   if (dri2_dpy->flush)
678      (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
679#endif
680
681   if (dri2_surf->have_fake_front)
682      render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT;
683   else
684      render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT;
685
686   cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
687					   dri2_surf->drawable,
688					   region,
689					   XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
690					   render_attachment);
691   free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
692
693   return EGL_TRUE;
694}
695
696static int64_t
697dri2_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
698                      int64_t msc, int64_t divisor, int64_t remainder)
699{
700#if XCB_DRI2_MINOR_VERSION >= 3
701   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
702   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
703   uint32_t msc_hi = msc >> 32;
704   uint32_t msc_lo = msc & 0xffffffff;
705   uint32_t divisor_hi = divisor >> 32;
706   uint32_t divisor_lo = divisor & 0xffffffff;
707   uint32_t remainder_hi = remainder >> 32;
708   uint32_t remainder_lo = remainder & 0xffffffff;
709   xcb_dri2_swap_buffers_cookie_t cookie;
710   xcb_dri2_swap_buffers_reply_t *reply;
711   int64_t swap_count = -1;
712
713   /* No-op for a pixmap or pbuffer surface */
714   if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
715      return 0;
716
717   if (draw->SwapBehavior == EGL_BUFFER_PRESERVED || !dri2_dpy->swap_available)
718      return dri2_copy_region(drv, disp, draw, dri2_surf->region) ? 0 : -1;
719
720#ifdef __DRI2_FLUSH
721   if (dri2_dpy->flush)
722      (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
723#endif
724
725   cookie = xcb_dri2_swap_buffers_unchecked(dri2_dpy->conn, dri2_surf->drawable,
726                  msc_hi, msc_lo, divisor_hi, divisor_lo, remainder_hi, remainder_lo);
727
728   reply = xcb_dri2_swap_buffers_reply(dri2_dpy->conn, cookie, NULL);
729
730   if (reply) {
731      swap_count = (((int64_t)reply->swap_hi) << 32) | reply->swap_lo;
732      free(reply);
733   }
734
735#if __DRI2_FLUSH_VERSION >= 3
736   /* If the server doesn't send invalidate events */
737   if (dri2_dpy->invalidate_available && dri2_dpy->flush &&
738       dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate)
739      (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
740#endif
741
742   return swap_count;
743#else
744   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
745
746   return dri2_copy_region(drv, disp, draw, dri2_surf->region) ? 0 : -1;
747#endif /* XCB_DRI2_MINOR_VERSION >= 3 */
748
749}
750
751static EGLBoolean
752dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
753{
754   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
755   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
756
757   if (dri2_dpy->dri2) {
758      return dri2_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1;
759   } else {
760      assert(dri2_dpy->swrast);
761
762      dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
763      return EGL_TRUE;
764   }
765}
766
767static EGLBoolean
768dri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
769			 EGLint numRects, const EGLint *rects)
770{
771   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
772   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
773   EGLBoolean ret;
774   xcb_xfixes_region_t region;
775   xcb_rectangle_t rectangles[16];
776   int i;
777
778   if (numRects > (int)ARRAY_SIZE(rectangles))
779      return dri2_copy_region(drv, disp, draw, dri2_surf->region);
780
781   for (i = 0; i < numRects; i++) {
782      rectangles[i].x = rects[i * 4];
783      rectangles[i].y = dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3];
784      rectangles[i].width = rects[i * 4 + 2];
785      rectangles[i].height = rects[i * 4 + 3];
786   }
787
788   region = xcb_generate_id(dri2_dpy->conn);
789   xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles);
790   ret = dri2_copy_region(drv, disp, draw, region);
791   xcb_xfixes_destroy_region(dri2_dpy->conn, region);
792
793   return ret;
794}
795
796static EGLBoolean
797dri2_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
798		     EGLint x, EGLint y, EGLint width, EGLint height)
799{
800   const EGLint rect[4] = { x, y, width, height };
801
802   if (x < 0 || y < 0 || width < 0 || height < 0)
803      _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV");
804
805   return dri2_swap_buffers_region(drv, disp, draw, 1, rect);
806}
807
808static EGLBoolean
809dri2_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
810{
811#if XCB_DRI2_MINOR_VERSION >= 3
812   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
813   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
814#endif
815
816   /* XXX Check vblank_mode here? */
817
818   if (interval > surf->Config->MaxSwapInterval)
819      interval = surf->Config->MaxSwapInterval;
820   else if (interval < surf->Config->MinSwapInterval)
821      interval = surf->Config->MinSwapInterval;
822
823#if XCB_DRI2_MINOR_VERSION >= 3
824   if (interval != surf->SwapInterval && dri2_dpy->swap_available)
825      xcb_dri2_swap_interval(dri2_dpy->conn, dri2_surf->drawable, interval);
826#endif
827
828   surf->SwapInterval = interval;
829
830   return EGL_TRUE;
831}
832
833static EGLBoolean
834dri2_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
835		  EGLNativePixmapType target)
836{
837   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
838   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
839   xcb_gcontext_t gc;
840
841   (void) drv;
842
843   (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
844
845   gc = xcb_generate_id(dri2_dpy->conn);
846   xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL);
847   xcb_copy_area(dri2_dpy->conn,
848		  dri2_surf->drawable,
849		  target,
850		  gc,
851		  0, 0,
852		  0, 0,
853		  dri2_surf->base.Width,
854		  dri2_surf->base.Height);
855   xcb_free_gc(dri2_dpy->conn, gc);
856
857   return EGL_TRUE;
858}
859
860static _EGLImage *
861dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
862			     EGLClientBuffer buffer, const EGLint *attr_list)
863{
864   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
865   struct dri2_egl_image *dri2_img;
866   unsigned int attachments[1];
867   xcb_drawable_t drawable;
868   xcb_dri2_get_buffers_cookie_t buffers_cookie;
869   xcb_dri2_get_buffers_reply_t *buffers_reply;
870   xcb_dri2_dri2_buffer_t *buffers;
871   xcb_get_geometry_cookie_t geometry_cookie;
872   xcb_get_geometry_reply_t *geometry_reply;
873   xcb_generic_error_t *error;
874   int stride, format;
875
876   (void) ctx;
877
878   drawable = (xcb_drawable_t) (uintptr_t) buffer;
879   xcb_dri2_create_drawable (dri2_dpy->conn, drawable);
880   attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;
881   buffers_cookie =
882      xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
883				      drawable, 1, 1, attachments);
884   geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable);
885   buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn,
886					       buffers_cookie, NULL);
887   buffers = xcb_dri2_get_buffers_buffers (buffers_reply);
888   if (buffers == NULL) {
889      return NULL;
890   }
891
892   geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn,
893					    geometry_cookie, &error);
894   if (geometry_reply == NULL || error != NULL) {
895      _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
896      free(error);
897      free(buffers_reply);
898      return NULL;
899   }
900
901   switch (geometry_reply->depth) {
902   case 16:
903      format = __DRI_IMAGE_FORMAT_RGB565;
904      break;
905   case 24:
906      format = __DRI_IMAGE_FORMAT_XRGB8888;
907      break;
908   case 32:
909      format = __DRI_IMAGE_FORMAT_ARGB8888;
910      break;
911   default:
912      _eglError(EGL_BAD_PARAMETER,
913		"dri2_create_image_khr: unsupported pixmap depth");
914      free(buffers_reply);
915      free(geometry_reply);
916      return NULL;
917   }
918
919   dri2_img = malloc(sizeof *dri2_img);
920   if (!dri2_img) {
921      free(buffers_reply);
922      free(geometry_reply);
923      _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
924      return EGL_NO_IMAGE_KHR;
925   }
926
927   if (!_eglInitImage(&dri2_img->base, disp)) {
928      free(buffers_reply);
929      free(geometry_reply);
930      free(dri2_img);
931      return EGL_NO_IMAGE_KHR;
932   }
933
934   stride = buffers[0].pitch / buffers[0].cpp;
935   dri2_img->dri_image =
936      dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
937					   buffers_reply->width,
938					   buffers_reply->height,
939					   format,
940					   buffers[0].name,
941					   stride,
942					   dri2_img);
943
944   free(buffers_reply);
945   free(geometry_reply);
946
947   return &dri2_img->base;
948}
949
950static _EGLImage *
951dri2_x11_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
952			  _EGLContext *ctx, EGLenum target,
953			  EGLClientBuffer buffer, const EGLint *attr_list)
954{
955   (void) drv;
956
957   switch (target) {
958   case EGL_NATIVE_PIXMAP_KHR:
959      return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
960   default:
961      return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
962   }
963}
964
965static EGLBoolean
966dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp)
967{
968   struct dri2_egl_display *dri2_dpy;
969
970   drv->API.CreateWindowSurface = dri2_create_window_surface;
971   drv->API.CreatePixmapSurface = dri2_create_pixmap_surface;
972   drv->API.CreatePbufferSurface = dri2_create_pbuffer_surface;
973   drv->API.DestroySurface = dri2_destroy_surface;
974   drv->API.SwapBuffers = dri2_swap_buffers;
975   drv->API.CopyBuffers = dri2_copy_buffers;
976
977   drv->API.SwapBuffersRegionNOK = NULL;
978   drv->API.CreateImageKHR  = NULL;
979   drv->API.DestroyImageKHR = NULL;
980   drv->API.CreateDRMImageMESA = NULL;
981   drv->API.ExportDRMImageMESA = NULL;
982
983   dri2_dpy = malloc(sizeof *dri2_dpy);
984   if (!dri2_dpy)
985      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
986
987   memset(dri2_dpy, 0, sizeof *dri2_dpy);
988
989   disp->DriverData = (void *) dri2_dpy;
990   if (disp->PlatformDisplay == NULL) {
991      dri2_dpy->conn = xcb_connect(0, 0);
992   } else {
993      dri2_dpy->conn = XGetXCBConnection((Display *) disp->PlatformDisplay);
994   }
995
996   if (xcb_connection_has_error(dri2_dpy->conn)) {
997      _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
998      goto cleanup_dpy;
999   }
1000
1001   if (!dri2_load_driver_swrast(disp))
1002      goto cleanup_conn;
1003
1004   dri2_dpy->swrast_loader_extension.base.name = __DRI_SWRAST_LOADER;
1005   dri2_dpy->swrast_loader_extension.base.version = __DRI_SWRAST_LOADER_VERSION;
1006   dri2_dpy->swrast_loader_extension.getDrawableInfo = swrastGetDrawableInfo;
1007   dri2_dpy->swrast_loader_extension.putImage = swrastPutImage;
1008   dri2_dpy->swrast_loader_extension.getImage = swrastGetImage;
1009
1010   dri2_dpy->extensions[0] = &dri2_dpy->swrast_loader_extension.base;
1011   dri2_dpy->extensions[1] = NULL;
1012   dri2_dpy->extensions[2] = NULL;
1013
1014   if (!dri2_create_screen(disp))
1015      goto cleanup_driver;
1016
1017   if (dri2_dpy->conn) {
1018      if (!dri2_add_configs_for_visuals(dri2_dpy, disp))
1019         goto cleanup_configs;
1020   }
1021
1022   /* we're supporting EGL 1.4 */
1023   disp->VersionMajor = 1;
1024   disp->VersionMinor = 4;
1025
1026   return EGL_TRUE;
1027
1028 cleanup_configs:
1029   _eglCleanupDisplay(disp);
1030   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1031 cleanup_driver:
1032   dlclose(dri2_dpy->driver);
1033 cleanup_conn:
1034   if (disp->PlatformDisplay == NULL)
1035      xcb_disconnect(dri2_dpy->conn);
1036 cleanup_dpy:
1037   free(dri2_dpy);
1038
1039   return EGL_FALSE;
1040}
1041
1042
1043static EGLBoolean
1044dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
1045{
1046   struct dri2_egl_display *dri2_dpy;
1047
1048   drv->API.CreateWindowSurface = dri2_create_window_surface;
1049   drv->API.CreatePixmapSurface = dri2_create_pixmap_surface;
1050   drv->API.CreatePbufferSurface = dri2_create_pbuffer_surface;
1051   drv->API.DestroySurface = dri2_destroy_surface;
1052   drv->API.SwapBuffers = dri2_swap_buffers;
1053   drv->API.CopyBuffers = dri2_copy_buffers;
1054   drv->API.CreateImageKHR = dri2_x11_create_image_khr;
1055   drv->API.SwapBuffersRegionNOK = dri2_swap_buffers_region;
1056   drv->API.PostSubBufferNV = dri2_post_sub_buffer;
1057   drv->API.SwapInterval = dri2_swap_interval;
1058
1059   dri2_dpy = malloc(sizeof *dri2_dpy);
1060   if (!dri2_dpy)
1061      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1062
1063   memset(dri2_dpy, 0, sizeof *dri2_dpy);
1064
1065   disp->DriverData = (void *) dri2_dpy;
1066   if (disp->PlatformDisplay == NULL) {
1067      dri2_dpy->conn = xcb_connect(0, 0);
1068   } else {
1069      dri2_dpy->conn = XGetXCBConnection((Display *) disp->PlatformDisplay);
1070   }
1071
1072   if (xcb_connection_has_error(dri2_dpy->conn)) {
1073      _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
1074      goto cleanup_dpy;
1075   }
1076
1077   if (dri2_dpy->conn) {
1078      if (!dri2_connect(dri2_dpy))
1079	 goto cleanup_conn;
1080   }
1081
1082   if (!dri2_load_driver(disp))
1083      goto cleanup_conn;
1084
1085#ifdef O_CLOEXEC
1086   dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
1087   if (dri2_dpy->fd == -1 && errno == EINVAL)
1088#endif
1089   {
1090      dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
1091      if (dri2_dpy->fd != -1)
1092         fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
1093            FD_CLOEXEC);
1094   }
1095   if (dri2_dpy->fd == -1) {
1096      _eglLog(_EGL_WARNING,
1097	      "DRI2: could not open %s (%s)", dri2_dpy->device_name,
1098              strerror(errno));
1099      goto cleanup_driver;
1100   }
1101
1102   if (dri2_dpy->conn) {
1103      if (!dri2_authenticate(disp))
1104	 goto cleanup_fd;
1105   }
1106
1107   if (dri2_dpy->dri2_minor >= 1) {
1108      dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
1109      dri2_dpy->dri2_loader_extension.base.version = 3;
1110      dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
1111      dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
1112      dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
1113	 dri2_get_buffers_with_format;
1114   } else {
1115      dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
1116      dri2_dpy->dri2_loader_extension.base.version = 2;
1117      dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
1118      dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
1119      dri2_dpy->dri2_loader_extension.getBuffersWithFormat = NULL;
1120   }
1121
1122   dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
1123   dri2_dpy->extensions[1] = &image_lookup_extension.base;
1124   dri2_dpy->extensions[2] = NULL;
1125
1126#if XCB_DRI2_MINOR_VERSION >= 3
1127   dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2);
1128   dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3);
1129#endif
1130
1131   if (!dri2_create_screen(disp))
1132      goto cleanup_fd;
1133
1134   if (dri2_dpy->conn) {
1135      if (!dri2_add_configs_for_visuals(dri2_dpy, disp))
1136	 goto cleanup_configs;
1137   }
1138
1139   disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1140   disp->Extensions.NOK_swap_region = EGL_TRUE;
1141   disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1142   disp->Extensions.NV_post_sub_buffer = EGL_TRUE;
1143
1144#ifdef HAVE_WAYLAND_PLATFORM
1145   disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
1146#endif
1147   dri2_dpy->authenticate = dri2_x11_authenticate;
1148
1149   /* we're supporting EGL 1.4 */
1150   disp->VersionMajor = 1;
1151   disp->VersionMinor = 4;
1152
1153   return EGL_TRUE;
1154
1155 cleanup_configs:
1156   _eglCleanupDisplay(disp);
1157   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1158 cleanup_fd:
1159   close(dri2_dpy->fd);
1160 cleanup_driver:
1161   dlclose(dri2_dpy->driver);
1162 cleanup_conn:
1163   if (disp->PlatformDisplay == NULL)
1164      xcb_disconnect(dri2_dpy->conn);
1165 cleanup_dpy:
1166   free(dri2_dpy);
1167
1168   return EGL_FALSE;
1169}
1170
1171EGLBoolean
1172dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)
1173{
1174   EGLBoolean initialized = EGL_TRUE;
1175
1176   int x11_dri2_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
1177
1178   if (x11_dri2_accel) {
1179      if (!dri2_initialize_x11_dri2(drv, disp)) {
1180         initialized = dri2_initialize_x11_swrast(drv, disp);
1181      }
1182   } else {
1183      initialized = dri2_initialize_x11_swrast(drv, disp);
1184   }
1185
1186   return initialized;
1187}
1188
1189