Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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