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