Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 2011 Benjamin Franzke <benjaminfranzke@googlemail.com>
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22.  * DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25. #include "util/u_memory.h"
  26. #include "util/u_inlines.h"
  27.  
  28. #include "pipe/p_compiler.h"
  29. #include "pipe/p_screen.h"
  30. #include "pipe/p_context.h"
  31. #include "pipe/p_state.h"
  32. #include "state_tracker/drm_driver.h"
  33. #include "egllog.h"
  34.  
  35. #include "native_wayland.h"
  36.  
  37. static void
  38. sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
  39. {
  40.    int *done = data;
  41.  
  42.    *done = 1;
  43.    wl_callback_destroy(callback);
  44. }
  45.  
  46. static const struct wl_callback_listener sync_listener = {
  47.    sync_callback
  48. };
  49.  
  50. int
  51. wayland_roundtrip(struct wayland_display *display)
  52. {
  53.    struct wl_callback *callback;
  54.    int done = 0, ret = 0;
  55.  
  56.    callback = wl_display_sync(display->dpy);
  57.    wl_callback_add_listener(callback, &sync_listener, &done);
  58.    wl_proxy_set_queue((struct wl_proxy *) callback, display->queue);
  59.    while (ret != -1 && !done)
  60.       ret = wl_display_dispatch_queue(display->dpy, display->queue);
  61.  
  62.    if (!done)
  63.       wl_callback_destroy(callback);
  64.  
  65.    return ret;
  66. }
  67.  
  68. static const struct native_event_handler *wayland_event_handler;
  69.  
  70. const static struct {
  71.    enum pipe_format format;
  72.    enum wayland_format_flag flag;
  73. } wayland_formats[] = {
  74.    { PIPE_FORMAT_B8G8R8A8_UNORM, HAS_ARGB8888 },
  75.    { PIPE_FORMAT_B8G8R8X8_UNORM, HAS_XRGB8888 },
  76. };
  77.  
  78. static const struct native_config **
  79. wayland_display_get_configs(struct native_display *ndpy, int *num_configs)
  80. {
  81.    struct wayland_display *display = wayland_display(ndpy);
  82.    const struct native_config **configs;
  83.    int i;
  84.  
  85.    if (!display->configs) {
  86.       struct native_config *nconf;
  87.  
  88.       display->num_configs = 0;
  89.       display->configs = CALLOC(Elements(wayland_formats),
  90.                                 sizeof(*display->configs));
  91.       if (!display->configs)
  92.          return NULL;
  93.  
  94.       for (i = 0; i < Elements(wayland_formats); ++i) {
  95.          if (!(display->formats & wayland_formats[i].flag))
  96.             continue;
  97.  
  98.          nconf = &display->configs[display->num_configs].base;
  99.          nconf->buffer_mask =
  100.             (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
  101.             (1 << NATIVE_ATTACHMENT_BACK_LEFT);
  102.          
  103.          nconf->window_bit = TRUE;
  104.          
  105.          nconf->color_format = wayland_formats[i].format;
  106.          display->num_configs++;
  107.       }
  108.    }
  109.  
  110.    configs = MALLOC(display->num_configs * sizeof(*configs));
  111.    if (configs) {
  112.       for (i = 0; i < display->num_configs; ++i)
  113.          configs[i] = &display->configs[i].base;
  114.       if (num_configs)
  115.          *num_configs = display->num_configs;
  116.    }
  117.  
  118.    return configs;
  119. }
  120.  
  121. static int
  122. wayland_display_get_param(struct native_display *ndpy,
  123.                           enum native_param_type param)
  124. {
  125.    int val;
  126.  
  127.    switch (param) {
  128.    case NATIVE_PARAM_PREMULTIPLIED_ALPHA:
  129.       val = 1;
  130.       break;
  131.    case NATIVE_PARAM_USE_NATIVE_BUFFER:
  132.    case NATIVE_PARAM_PRESERVE_BUFFER:
  133.    case NATIVE_PARAM_MAX_SWAP_INTERVAL:
  134.    default:
  135.       val = 0;
  136.       break;
  137.    }
  138.  
  139.    return val;
  140. }
  141.  
  142. static void
  143. wayland_release_pending_resource(void *data,
  144.                                  struct wl_callback *callback,
  145.                                  uint32_t time)
  146. {
  147.    struct wayland_surface *surface = data;
  148.  
  149.    wl_callback_destroy(callback);
  150.  
  151.    /* FIXME: print internal error */
  152.    if (!surface->pending_resource)
  153.       return;
  154.  
  155.    pipe_resource_reference(&surface->pending_resource, NULL);
  156. }
  157.  
  158. static const struct wl_callback_listener release_buffer_listener = {
  159.    wayland_release_pending_resource
  160. };
  161.  
  162. static void
  163. wayland_window_surface_handle_resize(struct wayland_surface *surface)
  164. {
  165.    struct wayland_display *display = surface->display;
  166.    struct pipe_resource *front_resource;
  167.    const enum native_attachment front_natt = NATIVE_ATTACHMENT_FRONT_LEFT;
  168.    int i;
  169.  
  170.    front_resource = resource_surface_get_single_resource(surface->rsurf,
  171.                                                          front_natt);
  172.    if (resource_surface_set_size(surface->rsurf,
  173.                                  surface->win->width, surface->win->height)) {
  174.  
  175.       if (surface->pending_resource)
  176.          wayland_roundtrip(display);
  177.  
  178.       if (front_resource) {
  179.          struct wl_callback *callback;
  180.  
  181.          surface->pending_resource = front_resource;
  182.          front_resource = NULL;
  183.  
  184.          callback = wl_display_sync(display->dpy);
  185.          wl_callback_add_listener(callback, &release_buffer_listener, surface);
  186.          wl_proxy_set_queue((struct wl_proxy *) callback, display->queue);
  187.       }
  188.  
  189.       for (i = 0; i < WL_BUFFER_COUNT; ++i) {
  190.          if (surface->buffer[i])
  191.             wl_buffer_destroy(surface->buffer[i]);
  192.          surface->buffer[i] = NULL;
  193.       }
  194.  
  195.       surface->dx = surface->win->dx;
  196.       surface->dy = surface->win->dy;
  197.    }
  198.    pipe_resource_reference(&front_resource, NULL);
  199. }
  200.  
  201. static boolean
  202. wayland_surface_validate(struct native_surface *nsurf, uint attachment_mask,
  203.                          unsigned int *seq_num, struct pipe_resource **textures,
  204.                          int *width, int *height)
  205. {
  206.    struct wayland_surface *surface = wayland_surface(nsurf);
  207.  
  208.    if (surface->type == WL_WINDOW_SURFACE)
  209.       wayland_window_surface_handle_resize(surface);
  210.  
  211.    if (!resource_surface_add_resources(surface->rsurf, attachment_mask |
  212.                                        surface->attachment_mask))
  213.       return FALSE;
  214.  
  215.    if (textures)
  216.       resource_surface_get_resources(surface->rsurf, textures, attachment_mask);
  217.  
  218.    if (seq_num)
  219.       *seq_num = surface->sequence_number;
  220.  
  221.    resource_surface_get_size(surface->rsurf, (uint *) width, (uint *) height);
  222.  
  223.    return TRUE;
  224. }
  225.  
  226. static void
  227. wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
  228. {
  229.    struct wayland_surface *surface = data;
  230.  
  231.    surface->frame_callback = NULL;
  232.  
  233.    wl_callback_destroy(callback);
  234. }
  235.  
  236. static const struct wl_callback_listener frame_listener = {
  237.    wayland_frame_callback
  238. };
  239.  
  240. static INLINE void
  241. wayland_buffers_swap(struct wl_buffer **buffer,
  242.                      enum wayland_buffer_type buf1,
  243.                      enum wayland_buffer_type buf2)
  244. {
  245.    struct wl_buffer *tmp = buffer[buf1];
  246.    buffer[buf1] = buffer[buf2];
  247.    buffer[buf2] = tmp;
  248. }
  249.  
  250. static boolean
  251. wayland_surface_swap_buffers(struct native_surface *nsurf)
  252. {
  253.    struct wayland_surface *surface = wayland_surface(nsurf);
  254.    struct wayland_display *display = surface->display;
  255.    int ret = 0;
  256.  
  257.    while (surface->frame_callback && ret != -1)
  258.       ret = wl_display_dispatch_queue(display->dpy, display->queue);
  259.    if (ret == -1)
  260.       return EGL_FALSE;
  261.  
  262.    surface->frame_callback = wl_surface_frame(surface->win->surface);
  263.    wl_callback_add_listener(surface->frame_callback, &frame_listener, surface);
  264.    wl_proxy_set_queue((struct wl_proxy *) surface->frame_callback,
  265.                       display->queue);
  266.  
  267.    if (surface->type == WL_WINDOW_SURFACE) {
  268.       resource_surface_swap_buffers(surface->rsurf,
  269.                                     NATIVE_ATTACHMENT_FRONT_LEFT,
  270.                                     NATIVE_ATTACHMENT_BACK_LEFT, FALSE);
  271.  
  272.       wayland_buffers_swap(surface->buffer, WL_BUFFER_FRONT, WL_BUFFER_BACK);
  273.  
  274.       if (surface->buffer[WL_BUFFER_FRONT] == NULL)
  275.          surface->buffer[WL_BUFFER_FRONT] =
  276.             display->create_buffer(display, surface,
  277.                                    NATIVE_ATTACHMENT_FRONT_LEFT);
  278.  
  279.       wl_surface_attach(surface->win->surface, surface->buffer[WL_BUFFER_FRONT],
  280.                         surface->dx, surface->dy);
  281.  
  282.       resource_surface_get_size(surface->rsurf,
  283.                                 (uint *) &surface->win->attached_width,
  284.                                 (uint *) &surface->win->attached_height);
  285.       surface->dx = 0;
  286.       surface->dy = 0;
  287.    }
  288.  
  289.    surface->sequence_number++;
  290.    wayland_event_handler->invalid_surface(&display->base,
  291.                                           &surface->base,
  292.                                           surface->sequence_number);
  293.  
  294.    return TRUE;
  295. }
  296.  
  297. static boolean
  298. wayland_surface_present(struct native_surface *nsurf,
  299.                         const struct native_present_control *ctrl)
  300. {
  301.    struct wayland_surface *surface = wayland_surface(nsurf);
  302.    uint width, height;
  303.    boolean ret;
  304.  
  305.    if (ctrl->preserve || ctrl->swap_interval)
  306.       return FALSE;
  307.  
  308.    /* force buffers to be re-created if they will be presented differently */
  309.    if (surface->premultiplied_alpha != ctrl->premultiplied_alpha) {
  310.       enum wayland_buffer_type buffer;
  311.  
  312.       for (buffer = 0; buffer < WL_BUFFER_COUNT; ++buffer) {
  313.          if (surface->buffer[buffer]) {
  314.             wl_buffer_destroy(surface->buffer[buffer]);
  315.             surface->buffer[buffer] = NULL;
  316.          }
  317.       }
  318.  
  319.       surface->premultiplied_alpha = ctrl->premultiplied_alpha;
  320.    }
  321.  
  322.    switch (ctrl->natt) {
  323.    case NATIVE_ATTACHMENT_FRONT_LEFT:
  324.       ret = TRUE;
  325.       break;
  326.    case NATIVE_ATTACHMENT_BACK_LEFT:
  327.       ret = wayland_surface_swap_buffers(nsurf);
  328.       break;
  329.    default:
  330.       ret = FALSE;
  331.       break;
  332.    }
  333.  
  334.    if (surface->type == WL_WINDOW_SURFACE) {
  335.       resource_surface_get_size(surface->rsurf, &width, &height);
  336.       wl_surface_damage(surface->win->surface, 0, 0, width, height);
  337.       wl_surface_commit(surface->win->surface);
  338.    }
  339.  
  340.    return ret;
  341. }
  342.  
  343. static void
  344. wayland_surface_wait(struct native_surface *nsurf)
  345. {
  346.    /* no-op */
  347. }
  348.  
  349. static void
  350. wayland_surface_destroy(struct native_surface *nsurf)
  351. {
  352.    struct wayland_surface *surface = wayland_surface(nsurf);
  353.    enum wayland_buffer_type buffer;
  354.  
  355.    for (buffer = 0; buffer < WL_BUFFER_COUNT; ++buffer) {
  356.       if (surface->buffer[buffer])
  357.          wl_buffer_destroy(surface->buffer[buffer]);
  358.    }
  359.  
  360.    if (surface->frame_callback)
  361.       wl_callback_destroy(surface->frame_callback);
  362.  
  363.    resource_surface_destroy(surface->rsurf);
  364.    FREE(surface);
  365. }
  366.  
  367.  
  368. static struct native_surface *
  369. wayland_create_window_surface(struct native_display *ndpy,
  370.                               EGLNativeWindowType win,
  371.                               const struct native_config *nconf)
  372. {
  373.    struct wayland_display *display = wayland_display(ndpy);
  374.    struct wayland_config *config = wayland_config(nconf);
  375.    struct wayland_surface *surface;
  376.    uint bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW |
  377.       PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT;
  378.  
  379.    surface = CALLOC_STRUCT(wayland_surface);
  380.    if (!surface)
  381.       return NULL;
  382.  
  383.    surface->display = display;
  384.    surface->color_format = config->base.color_format;
  385.  
  386.    surface->win = (struct wl_egl_window *) win;
  387.  
  388.    surface->pending_resource = NULL;
  389.    surface->frame_callback = NULL;
  390.    surface->type = WL_WINDOW_SURFACE;
  391.  
  392.    surface->buffer[WL_BUFFER_FRONT] = NULL;
  393.    surface->buffer[WL_BUFFER_BACK] = NULL;
  394.    surface->attachment_mask = (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
  395.       (1 << NATIVE_ATTACHMENT_BACK_LEFT);
  396.  
  397.    surface->rsurf = resource_surface_create(display->base.screen,
  398.                                             surface->color_format, bind);
  399.  
  400.    if (!surface->rsurf) {
  401.       FREE(surface);
  402.       return NULL;
  403.    }
  404.  
  405.    surface->base.destroy = wayland_surface_destroy;
  406.    surface->base.present = wayland_surface_present;
  407.    surface->base.validate = wayland_surface_validate;
  408.    surface->base.wait = wayland_surface_wait;
  409.  
  410.    return &surface->base;
  411. }
  412.  
  413. static struct native_display *
  414. native_create_display(void *dpy, boolean use_sw)
  415. {
  416.    struct wayland_display *display = NULL;
  417.    boolean own_dpy = FALSE;
  418.  
  419.    use_sw = use_sw || debug_get_bool_option("EGL_SOFTWARE", FALSE);
  420.  
  421.    if (dpy == NULL) {
  422.       dpy = wl_display_connect(NULL);
  423.       if (dpy == NULL)
  424.          return NULL;
  425.       own_dpy = TRUE;
  426.    }
  427.  
  428.    if (use_sw) {
  429.       _eglLog(_EGL_INFO, "use software fallback");
  430.       display = wayland_create_shm_display((struct wl_display *) dpy,
  431.                                            wayland_event_handler);
  432.    } else {
  433.       display = wayland_create_drm_display((struct wl_display *) dpy,
  434.                                            wayland_event_handler);
  435.    }
  436.  
  437.    if (!display)
  438.       return NULL;
  439.  
  440.    display->base.get_param = wayland_display_get_param;
  441.    display->base.get_configs = wayland_display_get_configs;
  442.    display->base.create_window_surface = wayland_create_window_surface;
  443.  
  444.    display->own_dpy = own_dpy;
  445.  
  446.    return &display->base;
  447. }
  448.  
  449. static const struct native_platform wayland_platform = {
  450.    "wayland", /* name */
  451.    native_create_display
  452. };
  453.  
  454. const struct native_platform *
  455. native_get_wayland_platform(const struct native_event_handler *event_handler)
  456. {
  457.    wayland_event_handler = event_handler;
  458.    return &wayland_platform;
  459. }
  460.  
  461. /* vim: set sw=3 ts=8 sts=3 expandtab: */
  462.