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 <stdbool.h>
29#include <stdint.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdio.h>
33#include <limits.h>
34#include <dlfcn.h>
35#include <fcntl.h>
36#include <errno.h>
37#include <unistd.h>
38#ifdef HAVE_LIBDRM
39#include <xf86drm.h>
40#endif
41#include <sys/types.h>
42#include <sys/stat.h>
43
44#include "egl_dri2.h"
45#include "egl_dri2_fallbacks.h"
46#include "loader.h"
47
48#ifdef HAVE_DRI3
49#include "platform_x11_dri3.h"
50#endif
51
52static EGLBoolean
53dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
54                       EGLint interval);
55
56static void
57swrastCreateDrawable(struct dri2_egl_display * dri2_dpy,
58                     struct dri2_egl_surface * dri2_surf)
59{
60   uint32_t           mask;
61   const uint32_t     function = GXcopy;
62   uint32_t           valgc[2];
63
64   /* create GC's */
65   dri2_surf->gc = xcb_generate_id(dri2_dpy->conn);
66   mask = XCB_GC_FUNCTION;
67   xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask, &function);
68
69   dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn);
70   mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES;
71   valgc[0] = function;
72   valgc[1] = False;
73   xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask, valgc);
74   switch (dri2_surf->depth) {
75      case 32:
76      case 24:
77         dri2_surf->bytes_per_pixel = 4;
78         break;
79      case 16:
80         dri2_surf->bytes_per_pixel = 2;
81         break;
82      case 8:
83         dri2_surf->bytes_per_pixel = 1;
84         break;
85      case 0:
86         dri2_surf->bytes_per_pixel = 0;
87         break;
88      default:
89         _eglLog(_EGL_WARNING, "unsupported depth %d", dri2_surf->depth);
90   }
91}
92
93static void
94swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy,
95                      struct dri2_egl_surface * dri2_surf)
96{
97   xcb_free_gc(dri2_dpy->conn, dri2_surf->gc);
98   xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc);
99}
100
101static void
102swrastGetDrawableInfo(__DRIdrawable * draw,
103                      int *x, int *y, int *w, int *h,
104                      void *loaderPrivate)
105{
106   struct dri2_egl_surface *dri2_surf = loaderPrivate;
107   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
108
109   xcb_get_geometry_cookie_t cookie;
110   xcb_get_geometry_reply_t *reply;
111   xcb_generic_error_t *error;
112
113   *w = *h = 0;
114   cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
115   reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
116   if (reply == NULL)
117      return;
118
119   if (error != NULL) {
120      _eglLog(_EGL_WARNING, "error in xcb_get_geometry");
121      free(error);
122   } else {
123      *w = reply->width;
124      *h = reply->height;
125   }
126   free(reply);
127}
128
129static void
130swrastPutImage(__DRIdrawable * draw, int op,
131               int x, int y, int w, int h,
132               char *data, void *loaderPrivate)
133{
134   struct dri2_egl_surface *dri2_surf = loaderPrivate;
135   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
136
137   xcb_gcontext_t gc;
138
139   switch (op) {
140   case __DRI_SWRAST_IMAGE_OP_DRAW:
141      gc = dri2_surf->gc;
142      break;
143   case __DRI_SWRAST_IMAGE_OP_SWAP:
144      gc = dri2_surf->swapgc;
145      break;
146   default:
147      return;
148   }
149
150   xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable,
151                 gc, w, h, x, y, 0, dri2_surf->depth,
152                 w*h*dri2_surf->bytes_per_pixel, (const uint8_t *)data);
153}
154
155static void
156swrastGetImage(__DRIdrawable * read,
157               int x, int y, int w, int h,
158               char *data, void *loaderPrivate)
159{
160   struct dri2_egl_surface *dri2_surf = loaderPrivate;
161   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
162
163   xcb_get_image_cookie_t cookie;
164   xcb_get_image_reply_t *reply;
165   xcb_generic_error_t *error;
166
167   cookie = xcb_get_image (dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
168                           dri2_surf->drawable, x, y, w, h, ~0);
169   reply = xcb_get_image_reply (dri2_dpy->conn, cookie, &error);
170   if (reply == NULL)
171      return;
172
173   if (error != NULL) {
174      _eglLog(_EGL_WARNING, "error in xcb_get_image");
175      free(error);
176   } else {
177      uint32_t bytes = xcb_get_image_data_length(reply);
178      uint8_t *idata = xcb_get_image_data(reply);
179      memcpy(data, idata, bytes);
180   }
181   free(reply);
182}
183
184
185static xcb_screen_t *
186get_xcb_screen(xcb_screen_iterator_t iter, int screen)
187{
188    for (; iter.rem; --screen, xcb_screen_next(&iter))
189        if (screen == 0)
190            return iter.data;
191
192    return NULL;
193}
194
195
196/**
197 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
198 */
199static _EGLSurface *
200dri2_x11_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
201                        _EGLConfig *conf, void *native_surface,
202                        const EGLint *attrib_list)
203{
204   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
205   struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
206   struct dri2_egl_surface *dri2_surf;
207   xcb_get_geometry_cookie_t cookie;
208   xcb_get_geometry_reply_t *reply;
209   xcb_generic_error_t *error;
210   xcb_drawable_t drawable;
211   const __DRIconfig *config;
212
213   STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
214   drawable = (uintptr_t) native_surface;
215
216   (void) drv;
217
218   dri2_surf = malloc(sizeof *dri2_surf);
219   if (!dri2_surf) {
220      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
221      return NULL;
222   }
223
224   if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
225      goto cleanup_surf;
226
227   dri2_surf->region = XCB_NONE;
228   if (type == EGL_PBUFFER_BIT) {
229      dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
230      xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
231                       dri2_surf->drawable, dri2_dpy->screen->root,
232			dri2_surf->base.Width, dri2_surf->base.Height);
233   } else {
234      if (!drawable) {
235         if (type == EGL_WINDOW_BIT)
236            _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface");
237         else
238            _eglError(EGL_BAD_NATIVE_PIXMAP, "dri2_create_surface");
239         goto cleanup_surf;
240      }
241      dri2_surf->drawable = drawable;
242   }
243
244   config = dri2_get_dri_config(dri2_conf, type,
245                                dri2_surf->base.GLColorspace);
246
247   if (dri2_dpy->dri2) {
248      dri2_surf->dri_drawable =
249         dri2_dpy->dri2->createNewDrawable(dri2_dpy->dri_screen, config,
250                                           dri2_surf);
251   } else {
252      assert(dri2_dpy->swrast);
253      dri2_surf->dri_drawable =
254         dri2_dpy->swrast->createNewDrawable(dri2_dpy->dri_screen, config,
255                                             dri2_surf);
256   }
257
258   if (dri2_surf->dri_drawable == NULL) {
259      _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
260      goto cleanup_pixmap;
261   }
262
263   if (type != EGL_PBUFFER_BIT) {
264      cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
265      reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
266      if (error != NULL) {
267         if (error->error_code == BadAlloc)
268            _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
269         else if (type == EGL_WINDOW_BIT)
270            _eglError(EGL_BAD_NATIVE_WINDOW, "xcb_get_geometry");
271         else
272            _eglError(EGL_BAD_NATIVE_PIXMAP, "xcb_get_geometry");
273         free(error);
274         goto cleanup_dri_drawable;
275      } else if (reply == NULL) {
276         _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
277         goto cleanup_dri_drawable;
278      }
279
280      dri2_surf->base.Width = reply->width;
281      dri2_surf->base.Height = reply->height;
282      dri2_surf->depth = reply->depth;
283      free(reply);
284   }
285
286   if (dri2_dpy->dri2) {
287      xcb_void_cookie_t cookie;
288      int conn_error;
289
290      cookie = xcb_dri2_create_drawable_checked(dri2_dpy->conn,
291                                                dri2_surf->drawable);
292      error = xcb_request_check(dri2_dpy->conn, cookie);
293      conn_error = xcb_connection_has_error(dri2_dpy->conn);
294      if (conn_error || error != NULL) {
295         if (type == EGL_PBUFFER_BIT || conn_error || error->error_code == BadAlloc)
296            _eglError(EGL_BAD_ALLOC, "xcb_dri2_create_drawable_checked");
297         else if (type == EGL_WINDOW_BIT)
298            _eglError(EGL_BAD_NATIVE_WINDOW,
299                      "xcb_dri2_create_drawable_checked");
300         else
301            _eglError(EGL_BAD_NATIVE_PIXMAP,
302                      "xcb_dri2_create_drawable_checked");
303         free(error);
304         goto cleanup_dri_drawable;
305      }
306   } else {
307      if (type == EGL_PBUFFER_BIT) {
308         dri2_surf->depth = _eglGetConfigKey(conf, EGL_BUFFER_SIZE);
309      }
310      swrastCreateDrawable(dri2_dpy, dri2_surf);
311   }
312
313   /* we always copy the back buffer to front */
314   dri2_surf->base.PostSubBufferSupportedNV = EGL_TRUE;
315
316   return &dri2_surf->base;
317
318 cleanup_dri_drawable:
319   dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
320 cleanup_pixmap:
321   if (type == EGL_PBUFFER_BIT)
322      xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);
323 cleanup_surf:
324   free(dri2_surf);
325
326   return NULL;
327}
328
329/**
330 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
331 */
332static _EGLSurface *
333dri2_x11_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
334                               _EGLConfig *conf, void *native_window,
335                               const EGLint *attrib_list)
336{
337   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
338   _EGLSurface *surf;
339
340   surf = dri2_x11_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
341                                  native_window, attrib_list);
342   if (surf != NULL) {
343      /* When we first create the DRI2 drawable, its swap interval on the
344       * server side is 1.
345       */
346      surf->SwapInterval = 1;
347
348      /* Override that with a driconf-set value. */
349      dri2_x11_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
350   }
351
352   return surf;
353}
354
355static _EGLSurface *
356dri2_x11_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
357                               _EGLConfig *conf, void *native_pixmap,
358                               const EGLint *attrib_list)
359{
360   return dri2_x11_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
361                                  native_pixmap, attrib_list);
362}
363
364static _EGLSurface *
365dri2_x11_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
366                                _EGLConfig *conf, const EGLint *attrib_list)
367{
368   return dri2_x11_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
369                                  XCB_WINDOW_NONE, attrib_list);
370}
371
372static EGLBoolean
373dri2_x11_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
374{
375   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
376   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
377
378   (void) drv;
379
380   dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
381
382   if (dri2_dpy->dri2) {
383      xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
384   } else {
385      assert(dri2_dpy->swrast);
386      swrastDestroyDrawable(dri2_dpy, dri2_surf);
387   }
388
389   if (surf->Type == EGL_PBUFFER_BIT)
390      xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
391
392   free(surf);
393
394   return EGL_TRUE;
395}
396
397/**
398 * Function utilizes swrastGetDrawableInfo to get surface
399 * geometry from x server and calls default query surface
400 * implementation that returns the updated values.
401 *
402 * In case of errors we still return values that we currently
403 * have.
404 */
405static EGLBoolean
406dri2_query_surface(_EGLDriver *drv, _EGLDisplay *dpy,
407                   _EGLSurface *surf, EGLint attribute,
408                   EGLint *value)
409{
410   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
411   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
412   int x, y, w = -1, h = -1;
413
414   __DRIdrawable *drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
415
416   switch (attribute) {
417   case EGL_WIDTH:
418   case EGL_HEIGHT:
419      swrastGetDrawableInfo(drawable, &x, &y, &w, &h, dri2_surf);
420      if (w != -1 && h != -1) {
421         surf->Width = w;
422         surf->Height = h;
423      }
424      break;
425   default:
426      break;
427   }
428   return _eglQuerySurface(drv, dpy, surf, attribute, value);
429}
430
431/**
432 * Process list of buffer received from the server
433 *
434 * Processes the list of buffers received in a reply from the server to either
435 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
436 */
437static void
438dri2_x11_process_buffers(struct dri2_egl_surface *dri2_surf,
439                         xcb_dri2_dri2_buffer_t *buffers, unsigned count)
440{
441   struct dri2_egl_display *dri2_dpy =
442      dri2_egl_display(dri2_surf->base.Resource.Display);
443   xcb_rectangle_t rectangle;
444   unsigned i;
445
446   dri2_surf->buffer_count = count;
447   dri2_surf->have_fake_front = 0;
448
449   /* This assumes the DRI2 buffer attachment tokens matches the
450    * __DRIbuffer tokens. */
451   for (i = 0; i < count; i++) {
452      dri2_surf->buffers[i].attachment = buffers[i].attachment;
453      dri2_surf->buffers[i].name = buffers[i].name;
454      dri2_surf->buffers[i].pitch = buffers[i].pitch;
455      dri2_surf->buffers[i].cpp = buffers[i].cpp;
456      dri2_surf->buffers[i].flags = buffers[i].flags;
457
458      /* We only use the DRI drivers single buffer configs.  This
459       * means that if we try to render to a window, DRI2 will give us
460       * the fake front buffer, which we'll use as a back buffer.
461       * Note that EGL doesn't require that several clients rendering
462       * to the same window must see the same aux buffers. */
463      if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
464         dri2_surf->have_fake_front = 1;
465   }
466
467   if (dri2_surf->region != XCB_NONE)
468      xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region);
469
470   rectangle.x = 0;
471   rectangle.y = 0;
472   rectangle.width = dri2_surf->base.Width;
473   rectangle.height = dri2_surf->base.Height;
474   dri2_surf->region = xcb_generate_id(dri2_dpy->conn);
475   xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle);
476}
477
478static __DRIbuffer *
479dri2_x11_get_buffers(__DRIdrawable * driDrawable,
480                     int *width, int *height,
481                     unsigned int *attachments, int count,
482                     int *out_count, void *loaderPrivate)
483{
484   struct dri2_egl_surface *dri2_surf = loaderPrivate;
485   struct dri2_egl_display *dri2_dpy =
486      dri2_egl_display(dri2_surf->base.Resource.Display);
487   xcb_dri2_dri2_buffer_t *buffers;
488   xcb_dri2_get_buffers_reply_t *reply;
489   xcb_dri2_get_buffers_cookie_t cookie;
490
491   (void) driDrawable;
492
493   cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
494					    dri2_surf->drawable,
495					    count, count, attachments);
496   reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL);
497   if (reply == NULL)
498      return NULL;
499   buffers = xcb_dri2_get_buffers_buffers (reply);
500   if (buffers == NULL)
501      return NULL;
502
503   *out_count = reply->count;
504   dri2_surf->base.Width = *width = reply->width;
505   dri2_surf->base.Height = *height = reply->height;
506   dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
507
508   free(reply);
509
510   return dri2_surf->buffers;
511}
512
513static __DRIbuffer *
514dri2_x11_get_buffers_with_format(__DRIdrawable * driDrawable,
515                                 int *width, int *height,
516                                 unsigned int *attachments, int count,
517                                 int *out_count, void *loaderPrivate)
518{
519   struct dri2_egl_surface *dri2_surf = loaderPrivate;
520   struct dri2_egl_display *dri2_dpy =
521      dri2_egl_display(dri2_surf->base.Resource.Display);
522   xcb_dri2_dri2_buffer_t *buffers;
523   xcb_dri2_get_buffers_with_format_reply_t *reply;
524   xcb_dri2_get_buffers_with_format_cookie_t cookie;
525   xcb_dri2_attach_format_t *format_attachments;
526
527   (void) driDrawable;
528
529   format_attachments = (xcb_dri2_attach_format_t *) attachments;
530   cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn,
531							dri2_surf->drawable,
532							count, count,
533							format_attachments);
534
535   reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn,
536						   cookie, NULL);
537   if (reply == NULL)
538      return NULL;
539
540   buffers = xcb_dri2_get_buffers_with_format_buffers (reply);
541   dri2_surf->base.Width = *width = reply->width;
542   dri2_surf->base.Height = *height = reply->height;
543   *out_count = reply->count;
544   dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
545
546   free(reply);
547
548   return dri2_surf->buffers;
549}
550
551static void
552dri2_x11_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
553{
554   (void) driDrawable;
555
556   /* FIXME: Does EGL support front buffer rendering at all? */
557
558#if 0
559   struct dri2_egl_surface *dri2_surf = loaderPrivate;
560
561   dri2WaitGL(dri2_surf);
562#else
563   (void) loaderPrivate;
564#endif
565}
566
567static int
568dri2_x11_do_authenticate(struct dri2_egl_display *dri2_dpy, uint32_t id)
569{
570   xcb_dri2_authenticate_reply_t *authenticate;
571   xcb_dri2_authenticate_cookie_t authenticate_cookie;
572   int ret = 0;
573
574   authenticate_cookie =
575      xcb_dri2_authenticate_unchecked(dri2_dpy->conn, dri2_dpy->screen->root, id);
576   authenticate =
577      xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);
578
579   if (authenticate == NULL || !authenticate->authenticated)
580      ret = -1;
581
582   free(authenticate);
583
584   return ret;
585}
586
587static EGLBoolean
588dri2_x11_local_authenticate(struct dri2_egl_display *dri2_dpy)
589{
590#ifdef HAVE_LIBDRM
591   drm_magic_t magic;
592
593   if (drmGetMagic(dri2_dpy->fd, &magic)) {
594      _eglLog(_EGL_WARNING, "DRI2: failed to get drm magic");
595      return EGL_FALSE;
596   }
597
598   if (dri2_x11_do_authenticate(dri2_dpy, magic) < 0) {
599      _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
600      return EGL_FALSE;
601   }
602#endif
603   return EGL_TRUE;
604}
605
606static EGLBoolean
607dri2_x11_connect(struct dri2_egl_display *dri2_dpy)
608{
609   xcb_xfixes_query_version_reply_t *xfixes_query;
610   xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
611   xcb_dri2_query_version_reply_t *dri2_query;
612   xcb_dri2_query_version_cookie_t dri2_query_cookie;
613   xcb_dri2_connect_reply_t *connect;
614   xcb_dri2_connect_cookie_t connect_cookie;
615   xcb_generic_error_t *error;
616   char *driver_name, *loader_driver_name, *device_name;
617   const xcb_query_extension_reply_t *extension;
618
619   xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
620   xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
621
622   extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
623   if (!(extension && extension->present))
624      return EGL_FALSE;
625
626   extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri2_id);
627   if (!(extension && extension->present))
628      return EGL_FALSE;
629
630   xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
631						  XCB_XFIXES_MAJOR_VERSION,
632						  XCB_XFIXES_MINOR_VERSION);
633
634   dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn,
635					       XCB_DRI2_MAJOR_VERSION,
636					       XCB_DRI2_MINOR_VERSION);
637
638   connect_cookie = xcb_dri2_connect_unchecked(dri2_dpy->conn, dri2_dpy->screen->root,
639                                   XCB_DRI2_DRIVER_TYPE_DRI);
640
641   xfixes_query =
642      xcb_xfixes_query_version_reply (dri2_dpy->conn,
643				      xfixes_query_cookie, &error);
644   if (xfixes_query == NULL ||
645       error != NULL || xfixes_query->major_version < 2) {
646      _eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version");
647      free(error);
648      return EGL_FALSE;
649   }
650   free(xfixes_query);
651
652   dri2_query =
653      xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);
654   if (dri2_query == NULL || error != NULL) {
655      _eglLog(_EGL_WARNING, "DRI2: failed to query version");
656      free(error);
657      return EGL_FALSE;
658   }
659   dri2_dpy->dri2_major = dri2_query->major_version;
660   dri2_dpy->dri2_minor = dri2_query->minor_version;
661   free(dri2_query);
662
663   connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);
664   if (connect == NULL ||
665       connect->driver_name_length + connect->device_name_length == 0) {
666      _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
667      return EGL_FALSE;
668   }
669
670   device_name = xcb_dri2_connect_device_name (connect);
671
672   dri2_dpy->fd = loader_open_device(device_name);
673   if (dri2_dpy->fd == -1) {
674      _eglLog(_EGL_WARNING,
675              "DRI2: could not open %s (%s)", device_name, strerror(errno));
676      free(connect);
677      return EGL_FALSE;
678   }
679
680   if (!dri2_x11_local_authenticate(dri2_dpy)) {
681      close(dri2_dpy->fd);
682      free(connect);
683      return EGL_FALSE;
684   }
685
686   driver_name = xcb_dri2_connect_driver_name (connect);
687
688   /* If Mesa knows about the appropriate driver for this fd, then trust it.
689    * Otherwise, default to the server's value.
690    */
691   loader_driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
692   if (loader_driver_name) {
693      dri2_dpy->driver_name = loader_driver_name;
694   } else {
695      dri2_dpy->driver_name =
696         strndup(driver_name,
697                 xcb_dri2_connect_driver_name_length(connect));
698   }
699
700   if (dri2_dpy->driver_name == NULL) {
701      close(dri2_dpy->fd);
702      free(dri2_dpy->driver_name);
703      free(connect);
704      return EGL_FALSE;
705   }
706
707#ifdef HAVE_WAYLAND_PLATFORM
708   dri2_dpy->device_name =
709      strndup(device_name,
710              xcb_dri2_connect_device_name_length(connect));
711#endif
712
713   free(connect);
714
715   return EGL_TRUE;
716}
717
718static int
719dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id)
720{
721   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
722
723   return dri2_x11_do_authenticate(dri2_dpy, id);
724}
725
726static EGLBoolean
727dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
728                                 _EGLDisplay *disp, bool supports_preserved)
729{
730   xcb_depth_iterator_t d;
731   xcb_visualtype_t *visuals;
732   int i, j, count;
733   unsigned int rgba_masks[4];
734   EGLint surface_type;
735   EGLint config_attrs[] = {
736	   EGL_NATIVE_VISUAL_ID,   0,
737	   EGL_NATIVE_VISUAL_TYPE, 0,
738	   EGL_NONE
739   };
740
741   d = xcb_screen_allowed_depths_iterator(dri2_dpy->screen);
742   count = 0;
743
744   surface_type =
745      EGL_WINDOW_BIT |
746      EGL_PIXMAP_BIT |
747      EGL_PBUFFER_BIT;
748
749   if (supports_preserved)
750      surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
751
752   while (d.rem > 0) {
753      EGLBoolean class_added[6] = { 0, };
754
755      visuals = xcb_depth_visuals(d.data);
756      for (i = 0; i < xcb_depth_visuals_length(d.data); i++) {
757	 if (class_added[visuals[i]._class])
758	    continue;
759
760	 class_added[visuals[i]._class] = EGL_TRUE;
761	 for (j = 0; dri2_dpy->driver_configs[j]; j++) {
762            struct dri2_egl_config *dri2_conf;
763            const __DRIconfig *config = dri2_dpy->driver_configs[j];
764
765            config_attrs[1] = visuals[i].visual_id;
766            config_attrs[3] = visuals[i]._class;
767
768            rgba_masks[0] = visuals[i].red_mask;
769            rgba_masks[1] = visuals[i].green_mask;
770            rgba_masks[2] = visuals[i].blue_mask;
771            rgba_masks[3] = 0;
772            dri2_conf = dri2_add_config(disp, config, count + 1, surface_type,
773                                        config_attrs, rgba_masks);
774            if (dri2_conf)
775               count++;
776
777            /* Allow a 24-bit RGB visual to match a 32-bit RGBA EGLConfig.
778             * Otherwise it will only match a 32-bit RGBA visual.  On a
779             * composited window manager on X11, this will make all of the
780             * EGLConfigs with destination alpha get blended by the
781             * compositor.  This is probably not what the application
782             * wants... especially on drivers that only have 32-bit RGBA
783             * EGLConfigs! */
784            if (d.data->depth == 24) {
785               rgba_masks[3] =
786                  ~(rgba_masks[0] | rgba_masks[1] | rgba_masks[2]);
787               dri2_conf = dri2_add_config(disp, config, count + 1, surface_type,
788                                           config_attrs, rgba_masks);
789               if (dri2_conf)
790                  count++;
791            }
792	 }
793      }
794
795      xcb_depth_next(&d);
796   }
797
798   if (!count) {
799      _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
800      return EGL_FALSE;
801   }
802
803   return EGL_TRUE;
804}
805
806static EGLBoolean
807dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp,
808		 _EGLSurface *draw, xcb_xfixes_region_t region)
809{
810   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
811   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
812   enum xcb_dri2_attachment_t render_attachment;
813   xcb_dri2_copy_region_cookie_t cookie;
814
815   /* No-op for a pixmap or pbuffer surface */
816   if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
817      return EGL_TRUE;
818
819   if (dri2_dpy->flush)
820      dri2_dpy->flush->flush(dri2_surf->dri_drawable);
821
822   if (dri2_surf->have_fake_front)
823      render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT;
824   else
825      render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT;
826
827   cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
828					   dri2_surf->drawable,
829					   region,
830					   XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
831					   render_attachment);
832   free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
833
834   return EGL_TRUE;
835}
836
837static int64_t
838dri2_x11_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
839                          int64_t msc, int64_t divisor, int64_t remainder)
840{
841   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
842   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
843   uint32_t msc_hi = msc >> 32;
844   uint32_t msc_lo = msc & 0xffffffff;
845   uint32_t divisor_hi = divisor >> 32;
846   uint32_t divisor_lo = divisor & 0xffffffff;
847   uint32_t remainder_hi = remainder >> 32;
848   uint32_t remainder_lo = remainder & 0xffffffff;
849   xcb_dri2_swap_buffers_cookie_t cookie;
850   xcb_dri2_swap_buffers_reply_t *reply;
851   int64_t swap_count = -1;
852
853   /* No-op for a pixmap or pbuffer surface */
854   if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
855      return 0;
856
857   if (draw->SwapBehavior == EGL_BUFFER_PRESERVED || !dri2_dpy->swap_available)
858      return dri2_copy_region(drv, disp, draw, dri2_surf->region) ? 0 : -1;
859
860   dri2_flush_drawable_for_swapbuffers(disp, draw);
861
862   cookie = xcb_dri2_swap_buffers_unchecked(dri2_dpy->conn, dri2_surf->drawable,
863                  msc_hi, msc_lo, divisor_hi, divisor_lo, remainder_hi, remainder_lo);
864
865   reply = xcb_dri2_swap_buffers_reply(dri2_dpy->conn, cookie, NULL);
866
867   if (reply) {
868      swap_count = (((int64_t)reply->swap_hi) << 32) | reply->swap_lo;
869      free(reply);
870   }
871
872   /* Since we aren't watching for the server's invalidate events like we're
873    * supposed to (due to XCB providing no mechanism for filtering the events
874    * the way xlib does), and SwapBuffers is a common cause of invalidate
875    * events, just shove one down to the driver, even though we haven't told
876    * the driver that we're the kind of loader that provides reliable
877    * invalidate events.  This causes the driver to request buffers again at
878    * its next draw, so that we get the correct buffers if a pageflip
879    * happened.  The driver should still be using the viewport hack to catch
880    * window resizes.
881    */
882   if (dri2_dpy->flush &&
883       dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate)
884      dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
885
886   return swap_count;
887}
888
889static EGLBoolean
890dri2_x11_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
891{
892   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
893   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
894
895   if (dri2_dpy->dri2) {
896      if (dri2_x11_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1) {
897          return EGL_TRUE;
898      }
899      /* Swap failed with a window drawable. */
900      _eglError(EGL_BAD_NATIVE_WINDOW, __func__);
901      return EGL_FALSE;
902   } else {
903      assert(dri2_dpy->swrast);
904
905      dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
906      return EGL_TRUE;
907   }
908}
909
910static EGLBoolean
911dri2_x11_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp,
912                             _EGLSurface *draw,
913                             EGLint numRects, const EGLint *rects)
914{
915   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
916   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
917   EGLBoolean ret;
918   xcb_xfixes_region_t region;
919   xcb_rectangle_t rectangles[16];
920   int i;
921
922   if (numRects > (int)ARRAY_SIZE(rectangles))
923      return dri2_copy_region(drv, disp, draw, dri2_surf->region);
924
925   for (i = 0; i < numRects; i++) {
926      rectangles[i].x = rects[i * 4];
927      rectangles[i].y = dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3];
928      rectangles[i].width = rects[i * 4 + 2];
929      rectangles[i].height = rects[i * 4 + 3];
930   }
931
932   region = xcb_generate_id(dri2_dpy->conn);
933   xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles);
934   ret = dri2_copy_region(drv, disp, draw, region);
935   xcb_xfixes_destroy_region(dri2_dpy->conn, region);
936
937   return ret;
938}
939
940static EGLBoolean
941dri2_x11_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
942		     EGLint x, EGLint y, EGLint width, EGLint height)
943{
944   const EGLint rect[4] = { x, y, width, height };
945
946   if (x < 0 || y < 0 || width < 0 || height < 0)
947      _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV");
948
949   return dri2_x11_swap_buffers_region(drv, disp, draw, 1, rect);
950}
951
952static EGLBoolean
953dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
954                       EGLint interval)
955{
956   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
957   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
958
959   if (interval > surf->Config->MaxSwapInterval)
960      interval = surf->Config->MaxSwapInterval;
961   else if (interval < surf->Config->MinSwapInterval)
962      interval = surf->Config->MinSwapInterval;
963
964   if (interval != surf->SwapInterval && dri2_dpy->swap_available)
965      xcb_dri2_swap_interval(dri2_dpy->conn, dri2_surf->drawable, interval);
966
967   surf->SwapInterval = interval;
968
969   return EGL_TRUE;
970}
971
972static EGLBoolean
973dri2_x11_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
974                      void *native_pixmap_target)
975{
976   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
977   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
978   xcb_gcontext_t gc;
979   xcb_pixmap_t target;
980
981   STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
982   target = (uintptr_t) native_pixmap_target;
983
984   (void) drv;
985
986   dri2_dpy->flush->flush(dri2_surf->dri_drawable);
987
988   gc = xcb_generate_id(dri2_dpy->conn);
989   xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL);
990   xcb_copy_area(dri2_dpy->conn,
991		  dri2_surf->drawable,
992		  target,
993		  gc,
994		  0, 0,
995		  0, 0,
996		  dri2_surf->base.Width,
997		  dri2_surf->base.Height);
998   xcb_free_gc(dri2_dpy->conn, gc);
999
1000   return EGL_TRUE;
1001}
1002
1003static _EGLImage *
1004dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
1005			     EGLClientBuffer buffer, const EGLint *attr_list)
1006{
1007   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1008   struct dri2_egl_image *dri2_img;
1009   unsigned int attachments[1];
1010   xcb_drawable_t drawable;
1011   xcb_dri2_get_buffers_cookie_t buffers_cookie;
1012   xcb_dri2_get_buffers_reply_t *buffers_reply;
1013   xcb_dri2_dri2_buffer_t *buffers;
1014   xcb_get_geometry_cookie_t geometry_cookie;
1015   xcb_get_geometry_reply_t *geometry_reply;
1016   xcb_generic_error_t *error;
1017   int stride, format;
1018
1019   (void) ctx;
1020
1021   drawable = (xcb_drawable_t) (uintptr_t) buffer;
1022   xcb_dri2_create_drawable (dri2_dpy->conn, drawable);
1023   attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;
1024   buffers_cookie =
1025      xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
1026				      drawable, 1, 1, attachments);
1027   geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable);
1028   buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn,
1029					       buffers_cookie, NULL);
1030   if (buffers_reply == NULL)
1031     return NULL;
1032
1033   buffers = xcb_dri2_get_buffers_buffers (buffers_reply);
1034   if (buffers == NULL) {
1035      return NULL;
1036   }
1037
1038   geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn,
1039					    geometry_cookie, &error);
1040   if (geometry_reply == NULL || error != NULL) {
1041      _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
1042      free(error);
1043      free(buffers_reply);
1044      return NULL;
1045   }
1046
1047   switch (geometry_reply->depth) {
1048   case 16:
1049      format = __DRI_IMAGE_FORMAT_RGB565;
1050      break;
1051   case 24:
1052      format = __DRI_IMAGE_FORMAT_XRGB8888;
1053      break;
1054   case 32:
1055      format = __DRI_IMAGE_FORMAT_ARGB8888;
1056      break;
1057   default:
1058      _eglError(EGL_BAD_PARAMETER,
1059		"dri2_create_image_khr: unsupported pixmap depth");
1060      free(buffers_reply);
1061      free(geometry_reply);
1062      return NULL;
1063   }
1064
1065   dri2_img = malloc(sizeof *dri2_img);
1066   if (!dri2_img) {
1067      free(buffers_reply);
1068      free(geometry_reply);
1069      _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
1070      return EGL_NO_IMAGE_KHR;
1071   }
1072
1073   if (!_eglInitImage(&dri2_img->base, disp)) {
1074      free(buffers_reply);
1075      free(geometry_reply);
1076      free(dri2_img);
1077      return EGL_NO_IMAGE_KHR;
1078   }
1079
1080   stride = buffers[0].pitch / buffers[0].cpp;
1081   dri2_img->dri_image =
1082      dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
1083					   buffers_reply->width,
1084					   buffers_reply->height,
1085					   format,
1086					   buffers[0].name,
1087					   stride,
1088					   dri2_img);
1089
1090   free(buffers_reply);
1091   free(geometry_reply);
1092
1093   return &dri2_img->base;
1094}
1095
1096static _EGLImage *
1097dri2_x11_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
1098			  _EGLContext *ctx, EGLenum target,
1099			  EGLClientBuffer buffer, const EGLint *attr_list)
1100{
1101   (void) drv;
1102
1103   switch (target) {
1104   case EGL_NATIVE_PIXMAP_KHR:
1105      return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
1106   default:
1107      return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
1108   }
1109}
1110
1111static EGLBoolean
1112dri2_x11_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
1113                         EGLuint64KHR *ust, EGLuint64KHR *msc,
1114                         EGLuint64KHR *sbc)
1115{
1116   struct dri2_egl_display *dri2_dpy = dri2_egl_display(display);
1117   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
1118   xcb_dri2_get_msc_cookie_t cookie;
1119   xcb_dri2_get_msc_reply_t *reply;
1120
1121   cookie = xcb_dri2_get_msc(dri2_dpy->conn, dri2_surf->drawable);
1122   reply = xcb_dri2_get_msc_reply(dri2_dpy->conn, cookie, NULL);
1123
1124   if (!reply) {
1125      _eglError(EGL_BAD_ACCESS, __func__);
1126      return EGL_FALSE;
1127   }
1128
1129   *ust = ((EGLuint64KHR) reply->ust_hi << 32) | reply->ust_lo;
1130   *msc = ((EGLuint64KHR) reply->msc_hi << 32) | reply->msc_lo;
1131   *sbc = ((EGLuint64KHR) reply->sbc_hi << 32) | reply->sbc_lo;
1132   free(reply);
1133
1134   return EGL_TRUE;
1135}
1136
1137static struct dri2_egl_display_vtbl dri2_x11_swrast_display_vtbl = {
1138   .authenticate = NULL,
1139   .create_window_surface = dri2_x11_create_window_surface,
1140   .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1141   .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1142   .destroy_surface = dri2_x11_destroy_surface,
1143   .create_image = dri2_fallback_create_image_khr,
1144   .swap_interval = dri2_fallback_swap_interval,
1145   .swap_buffers = dri2_x11_swap_buffers,
1146   .swap_buffers_region = dri2_fallback_swap_buffers_region,
1147   .post_sub_buffer = dri2_fallback_post_sub_buffer,
1148   .copy_buffers = dri2_x11_copy_buffers,
1149   .query_buffer_age = dri2_fallback_query_buffer_age,
1150   .query_surface = dri2_query_surface,
1151   .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
1152   .get_sync_values = dri2_fallback_get_sync_values,
1153   .get_dri_drawable = dri2_surface_get_dri_drawable,
1154};
1155
1156static struct dri2_egl_display_vtbl dri2_x11_display_vtbl = {
1157   .authenticate = dri2_x11_authenticate,
1158   .create_window_surface = dri2_x11_create_window_surface,
1159   .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1160   .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1161   .destroy_surface = dri2_x11_destroy_surface,
1162   .create_image = dri2_x11_create_image_khr,
1163   .swap_interval = dri2_x11_swap_interval,
1164   .swap_buffers = dri2_x11_swap_buffers,
1165   .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
1166   .swap_buffers_region = dri2_x11_swap_buffers_region,
1167   .post_sub_buffer = dri2_x11_post_sub_buffer,
1168   .copy_buffers = dri2_x11_copy_buffers,
1169   .query_buffer_age = dri2_fallback_query_buffer_age,
1170   .query_surface = dri2_query_surface,
1171   .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
1172   .get_sync_values = dri2_x11_get_sync_values,
1173   .get_dri_drawable = dri2_surface_get_dri_drawable,
1174};
1175
1176static const __DRIswrastLoaderExtension swrast_loader_extension = {
1177   .base = { __DRI_SWRAST_LOADER, 1 },
1178
1179   .getDrawableInfo = swrastGetDrawableInfo,
1180   .putImage        = swrastPutImage,
1181   .getImage        = swrastGetImage,
1182};
1183
1184static const __DRIextension *swrast_loader_extensions[] = {
1185   &swrast_loader_extension.base,
1186   NULL,
1187};
1188
1189static EGLBoolean
1190dri2_get_xcb_connection(_EGLDriver *drv, _EGLDisplay *disp,
1191                        struct dri2_egl_display *dri2_dpy)
1192{
1193   xcb_screen_iterator_t s;
1194   int screen = 0;
1195   const char *msg;
1196
1197   disp->DriverData = (void *) dri2_dpy;
1198   if (disp->PlatformDisplay == NULL) {
1199      dri2_dpy->conn = xcb_connect(NULL, &screen);
1200      dri2_dpy->own_device = true;
1201   } else {
1202      Display *dpy = disp->PlatformDisplay;
1203
1204      dri2_dpy->conn = XGetXCBConnection(dpy);
1205      screen = DefaultScreen(dpy);
1206   }
1207
1208   if (!dri2_dpy->conn || xcb_connection_has_error(dri2_dpy->conn)) {
1209      msg = "xcb_connect failed";
1210      goto disconnect;
1211   }
1212
1213   s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
1214   dri2_dpy->screen = get_xcb_screen(s, screen);
1215   if (!dri2_dpy->screen) {
1216      msg = "failed to get xcb screen";
1217      goto disconnect;
1218   }
1219
1220   return EGL_TRUE;
1221disconnect:
1222   if (disp->PlatformDisplay == NULL)
1223      xcb_disconnect(dri2_dpy->conn);
1224
1225   return _eglError(EGL_BAD_ALLOC, msg);
1226}
1227
1228static EGLBoolean
1229dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp)
1230{
1231   struct dri2_egl_display *dri2_dpy;
1232
1233   dri2_dpy = calloc(1, sizeof *dri2_dpy);
1234   if (!dri2_dpy)
1235      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1236
1237   if (!dri2_get_xcb_connection(drv, disp, dri2_dpy))
1238      goto cleanup_dpy;
1239
1240   /*
1241    * Every hardware driver_name is set using strdup. Doing the same in
1242    * here will allow is to simply free the memory at dri2_terminate().
1243    */
1244   dri2_dpy->fd = -1;
1245   dri2_dpy->driver_name = strdup("swrast");
1246   if (!dri2_load_driver_swrast(disp))
1247      goto cleanup_conn;
1248
1249   dri2_dpy->loader_extensions = swrast_loader_extensions;
1250
1251   if (!dri2_create_screen(disp))
1252      goto cleanup_driver;
1253
1254   if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true))
1255      goto cleanup_configs;
1256
1257   /* Fill vtbl last to prevent accidentally calling virtual function during
1258    * initialization.
1259    */
1260   dri2_dpy->vtbl = &dri2_x11_swrast_display_vtbl;
1261
1262   return EGL_TRUE;
1263
1264 cleanup_configs:
1265   _eglCleanupDisplay(disp);
1266   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1267 cleanup_driver:
1268   dlclose(dri2_dpy->driver);
1269 cleanup_conn:
1270   free(dri2_dpy->driver_name);
1271   if (disp->PlatformDisplay == NULL)
1272      xcb_disconnect(dri2_dpy->conn);
1273 cleanup_dpy:
1274   free(dri2_dpy);
1275   disp->DriverData = NULL;
1276
1277   return EGL_FALSE;
1278}
1279
1280static void
1281dri2_x11_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
1282{
1283   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
1284   int arbitrary_max_interval = 1000;
1285
1286   /* default behavior for no SwapBuffers support: no vblank syncing
1287    * either.
1288    */
1289   dri2_dpy->min_swap_interval = 0;
1290   dri2_dpy->max_swap_interval = 0;
1291
1292   if (!dri2_dpy->swap_available)
1293      return;
1294
1295   /* If we do have swapbuffers, then we can support pretty much any swap
1296    * interval, but we allow driconf to override applications.
1297    */
1298   if (dri2_dpy->config)
1299      dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
1300                                     "vblank_mode", &vblank_mode);
1301   switch (vblank_mode) {
1302   case DRI_CONF_VBLANK_NEVER:
1303      dri2_dpy->min_swap_interval = 0;
1304      dri2_dpy->max_swap_interval = 0;
1305      dri2_dpy->default_swap_interval = 0;
1306      break;
1307   case DRI_CONF_VBLANK_ALWAYS_SYNC:
1308      dri2_dpy->min_swap_interval = 1;
1309      dri2_dpy->max_swap_interval = arbitrary_max_interval;
1310      dri2_dpy->default_swap_interval = 1;
1311      break;
1312   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
1313      dri2_dpy->min_swap_interval = 0;
1314      dri2_dpy->max_swap_interval = arbitrary_max_interval;
1315      dri2_dpy->default_swap_interval = 0;
1316      break;
1317   default:
1318   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
1319      dri2_dpy->min_swap_interval = 0;
1320      dri2_dpy->max_swap_interval = arbitrary_max_interval;
1321      dri2_dpy->default_swap_interval = 1;
1322      break;
1323   }
1324}
1325
1326#ifdef HAVE_DRI3
1327
1328static const __DRIextension *dri3_image_loader_extensions[] = {
1329   &dri3_image_loader_extension.base,
1330   &image_lookup_extension.base,
1331   &use_invalidate.base,
1332   NULL,
1333};
1334
1335static EGLBoolean
1336dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp)
1337{
1338   struct dri2_egl_display *dri2_dpy;
1339
1340   dri2_dpy = calloc(1, sizeof *dri2_dpy);
1341   if (!dri2_dpy)
1342      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1343
1344   if (!dri2_get_xcb_connection(drv, disp, dri2_dpy))
1345      goto cleanup_dpy;
1346
1347   if (!dri3_x11_connect(dri2_dpy))
1348      goto cleanup_conn;
1349
1350   if (!dri2_load_driver_dri3(disp))
1351      goto cleanup_conn;
1352
1353   dri2_dpy->loader_extensions = dri3_image_loader_extensions;
1354
1355   dri2_dpy->swap_available = true;
1356   dri2_dpy->invalidate_available = true;
1357
1358   if (!dri2_create_screen(disp))
1359      goto cleanup_fd;
1360
1361   dri2_x11_setup_swap_interval(dri2_dpy);
1362
1363   if (!dri2_dpy->is_different_gpu)
1364      disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1365   disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1366   disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
1367   disp->Extensions.EXT_buffer_age = EGL_TRUE;
1368
1369   dri2_set_WL_bind_wayland_display(drv, disp);
1370
1371   if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false))
1372      goto cleanup_configs;
1373
1374   dri2_dpy->loader_dri3_ext.core = dri2_dpy->core;
1375   dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver;
1376   dri2_dpy->loader_dri3_ext.flush = dri2_dpy->flush;
1377   dri2_dpy->loader_dri3_ext.tex_buffer = dri2_dpy->tex_buffer;
1378   dri2_dpy->loader_dri3_ext.image = dri2_dpy->image;
1379   dri2_dpy->loader_dri3_ext.config = dri2_dpy->config;
1380
1381   /* Fill vtbl last to prevent accidentally calling virtual function during
1382    * initialization.
1383    */
1384   dri2_dpy->vtbl = &dri3_x11_display_vtbl;
1385
1386   _eglLog(_EGL_INFO, "Using DRI3");
1387
1388   return EGL_TRUE;
1389
1390 cleanup_configs:
1391   _eglCleanupDisplay(disp);
1392   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1393   dlclose(dri2_dpy->driver);
1394 cleanup_fd:
1395   close(dri2_dpy->fd);
1396 cleanup_conn:
1397   if (disp->PlatformDisplay == NULL)
1398      xcb_disconnect(dri2_dpy->conn);
1399 cleanup_dpy:
1400   free(dri2_dpy);
1401   disp->DriverData = NULL;
1402
1403   return EGL_FALSE;
1404}
1405#endif
1406
1407static const __DRIdri2LoaderExtension dri2_loader_extension_old = {
1408   .base = { __DRI_DRI2_LOADER, 2 },
1409
1410   .getBuffers           = dri2_x11_get_buffers,
1411   .flushFrontBuffer     = dri2_x11_flush_front_buffer,
1412   .getBuffersWithFormat = NULL,
1413};
1414
1415static const __DRIdri2LoaderExtension dri2_loader_extension = {
1416   .base = { __DRI_DRI2_LOADER, 3 },
1417
1418   .getBuffers           = dri2_x11_get_buffers,
1419   .flushFrontBuffer     = dri2_x11_flush_front_buffer,
1420   .getBuffersWithFormat = dri2_x11_get_buffers_with_format,
1421};
1422
1423static const __DRIextension *dri2_loader_extensions_old[] = {
1424   &dri2_loader_extension_old.base,
1425   &image_lookup_extension.base,
1426   NULL,
1427};
1428
1429static const __DRIextension *dri2_loader_extensions[] = {
1430   &dri2_loader_extension.base,
1431   &image_lookup_extension.base,
1432   NULL,
1433};
1434
1435static EGLBoolean
1436dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
1437{
1438   struct dri2_egl_display *dri2_dpy;
1439
1440   dri2_dpy = calloc(1, sizeof *dri2_dpy);
1441   if (!dri2_dpy)
1442      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1443
1444   if (!dri2_get_xcb_connection(drv, disp, dri2_dpy))
1445      goto cleanup_dpy;
1446
1447   if (!dri2_x11_connect(dri2_dpy))
1448      goto cleanup_conn;
1449
1450   if (!dri2_load_driver(disp))
1451      goto cleanup_fd;
1452
1453   if (dri2_dpy->dri2_minor >= 1)
1454      dri2_dpy->loader_extensions = dri2_loader_extensions;
1455   else
1456      dri2_dpy->loader_extensions = dri2_loader_extensions_old;
1457
1458   dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2);
1459   dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3);
1460
1461   if (!dri2_create_screen(disp))
1462      goto cleanup_driver;
1463
1464   dri2_x11_setup_swap_interval(dri2_dpy);
1465
1466   disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1467   disp->Extensions.NOK_swap_region = EGL_TRUE;
1468   disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1469   disp->Extensions.NV_post_sub_buffer = EGL_TRUE;
1470   disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
1471
1472   dri2_set_WL_bind_wayland_display(drv, disp);
1473
1474   if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true))
1475      goto cleanup_configs;
1476
1477   /* Fill vtbl last to prevent accidentally calling virtual function during
1478    * initialization.
1479    */
1480   dri2_dpy->vtbl = &dri2_x11_display_vtbl;
1481
1482   _eglLog(_EGL_INFO, "Using DRI2");
1483
1484   return EGL_TRUE;
1485
1486 cleanup_configs:
1487   _eglCleanupDisplay(disp);
1488   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1489 cleanup_driver:
1490   dlclose(dri2_dpy->driver);
1491 cleanup_fd:
1492   close(dri2_dpy->fd);
1493 cleanup_conn:
1494   if (disp->PlatformDisplay == NULL)
1495      xcb_disconnect(dri2_dpy->conn);
1496 cleanup_dpy:
1497   free(dri2_dpy);
1498   disp->DriverData = NULL;
1499
1500   return EGL_FALSE;
1501}
1502
1503EGLBoolean
1504dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)
1505{
1506   EGLBoolean initialized = EGL_FALSE;
1507
1508   if (!getenv("LIBGL_ALWAYS_SOFTWARE")) {
1509#ifdef HAVE_DRI3
1510      if (!getenv("LIBGL_DRI3_DISABLE"))
1511         initialized = dri2_initialize_x11_dri3(drv, disp);
1512#endif
1513
1514      if (!initialized)
1515         initialized = dri2_initialize_x11_dri2(drv, disp);
1516   }
1517
1518   if (!initialized)
1519      initialized = dri2_initialize_x11_swrast(drv, disp);
1520
1521   return initialized;
1522}
1523
1524