Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Copyright © 2011-2012 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.  *    Benjamin Franzke <benjaminfranzke@googlemail.com>
  27.  */
  28.  
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <limits.h>
  32. #include <dlfcn.h>
  33. #include <errno.h>
  34. #include <unistd.h>
  35. #include <fcntl.h>
  36. #include <xf86drm.h>
  37.  
  38. #include "egl_dri2.h"
  39.  
  40. #include <wayland-client.h>
  41. #include "wayland-drm-client-protocol.h"
  42.  
  43. enum wl_drm_format_flags {
  44.    HAS_ARGB8888 = 1,
  45.    HAS_XRGB8888 = 2
  46. };
  47.  
  48. static void
  49. sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
  50. {
  51.    int *done = data;
  52.  
  53.    *done = 1;
  54.    wl_callback_destroy(callback);
  55. }
  56.  
  57. static const struct wl_callback_listener sync_listener = {
  58.    sync_callback
  59. };
  60.  
  61. static int
  62. roundtrip(struct dri2_egl_display *dri2_dpy)
  63. {
  64.    struct wl_callback *callback;
  65.    int done = 0, ret = 0;
  66.  
  67.    callback = wl_display_sync(dri2_dpy->wl_dpy);
  68.    wl_callback_add_listener(callback, &sync_listener, &done);
  69.    wl_proxy_set_queue((struct wl_proxy *) callback, dri2_dpy->wl_queue);
  70.    while (ret != -1 && !done)
  71.       ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
  72.  
  73.    if (!done)
  74.       wl_callback_destroy(callback);
  75.  
  76.    return ret;
  77. }
  78.  
  79. static void
  80. wl_buffer_release(void *data, struct wl_buffer *buffer)
  81. {
  82.    struct dri2_egl_surface *dri2_surf = data;
  83.    int i;
  84.  
  85.    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
  86.       if (dri2_surf->color_buffers[i].wl_buffer == buffer)
  87.          break;
  88.  
  89.    if (i == ARRAY_SIZE(dri2_surf->color_buffers)) {
  90.       wl_buffer_destroy(buffer);
  91.       return;
  92.    }
  93.  
  94.    dri2_surf->color_buffers[i].locked = 0;
  95. }
  96.  
  97. static struct wl_buffer_listener wl_buffer_listener = {
  98.    wl_buffer_release
  99. };
  100.  
  101. static void
  102. resize_callback(struct wl_egl_window *wl_win, void *data)
  103. {
  104.    struct dri2_egl_surface *dri2_surf = data;
  105.    struct dri2_egl_display *dri2_dpy =
  106.       dri2_egl_display(dri2_surf->base.Resource.Display);
  107.  
  108.    (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
  109. }
  110.  
  111. /**
  112.  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
  113.  */
  114. static _EGLSurface *
  115. dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
  116.                     _EGLConfig *conf, EGLNativeWindowType window,
  117.                     const EGLint *attrib_list)
  118. {
  119.    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  120.    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
  121.    struct dri2_egl_surface *dri2_surf;
  122.  
  123.    (void) drv;
  124.  
  125.    dri2_surf = malloc(sizeof *dri2_surf);
  126.    if (!dri2_surf) {
  127.       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
  128.       return NULL;
  129.    }
  130.    
  131.    memset(dri2_surf, 0, sizeof *dri2_surf);
  132.    if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
  133.       goto cleanup_surf;
  134.  
  135.    if (conf->AlphaSize == 0)
  136.       dri2_surf->format = WL_DRM_FORMAT_XRGB8888;
  137.    else
  138.       dri2_surf->format = WL_DRM_FORMAT_ARGB8888;
  139.  
  140.    switch (type) {
  141.    case EGL_WINDOW_BIT:
  142.       dri2_surf->wl_win = (struct wl_egl_window *) window;
  143.  
  144.       dri2_surf->wl_win->private = dri2_surf;
  145.       dri2_surf->wl_win->resize_callback = resize_callback;
  146.  
  147.       dri2_surf->base.Width =  -1;
  148.       dri2_surf->base.Height = -1;
  149.       break;
  150.    default:
  151.       goto cleanup_surf;
  152.    }
  153.  
  154.    dri2_surf->dri_drawable =
  155.       (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
  156.                                             type == EGL_WINDOW_BIT ?
  157.                                             dri2_conf->dri_double_config :
  158.                                             dri2_conf->dri_single_config,
  159.                                             dri2_surf);
  160.    if (dri2_surf->dri_drawable == NULL) {
  161.       _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
  162.       goto cleanup_dri_drawable;
  163.    }
  164.  
  165.    return &dri2_surf->base;
  166.  
  167.  cleanup_dri_drawable:
  168.    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
  169.  cleanup_surf:
  170.    free(dri2_surf);
  171.  
  172.    return NULL;
  173. }
  174.  
  175. /**
  176.  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
  177.  */
  178. static _EGLSurface *
  179. dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
  180.                            _EGLConfig *conf, EGLNativeWindowType window,
  181.                            const EGLint *attrib_list)
  182. {
  183.    return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
  184.                               window, attrib_list);
  185. }
  186.  
  187. /**
  188.  * Called via eglDestroySurface(), drv->API.DestroySurface().
  189.  */
  190. static EGLBoolean
  191. dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
  192. {
  193.    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  194.    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
  195.    int i;
  196.  
  197.    (void) drv;
  198.  
  199.    if (!_eglPutSurface(surf))
  200.       return EGL_TRUE;
  201.  
  202.    (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
  203.  
  204.    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
  205.       if (dri2_surf->color_buffers[i].wl_buffer)
  206.          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
  207.       if (dri2_surf->color_buffers[i].dri_image)
  208.          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
  209.    }
  210.  
  211.    for (i = 0; i < __DRI_BUFFER_COUNT; i++)
  212.       if (dri2_surf->dri_buffers[i] &&
  213.           dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
  214.          dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
  215.                                        dri2_surf->dri_buffers[i]);
  216.  
  217.    if (dri2_surf->frame_callback)
  218.       wl_callback_destroy(dri2_surf->frame_callback);
  219.  
  220.    if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
  221.       dri2_surf->wl_win->private = NULL;
  222.       dri2_surf->wl_win->resize_callback = NULL;
  223.    }
  224.  
  225.    free(surf);
  226.  
  227.    return EGL_TRUE;
  228. }
  229.  
  230. static void
  231. dri2_release_buffers(struct dri2_egl_surface *dri2_surf)
  232. {
  233.    struct dri2_egl_display *dri2_dpy =
  234.       dri2_egl_display(dri2_surf->base.Resource.Display);
  235.    int i;
  236.  
  237.    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
  238.       if (dri2_surf->color_buffers[i].wl_buffer &&
  239.           !dri2_surf->color_buffers[i].locked)
  240.          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
  241.       if (dri2_surf->color_buffers[i].dri_image)
  242.          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
  243.  
  244.       dri2_surf->color_buffers[i].wl_buffer = NULL;
  245.       dri2_surf->color_buffers[i].dri_image = NULL;
  246.       dri2_surf->color_buffers[i].locked = 0;
  247.    }
  248.  
  249.    for (i = 0; i < __DRI_BUFFER_COUNT; i++)
  250.       if (dri2_surf->dri_buffers[i] &&
  251.           dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
  252.          dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
  253.                                        dri2_surf->dri_buffers[i]);
  254. }
  255.  
  256. static int
  257. get_back_bo(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
  258. {
  259.    struct dri2_egl_display *dri2_dpy =
  260.       dri2_egl_display(dri2_surf->base.Resource.Display);
  261.    __DRIimage *image;
  262.    int i, name, pitch;
  263.  
  264.    /* There might be a buffer release already queued that wasn't processed */
  265.    wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
  266.  
  267.    if (dri2_surf->back == NULL) {
  268.       for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
  269.          /* Get an unlocked buffer, preferrably one with a dri_buffer already
  270.           * allocated. */
  271.          if (dri2_surf->color_buffers[i].locked)
  272.             continue;
  273.          if (dri2_surf->back == NULL)
  274.             dri2_surf->back = &dri2_surf->color_buffers[i];
  275.          else if (dri2_surf->back->dri_image == NULL)
  276.             dri2_surf->back = &dri2_surf->color_buffers[i];
  277.       }
  278.    }
  279.  
  280.    if (dri2_surf->back == NULL)
  281.       return -1;
  282.    if (dri2_surf->back->dri_image == NULL) {
  283.       dri2_surf->back->dri_image =
  284.          dri2_dpy->image->createImage(dri2_dpy->dri_screen,
  285.                                       dri2_surf->base.Width,
  286.                                       dri2_surf->base.Height,
  287.                                       __DRI_IMAGE_FORMAT_ARGB8888,
  288.                                       __DRI_IMAGE_USE_SHARE,
  289.                                       NULL);
  290.       dri2_surf->back->age = 0;
  291.    }
  292.    if (dri2_surf->back->dri_image == NULL)
  293.       return -1;
  294.  
  295.    image = dri2_surf->back->dri_image;
  296.  
  297.    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
  298.    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
  299.  
  300.    dri2_surf->back->name = name;
  301.    dri2_surf->back->pitch = pitch;
  302.  
  303.    buffer->attachment = __DRI_BUFFER_BACK_LEFT;
  304.    buffer->name = name;
  305.    buffer->pitch = pitch;
  306.    buffer->cpp = 4;
  307.    buffer->flags = 0;
  308.  
  309.    dri2_surf->back->locked = 1;
  310.  
  311.    return 0;
  312. }
  313.  
  314. static int
  315. get_aux_bo(struct dri2_egl_surface *dri2_surf,
  316.            unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
  317. {
  318.    struct dri2_egl_display *dri2_dpy =
  319.       dri2_egl_display(dri2_surf->base.Resource.Display);
  320.    __DRIbuffer *b = dri2_surf->dri_buffers[attachment];
  321.  
  322.    if (b == NULL) {
  323.       b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
  324.                                          attachment, format,
  325.                                          dri2_surf->base.Width,
  326.                                          dri2_surf->base.Height);
  327.       dri2_surf->dri_buffers[attachment] = b;
  328.    }
  329.    if (b == NULL)
  330.       return -1;
  331.  
  332.    memcpy(buffer, b, sizeof *buffer);
  333.  
  334.    return 0;
  335. }
  336.  
  337. static __DRIbuffer *
  338. dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
  339.                              int *width, int *height,
  340.                              unsigned int *attachments, int count,
  341.                              int *out_count, void *loaderPrivate)
  342. {
  343.    struct dri2_egl_surface *dri2_surf = loaderPrivate;
  344.    struct dri2_egl_display *dri2_dpy =
  345.       dri2_egl_display(dri2_surf->base.Resource.Display);
  346.    int i, j;
  347.  
  348.    if (dri2_surf->base.Type == EGL_WINDOW_BIT &&
  349.        (dri2_surf->base.Width != dri2_surf->wl_win->width ||
  350.         dri2_surf->base.Height != dri2_surf->wl_win->height)) {
  351.  
  352.       dri2_release_buffers(dri2_surf);
  353.  
  354.       dri2_surf->base.Width  = dri2_surf->wl_win->width;
  355.       dri2_surf->base.Height = dri2_surf->wl_win->height;
  356.       dri2_surf->dx = dri2_surf->wl_win->dx;
  357.       dri2_surf->dy = dri2_surf->wl_win->dy;
  358.    }
  359.  
  360.    for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
  361.       switch (attachments[i]) {
  362.       case __DRI_BUFFER_BACK_LEFT:
  363.          if (get_back_bo(dri2_surf, &dri2_surf->buffers[j]) < 0) {
  364.             _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
  365.             return NULL;
  366.          }
  367.          break;
  368.       default:
  369.          if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
  370.                         &dri2_surf->buffers[j]) < 0) {
  371.             _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
  372.             return NULL;
  373.          }
  374.          break;
  375.       }
  376.    }
  377.  
  378.    /* If we have an extra unlocked buffer at this point, we had to do triple
  379.     * buffering for a while, but now can go back to just double buffering.
  380.     * That means we can free any unlocked buffer now. */
  381.    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
  382.       if (!dri2_surf->color_buffers[i].locked &&
  383.           dri2_surf->color_buffers[i].wl_buffer) {
  384.          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
  385.          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
  386.          dri2_surf->color_buffers[i].wl_buffer = NULL;
  387.          dri2_surf->color_buffers[i].dri_image = NULL;
  388.       }
  389.    }
  390.  
  391.    *out_count = j;
  392.    if (j == 0)
  393.            return NULL;
  394.  
  395.    *width = dri2_surf->base.Width;
  396.    *height = dri2_surf->base.Height;
  397.  
  398.    return dri2_surf->buffers;
  399. }
  400.  
  401. static __DRIbuffer *
  402. dri2_get_buffers(__DRIdrawable * driDrawable,
  403.                  int *width, int *height,
  404.                  unsigned int *attachments, int count,
  405.                  int *out_count, void *loaderPrivate)
  406. {
  407.    unsigned int *attachments_with_format;
  408.    __DRIbuffer *buffer;
  409.    const unsigned int format = 32;
  410.    int i;
  411.  
  412.    attachments_with_format = calloc(count * 2, sizeof(unsigned int));
  413.    if (!attachments_with_format) {
  414.       *out_count = 0;
  415.       return NULL;
  416.    }
  417.  
  418.    for (i = 0; i < count; ++i) {
  419.       attachments_with_format[2*i] = attachments[i];
  420.       attachments_with_format[2*i + 1] = format;
  421.    }
  422.  
  423.    buffer =
  424.       dri2_get_buffers_with_format(driDrawable,
  425.                                    width, height,
  426.                                    attachments_with_format, count,
  427.                                    out_count, loaderPrivate);
  428.  
  429.    free(attachments_with_format);
  430.  
  431.    return buffer;
  432. }
  433.  
  434. static void
  435. dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
  436. {
  437.    (void) driDrawable;
  438.    (void) loaderPrivate;
  439. }
  440.  
  441. static void
  442. wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
  443. {
  444.    struct dri2_egl_surface *dri2_surf = data;
  445.  
  446.    dri2_surf->frame_callback = NULL;
  447.    wl_callback_destroy(callback);
  448. }
  449.  
  450. static const struct wl_callback_listener frame_listener = {
  451.         wayland_frame_callback
  452. };
  453.  
  454. static void
  455. create_wl_buffer(struct dri2_egl_surface *dri2_surf)
  456. {
  457.    struct dri2_egl_display *dri2_dpy =
  458.       dri2_egl_display(dri2_surf->base.Resource.Display);
  459.    int fd;
  460.  
  461.    if (dri2_surf->current->wl_buffer != NULL)
  462.       return;
  463.  
  464.    if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
  465.       dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
  466.                                   __DRI_IMAGE_ATTRIB_FD, &fd);
  467.  
  468.       dri2_surf->current->wl_buffer =
  469.          wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
  470.                                     fd,
  471.                                     dri2_surf->base.Width,
  472.                                     dri2_surf->base.Height,
  473.                                     dri2_surf->format,
  474.                                     0, dri2_surf->current->pitch,
  475.                                     0, 0,
  476.                                     0, 0);
  477.       close(fd);
  478.    } else {
  479.       dri2_surf->current->wl_buffer =
  480.          wl_drm_create_buffer(dri2_dpy->wl_drm,
  481.                               dri2_surf->current->name,
  482.                               dri2_surf->base.Width,
  483.                               dri2_surf->base.Height,
  484.                               dri2_surf->current->pitch,
  485.                               dri2_surf->format);
  486.    }
  487.  
  488.    wl_proxy_set_queue((struct wl_proxy *) dri2_surf->current->wl_buffer,
  489.                       dri2_dpy->wl_queue);
  490.    wl_buffer_add_listener(dri2_surf->current->wl_buffer,
  491.                           &wl_buffer_listener, dri2_surf);
  492. }
  493.  
  494. /**
  495.  * Called via eglSwapBuffers(), drv->API.SwapBuffers().
  496.  */
  497. static EGLBoolean
  498. dri2_swap_buffers_with_damage(_EGLDriver *drv,
  499.                               _EGLDisplay *disp,
  500.                               _EGLSurface *draw,
  501.                               const EGLint *rects,
  502.                               EGLint n_rects)
  503. {
  504.    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  505.    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
  506.    __DRIbuffer buffer;
  507.    int i, ret = 0;
  508.  
  509.    while (dri2_surf->frame_callback && ret != -1)
  510.       ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
  511.    if (ret < 0)
  512.       return EGL_FALSE;
  513.  
  514.    dri2_surf->frame_callback = wl_surface_frame(dri2_surf->wl_win->surface);
  515.    wl_callback_add_listener(dri2_surf->frame_callback,
  516.                             &frame_listener, dri2_surf);
  517.    wl_proxy_set_queue((struct wl_proxy *) dri2_surf->frame_callback,
  518.                       dri2_dpy->wl_queue);
  519.  
  520.    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
  521.       if (dri2_surf->color_buffers[i].age > 0)
  522.          dri2_surf->color_buffers[i].age++;
  523.  
  524.    /* Make sure we have a back buffer in case we're swapping without ever
  525.     * rendering. */
  526.    if (get_back_bo(dri2_surf, &buffer) < 0) {
  527.       _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
  528.       return EGL_FALSE;
  529.    }
  530.  
  531.    dri2_surf->back->age = 1;
  532.    dri2_surf->current = dri2_surf->back;
  533.    dri2_surf->back = NULL;
  534.  
  535.    create_wl_buffer(dri2_surf);
  536.  
  537.    wl_surface_attach(dri2_surf->wl_win->surface,
  538.                      dri2_surf->current->wl_buffer,
  539.                      dri2_surf->dx, dri2_surf->dy);
  540.  
  541.    dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
  542.    dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
  543.    /* reset resize growing parameters */
  544.    dri2_surf->dx = 0;
  545.    dri2_surf->dy = 0;
  546.  
  547.    if (n_rects == 0) {
  548.       wl_surface_damage(dri2_surf->wl_win->surface, 0, 0,
  549.                         dri2_surf->base.Width, dri2_surf->base.Height);
  550.    } else {
  551.       for (i = 0; i < n_rects; i++) {
  552.          const int *rect = &rects[i * 4];
  553.          wl_surface_damage(dri2_surf->wl_win->surface,
  554.                            rect[0],
  555.                            dri2_surf->base.Height - rect[1] - rect[3],
  556.                            rect[2], rect[3]);
  557.       }
  558.    }
  559.  
  560.    wl_surface_commit(dri2_surf->wl_win->surface);
  561.  
  562.    (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
  563.    (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
  564.  
  565.    return EGL_TRUE;
  566. }
  567.  
  568. static EGLint
  569. dri2_query_buffer_age(_EGLDriver *drv,
  570.                       _EGLDisplay *disp, _EGLSurface *surface)
  571. {
  572.    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
  573.    __DRIbuffer buffer;
  574.  
  575.    if (get_back_bo(dri2_surf, &buffer) < 0) {
  576.       _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
  577.       return 0;
  578.    }
  579.  
  580.    return dri2_surf->back->age;
  581. }
  582.  
  583. static EGLBoolean
  584. dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
  585. {
  586.    return dri2_swap_buffers_with_damage (drv, disp, draw, NULL, 0);
  587. }
  588.  
  589. static int
  590. dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id)
  591. {
  592.    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  593.    int ret = 0;
  594.  
  595.    dri2_dpy->authenticated = 0;
  596.  
  597.    wl_drm_authenticate(dri2_dpy->wl_drm, id);
  598.    if (roundtrip(dri2_dpy) < 0)
  599.       ret = -1;
  600.  
  601.    if (!dri2_dpy->authenticated)
  602.       ret = -1;
  603.  
  604.    /* reset authenticated */
  605.    dri2_dpy->authenticated = 1;
  606.  
  607.    return ret;
  608. }
  609.  
  610. /**
  611.  * Called via eglTerminate(), drv->API.Terminate().
  612.  */
  613. static EGLBoolean
  614. dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
  615. {
  616.    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  617.  
  618.    _eglReleaseDisplayResources(drv, disp);
  619.    _eglCleanupDisplay(disp);
  620.  
  621.    dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
  622.    close(dri2_dpy->fd);
  623.    dlclose(dri2_dpy->driver);
  624.    free(dri2_dpy->driver_name);
  625.    free(dri2_dpy->device_name);
  626.    wl_drm_destroy(dri2_dpy->wl_drm);
  627.    if (dri2_dpy->own_device)
  628.       wl_display_disconnect(dri2_dpy->wl_dpy);
  629.    free(dri2_dpy);
  630.    disp->DriverData = NULL;
  631.  
  632.    return EGL_TRUE;
  633. }
  634.  
  635. static void
  636. drm_handle_device(void *data, struct wl_drm *drm, const char *device)
  637. {
  638.    struct dri2_egl_display *dri2_dpy = data;
  639.    drm_magic_t magic;
  640.  
  641.    dri2_dpy->device_name = strdup(device);
  642.    if (!dri2_dpy->device_name)
  643.       return;
  644.  
  645. #ifdef O_CLOEXEC
  646.    dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
  647.    if (dri2_dpy->fd == -1 && errno == EINVAL)
  648. #endif
  649.    {
  650.       dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
  651.       if (dri2_dpy->fd != -1)
  652.          fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
  653.             FD_CLOEXEC);
  654.    }
  655.    if (dri2_dpy->fd == -1) {
  656.       _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
  657.               dri2_dpy->device_name, strerror(errno));
  658.       return;
  659.    }
  660.  
  661.    drmGetMagic(dri2_dpy->fd, &magic);
  662.    wl_drm_authenticate(dri2_dpy->wl_drm, magic);
  663. }
  664.  
  665. static void
  666. drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
  667. {
  668.    struct dri2_egl_display *dri2_dpy = data;
  669.  
  670.    switch (format) {
  671.    case WL_DRM_FORMAT_ARGB8888:
  672.       dri2_dpy->formats |= HAS_ARGB8888;
  673.       break;
  674.    case WL_DRM_FORMAT_XRGB8888:
  675.       dri2_dpy->formats |= HAS_XRGB8888;
  676.       break;
  677.    }
  678. }
  679.  
  680. static void
  681. drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
  682. {
  683.    struct dri2_egl_display *dri2_dpy = data;
  684.  
  685.    dri2_dpy->capabilities = value;
  686. }
  687.  
  688. static void
  689. drm_handle_authenticated(void *data, struct wl_drm *drm)
  690. {
  691.    struct dri2_egl_display *dri2_dpy = data;
  692.  
  693.    dri2_dpy->authenticated = 1;
  694. }
  695.  
  696. static const struct wl_drm_listener drm_listener = {
  697.         drm_handle_device,
  698.         drm_handle_format,
  699.         drm_handle_authenticated,
  700.         drm_handle_capabilities
  701. };
  702.  
  703. static void
  704. registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
  705.                        const char *interface, uint32_t version)
  706. {
  707.    struct dri2_egl_display *dri2_dpy = data;
  708.  
  709.    if (version > 1)
  710.       version = 2;
  711.    if (strcmp(interface, "wl_drm") == 0) {
  712.       dri2_dpy->wl_drm =
  713.          wl_registry_bind(registry, name, &wl_drm_interface, version);
  714.       wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
  715.    }
  716. }
  717.  
  718. static void
  719. registry_handle_global_remove(void *data, struct wl_registry *registry,
  720.                               uint32_t name)
  721. {
  722. }
  723.  
  724. static const struct wl_registry_listener registry_listener = {
  725.    registry_handle_global,
  726.    registry_handle_global_remove
  727. };
  728.  
  729. EGLBoolean
  730. dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
  731. {
  732.    struct dri2_egl_display *dri2_dpy;
  733.    const __DRIconfig *config;
  734.    uint32_t types;
  735.    int i;
  736.    static const unsigned int argb_masks[4] =
  737.       { 0xff0000, 0xff00, 0xff, 0xff000000 };
  738.    static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };
  739.  
  740.    drv->API.CreateWindowSurface = dri2_create_window_surface;
  741.    drv->API.DestroySurface = dri2_destroy_surface;
  742.    drv->API.SwapBuffers = dri2_swap_buffers;
  743.    drv->API.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage;
  744.    drv->API.Terminate = dri2_terminate;
  745.    drv->API.QueryBufferAge = dri2_query_buffer_age;
  746.  
  747.    dri2_dpy = calloc(1, sizeof *dri2_dpy);
  748.    if (!dri2_dpy)
  749.       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
  750.  
  751.    disp->DriverData = (void *) dri2_dpy;
  752.    if (disp->PlatformDisplay == NULL) {
  753.       dri2_dpy->wl_dpy = wl_display_connect(NULL);
  754.       if (dri2_dpy->wl_dpy == NULL)
  755.          goto cleanup_dpy;
  756.       dri2_dpy->own_device = 1;
  757.    } else {
  758.       dri2_dpy->wl_dpy = disp->PlatformDisplay;
  759.    }
  760.  
  761.    dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
  762.  
  763.    if (dri2_dpy->own_device)
  764.       wl_display_dispatch_pending(dri2_dpy->wl_dpy);
  765.  
  766.    dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
  767.    wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
  768.                       dri2_dpy->wl_queue);
  769.    wl_registry_add_listener(dri2_dpy->wl_registry,
  770.                             &registry_listener, dri2_dpy);
  771.    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
  772.       goto cleanup_dpy;
  773.  
  774.    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
  775.       goto cleanup_drm;
  776.  
  777.    if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
  778.       goto cleanup_fd;
  779.  
  780.    dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd);
  781.    if (dri2_dpy->driver_name == NULL) {
  782.       _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
  783.       goto cleanup_fd;
  784.    }
  785.  
  786.    if (!dri2_load_driver(disp))
  787.       goto cleanup_driver_name;
  788.  
  789.    dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
  790.    dri2_dpy->dri2_loader_extension.base.version = 3;
  791.    dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
  792.    dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
  793.    dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
  794.       dri2_get_buffers_with_format;
  795.      
  796.    dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
  797.    dri2_dpy->extensions[1] = &image_lookup_extension.base;
  798.    dri2_dpy->extensions[2] = &use_invalidate.base;
  799.    dri2_dpy->extensions[3] = NULL;
  800.  
  801.    if (!dri2_create_screen(disp))
  802.       goto cleanup_driver;
  803.  
  804.    /* The server shouldn't advertise WL_DRM_CAPABILITY_PRIME if the driver
  805.     * doesn't have createImageFromFds, since we're using the same driver on
  806.     * both sides.  We don't want crash if that happens anyway, so fall back to
  807.     * gem names if we don't have prime support. */
  808.  
  809.    if (dri2_dpy->image->base.version < 7 ||
  810.        dri2_dpy->image->createImageFromFds == NULL)
  811.       dri2_dpy->capabilities &= WL_DRM_CAPABILITY_PRIME;
  812.  
  813.    types = EGL_WINDOW_BIT;
  814.    for (i = 0; dri2_dpy->driver_configs[i]; i++) {
  815.       config = dri2_dpy->driver_configs[i];
  816.       if (dri2_dpy->formats & HAS_XRGB8888)
  817.          dri2_add_config(disp, config, i + 1, 0, types, NULL, rgb_masks);
  818.       if (dri2_dpy->formats & HAS_ARGB8888)
  819.          dri2_add_config(disp, config, i + 1, 0, types, NULL, argb_masks);
  820.    }
  821.  
  822.    disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
  823.    disp->Extensions.EXT_buffer_age = EGL_TRUE;
  824.    dri2_dpy->authenticate = dri2_wayland_authenticate;
  825.  
  826.    disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
  827.  
  828.    /* we're supporting EGL 1.4 */
  829.    disp->VersionMajor = 1;
  830.    disp->VersionMinor = 4;
  831.  
  832.    return EGL_TRUE;
  833.  
  834.  cleanup_driver:
  835.    dlclose(dri2_dpy->driver);
  836.  cleanup_driver_name:
  837.    free(dri2_dpy->driver_name);
  838.  cleanup_fd:
  839.    close(dri2_dpy->fd);
  840.  cleanup_drm:
  841.    free(dri2_dpy->device_name);
  842.    wl_drm_destroy(dri2_dpy->wl_drm);
  843.  cleanup_dpy:
  844.    free(dri2_dpy);
  845.    
  846.    return EGL_FALSE;
  847. }
  848.