Home | History | Annotate | Download | only in x11
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  7.8
      4  *
      5  * Copyright (C) 2009-2010 Chia-I Wu <olv (at) 0xlab.org>
      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 <X11/Xlib.h>
     27 #include <X11/Xutil.h>
     28 #include "util/u_memory.h"
     29 #include "util/u_math.h"
     30 #include "util/u_format.h"
     31 #include "pipe/p_compiler.h"
     32 #include "util/u_inlines.h"
     33 #include "state_tracker/xlib_sw_winsys.h"
     34 #include "util/u_debug.h"
     35 #include "egllog.h"
     36 
     37 #include "common/native_helper.h"
     38 #include "native_x11.h"
     39 #include "x11_screen.h"
     40 
     41 struct ximage_display {
     42    struct native_display base;
     43    Display *dpy;
     44    boolean own_dpy;
     45 
     46    const struct native_event_handler *event_handler;
     47 
     48    struct x11_screen *xscr;
     49    int xscr_number;
     50 
     51    struct ximage_config *configs;
     52    int num_configs;
     53 };
     54 
     55 struct ximage_surface {
     56    struct native_surface base;
     57    Drawable drawable;
     58    enum pipe_format color_format;
     59    XVisualInfo visual;
     60    struct ximage_display *xdpy;
     61 
     62    unsigned int server_stamp;
     63    unsigned int client_stamp;
     64 
     65    struct resource_surface *rsurf;
     66    struct xlib_drawable xdraw;
     67 };
     68 
     69 struct ximage_config {
     70    struct native_config base;
     71    const XVisualInfo *visual;
     72 };
     73 
     74 static INLINE struct ximage_display *
     75 ximage_display(const struct native_display *ndpy)
     76 {
     77    return (struct ximage_display *) ndpy;
     78 }
     79 
     80 static INLINE struct ximage_surface *
     81 ximage_surface(const struct native_surface *nsurf)
     82 {
     83    return (struct ximage_surface *) nsurf;
     84 }
     85 
     86 static INLINE struct ximage_config *
     87 ximage_config(const struct native_config *nconf)
     88 {
     89    return (struct ximage_config *) nconf;
     90 }
     91 
     92 /**
     93  * Update the geometry of the surface.  This is a slow functions.
     94  */
     95 static void
     96 ximage_surface_update_geometry(struct native_surface *nsurf)
     97 {
     98    struct ximage_surface *xsurf = ximage_surface(nsurf);
     99    Status ok;
    100    Window root;
    101    int x, y;
    102    unsigned int w, h, border, depth;
    103 
    104    ok = XGetGeometry(xsurf->xdpy->dpy, xsurf->drawable,
    105          &root, &x, &y, &w, &h, &border, &depth);
    106    if (ok && resource_surface_set_size(xsurf->rsurf, w, h))
    107       xsurf->server_stamp++;
    108 }
    109 
    110 /**
    111  * Update the buffers of the surface.
    112  */
    113 static boolean
    114 ximage_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
    115 {
    116    struct ximage_surface *xsurf = ximage_surface(nsurf);
    117 
    118    if (xsurf->client_stamp != xsurf->server_stamp) {
    119       ximage_surface_update_geometry(&xsurf->base);
    120       xsurf->client_stamp = xsurf->server_stamp;
    121    }
    122 
    123    return resource_surface_add_resources(xsurf->rsurf, buffer_mask);
    124 }
    125 
    126 /**
    127  * Emulate an invalidate event.
    128  */
    129 static void
    130 ximage_surface_invalidate(struct native_surface *nsurf)
    131 {
    132    struct ximage_surface *xsurf = ximage_surface(nsurf);
    133    struct ximage_display *xdpy = xsurf->xdpy;
    134 
    135    xsurf->server_stamp++;
    136    xdpy->event_handler->invalid_surface(&xdpy->base,
    137          &xsurf->base, xsurf->server_stamp);
    138 }
    139 
    140 static boolean
    141 ximage_surface_flush_frontbuffer(struct native_surface *nsurf)
    142 {
    143    struct ximage_surface *xsurf = ximage_surface(nsurf);
    144    boolean ret;
    145 
    146    ret = resource_surface_present(xsurf->rsurf,
    147          NATIVE_ATTACHMENT_FRONT_LEFT, (void *) &xsurf->xdraw);
    148    /* force buffers to be updated in next validation call */
    149    ximage_surface_invalidate(&xsurf->base);
    150 
    151    return ret;
    152 }
    153 
    154 static boolean
    155 ximage_surface_swap_buffers(struct native_surface *nsurf)
    156 {
    157    struct ximage_surface *xsurf = ximage_surface(nsurf);
    158    boolean ret;
    159 
    160    ret = resource_surface_present(xsurf->rsurf,
    161          NATIVE_ATTACHMENT_BACK_LEFT, (void *) &xsurf->xdraw);
    162 
    163    resource_surface_swap_buffers(xsurf->rsurf,
    164          NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE);
    165    /* the front/back buffers have been swapped */
    166    ximage_surface_invalidate(&xsurf->base);
    167 
    168    return ret;
    169 }
    170 
    171 static boolean
    172 ximage_surface_present(struct native_surface *nsurf,
    173                        const struct native_present_control *ctrl)
    174 {
    175    boolean ret;
    176 
    177    if (ctrl->preserve || ctrl->swap_interval)
    178       return FALSE;
    179 
    180    switch (ctrl->natt) {
    181    case NATIVE_ATTACHMENT_FRONT_LEFT:
    182       ret = ximage_surface_flush_frontbuffer(nsurf);
    183       break;
    184    case NATIVE_ATTACHMENT_BACK_LEFT:
    185       ret = ximage_surface_swap_buffers(nsurf);
    186       break;
    187    default:
    188       ret = FALSE;
    189       break;
    190    }
    191 
    192    return ret;
    193 }
    194 
    195 static boolean
    196 ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask,
    197                         unsigned int *seq_num, struct pipe_resource **textures,
    198                         int *width, int *height)
    199 {
    200    struct ximage_surface *xsurf = ximage_surface(nsurf);
    201    uint w, h;
    202 
    203    if (!ximage_surface_update_buffers(&xsurf->base, attachment_mask))
    204       return FALSE;
    205 
    206    if (seq_num)
    207       *seq_num = xsurf->client_stamp;
    208 
    209    if (textures)
    210       resource_surface_get_resources(xsurf->rsurf, textures, attachment_mask);
    211 
    212    resource_surface_get_size(xsurf->rsurf, &w, &h);
    213    if (width)
    214       *width = w;
    215    if (height)
    216       *height = h;
    217 
    218    return TRUE;
    219 }
    220 
    221 static void
    222 ximage_surface_wait(struct native_surface *nsurf)
    223 {
    224    struct ximage_surface *xsurf = ximage_surface(nsurf);
    225    XSync(xsurf->xdpy->dpy, FALSE);
    226    /* TODO XGetImage and update the front texture */
    227 }
    228 
    229 static void
    230 ximage_surface_destroy(struct native_surface *nsurf)
    231 {
    232    struct ximage_surface *xsurf = ximage_surface(nsurf);
    233 
    234    resource_surface_destroy(xsurf->rsurf);
    235    FREE(xsurf);
    236 }
    237 
    238 static struct ximage_surface *
    239 ximage_display_create_surface(struct native_display *ndpy,
    240                               Drawable drawable,
    241                               const struct native_config *nconf)
    242 {
    243    struct ximage_display *xdpy = ximage_display(ndpy);
    244    struct ximage_config *xconf = ximage_config(nconf);
    245    struct ximage_surface *xsurf;
    246 
    247    xsurf = CALLOC_STRUCT(ximage_surface);
    248    if (!xsurf)
    249       return NULL;
    250 
    251    xsurf->xdpy = xdpy;
    252    xsurf->color_format = xconf->base.color_format;
    253    xsurf->drawable = drawable;
    254 
    255    xsurf->rsurf = resource_surface_create(xdpy->base.screen,
    256          xsurf->color_format,
    257          PIPE_BIND_RENDER_TARGET |
    258          PIPE_BIND_SAMPLER_VIEW |
    259          PIPE_BIND_DISPLAY_TARGET |
    260          PIPE_BIND_SCANOUT);
    261    if (!xsurf->rsurf) {
    262       FREE(xsurf);
    263       return NULL;
    264    }
    265 
    266    xsurf->drawable = drawable;
    267    xsurf->visual = *xconf->visual;
    268    /* initialize the geometry */
    269    ximage_surface_update_geometry(&xsurf->base);
    270 
    271    xsurf->xdraw.visual = xsurf->visual.visual;
    272    xsurf->xdraw.depth = xsurf->visual.depth;
    273    xsurf->xdraw.drawable = xsurf->drawable;
    274 
    275    xsurf->base.destroy = ximage_surface_destroy;
    276    xsurf->base.present = ximage_surface_present;
    277    xsurf->base.validate = ximage_surface_validate;
    278    xsurf->base.wait = ximage_surface_wait;
    279 
    280    return xsurf;
    281 }
    282 
    283 static struct native_surface *
    284 ximage_display_create_window_surface(struct native_display *ndpy,
    285                                      EGLNativeWindowType win,
    286                                      const struct native_config *nconf)
    287 {
    288    struct ximage_surface *xsurf;
    289 
    290    xsurf = ximage_display_create_surface(ndpy, (Drawable) win, nconf);
    291    return (xsurf) ? &xsurf->base : NULL;
    292 }
    293 
    294 static enum pipe_format
    295 get_pixmap_format(struct native_display *ndpy, EGLNativePixmapType pix)
    296 {
    297    struct ximage_display *xdpy = ximage_display(ndpy);
    298    enum pipe_format fmt;
    299    uint depth;
    300 
    301    depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix);
    302 
    303    switch (depth) {
    304    case 32:
    305       fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
    306       break;
    307    case 24:
    308       fmt = PIPE_FORMAT_B8G8R8X8_UNORM;
    309       break;
    310    case 16:
    311       fmt = PIPE_FORMAT_B5G6R5_UNORM;
    312       break;
    313    default:
    314       fmt = PIPE_FORMAT_NONE;
    315       break;
    316    }
    317 
    318    return fmt;
    319 }
    320 
    321 static struct native_surface *
    322 ximage_display_create_pixmap_surface(struct native_display *ndpy,
    323                                      EGLNativePixmapType pix,
    324                                      const struct native_config *nconf)
    325 {
    326    struct ximage_surface *xsurf;
    327 
    328    /* find the config */
    329    if (!nconf) {
    330       struct ximage_display *xdpy = ximage_display(ndpy);
    331       enum pipe_format fmt = get_pixmap_format(&xdpy->base, pix);
    332       int i;
    333 
    334       if (fmt != PIPE_FORMAT_NONE) {
    335          for (i = 0; i < xdpy->num_configs; i++) {
    336             if (xdpy->configs[i].base.color_format == fmt) {
    337                nconf = &xdpy->configs[i].base;
    338                break;
    339             }
    340          }
    341       }
    342 
    343       if (!nconf)
    344          return NULL;
    345    }
    346 
    347    xsurf = ximage_display_create_surface(ndpy, (Drawable) pix, nconf);
    348    return (xsurf) ? &xsurf->base : NULL;
    349 }
    350 
    351 static enum pipe_format
    352 choose_format(const XVisualInfo *vinfo)
    353 {
    354    enum pipe_format fmt;
    355    /* TODO elaborate the formats */
    356    switch (vinfo->depth) {
    357    case 32:
    358       fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
    359       break;
    360    case 24:
    361       fmt = PIPE_FORMAT_B8G8R8X8_UNORM;
    362       break;
    363    case 16:
    364       fmt = PIPE_FORMAT_B5G6R5_UNORM;
    365       break;
    366    default:
    367       fmt = PIPE_FORMAT_NONE;
    368       break;
    369    }
    370 
    371    return fmt;
    372 }
    373 
    374 static const struct native_config **
    375 ximage_display_get_configs(struct native_display *ndpy, int *num_configs)
    376 {
    377    struct ximage_display *xdpy = ximage_display(ndpy);
    378    const struct native_config **configs;
    379    int i;
    380 
    381    /* first time */
    382    if (!xdpy->configs) {
    383       const XVisualInfo *visuals;
    384       int num_visuals, count;
    385 
    386       visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals);
    387       if (!visuals)
    388          return NULL;
    389 
    390       /*
    391        * Create two configs for each visual.
    392        * One with depth/stencil buffer; one without
    393        */
    394       xdpy->configs = CALLOC(num_visuals * 2, sizeof(*xdpy->configs));
    395       if (!xdpy->configs)
    396          return NULL;
    397 
    398       count = 0;
    399       for (i = 0; i < num_visuals; i++) {
    400          struct ximage_config *xconf = &xdpy->configs[count];
    401 
    402          xconf->visual = &visuals[i];
    403          xconf->base.color_format = choose_format(xconf->visual);
    404          if (xconf->base.color_format == PIPE_FORMAT_NONE)
    405             continue;
    406 
    407          xconf->base.buffer_mask =
    408             (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
    409             (1 << NATIVE_ATTACHMENT_BACK_LEFT);
    410 
    411          xconf->base.window_bit = TRUE;
    412          xconf->base.pixmap_bit = TRUE;
    413 
    414          xconf->base.native_visual_id = xconf->visual->visualid;
    415 #if defined(__cplusplus) || defined(c_plusplus)
    416          xconf->base.native_visual_type = xconf->visual->c_class;
    417 #else
    418          xconf->base.native_visual_type = xconf->visual->class;
    419 #endif
    420 
    421          count++;
    422       }
    423 
    424       xdpy->num_configs = count;
    425    }
    426 
    427    configs = MALLOC(xdpy->num_configs * sizeof(*configs));
    428    if (configs) {
    429       for (i = 0; i < xdpy->num_configs; i++)
    430          configs[i] = (const struct native_config *) &xdpy->configs[i];
    431       if (num_configs)
    432          *num_configs = xdpy->num_configs;
    433    }
    434    return configs;
    435 }
    436 
    437 static boolean
    438 ximage_display_get_pixmap_format(struct native_display *ndpy,
    439                                  EGLNativePixmapType pix,
    440                                  enum pipe_format *format)
    441 {
    442    struct ximage_display *xdpy = ximage_display(ndpy);
    443 
    444    *format = get_pixmap_format(&xdpy->base, pix);
    445 
    446    return (*format != PIPE_FORMAT_NONE);
    447 }
    448 
    449 static boolean
    450 ximage_display_copy_to_pixmap(struct native_display *ndpy,
    451                               EGLNativePixmapType pix,
    452                               struct pipe_resource *src)
    453 {
    454    /* fast path to avoid unnecessary allocation and resource_copy_region */
    455    if (src->bind & PIPE_BIND_DISPLAY_TARGET) {
    456       struct ximage_display *xdpy = ximage_display(ndpy);
    457       enum pipe_format fmt = get_pixmap_format(&xdpy->base, pix);
    458       const struct ximage_config *xconf = NULL;
    459       struct xlib_drawable xdraw;
    460       int i;
    461 
    462       if (fmt == PIPE_FORMAT_NONE || src->format != fmt)
    463          return FALSE;
    464 
    465       for (i = 0; i < xdpy->num_configs; i++) {
    466          if (xdpy->configs[i].base.color_format == fmt) {
    467             xconf = &xdpy->configs[i];
    468             break;
    469          }
    470       }
    471       if (!xconf)
    472          return FALSE;
    473 
    474       memset(&xdraw, 0, sizeof(xdraw));
    475       xdraw.visual = xconf->visual->visual;
    476       xdraw.depth = xconf->visual->depth;
    477       xdraw.drawable = (Drawable) pix;
    478 
    479       xdpy->base.screen->flush_frontbuffer(xdpy->base.screen,
    480             src, 0, 0, &xdraw);
    481 
    482       return TRUE;
    483    }
    484 
    485    return native_display_copy_to_pixmap(ndpy, pix, src);
    486 }
    487 
    488 static int
    489 ximage_display_get_param(struct native_display *ndpy,
    490                          enum native_param_type param)
    491 {
    492    int val;
    493 
    494    switch (param) {
    495    case NATIVE_PARAM_USE_NATIVE_BUFFER:
    496       /* private buffers are allocated */
    497       val = FALSE;
    498       break;
    499    case NATIVE_PARAM_PRESERVE_BUFFER:
    500    case NATIVE_PARAM_MAX_SWAP_INTERVAL:
    501    default:
    502       val = 0;
    503       break;
    504    }
    505 
    506    return val;
    507 }
    508 
    509 static void
    510 ximage_display_destroy(struct native_display *ndpy)
    511 {
    512    struct ximage_display *xdpy = ximage_display(ndpy);
    513 
    514    if (xdpy->configs)
    515       FREE(xdpy->configs);
    516 
    517    ndpy_uninit(ndpy);
    518 
    519    x11_screen_destroy(xdpy->xscr);
    520    if (xdpy->own_dpy)
    521       XCloseDisplay(xdpy->dpy);
    522    FREE(xdpy);
    523 }
    524 
    525 static boolean
    526 ximage_display_init_screen(struct native_display *ndpy)
    527 {
    528    struct ximage_display *xdpy = ximage_display(ndpy);
    529    struct sw_winsys *winsys;
    530 
    531    winsys = xlib_create_sw_winsys(xdpy->dpy);
    532    if (!winsys)
    533       return FALSE;
    534 
    535    xdpy->base.screen =
    536       xdpy->event_handler->new_sw_screen(&xdpy->base, winsys);
    537    if (!xdpy->base.screen) {
    538       if (winsys->destroy)
    539          winsys->destroy(winsys);
    540       return FALSE;
    541    }
    542 
    543    return TRUE;
    544 }
    545 
    546 struct native_display *
    547 x11_create_ximage_display(Display *dpy,
    548                           const struct native_event_handler *event_handler)
    549 {
    550    struct ximage_display *xdpy;
    551 
    552    xdpy = CALLOC_STRUCT(ximage_display);
    553    if (!xdpy)
    554       return NULL;
    555 
    556    xdpy->dpy = dpy;
    557    if (!xdpy->dpy) {
    558       xdpy->dpy = XOpenDisplay(NULL);
    559       if (!xdpy->dpy) {
    560          FREE(xdpy);
    561          return NULL;
    562       }
    563       xdpy->own_dpy = TRUE;
    564    }
    565 
    566    xdpy->event_handler = event_handler;
    567 
    568    xdpy->xscr_number = DefaultScreen(xdpy->dpy);
    569    xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number);
    570    if (!xdpy->xscr) {
    571       if (xdpy->own_dpy)
    572          XCloseDisplay(xdpy->dpy);
    573       FREE(xdpy);
    574       return NULL;
    575    }
    576 
    577    xdpy->base.init_screen = ximage_display_init_screen;
    578    xdpy->base.destroy = ximage_display_destroy;
    579    xdpy->base.get_param = ximage_display_get_param;
    580 
    581    xdpy->base.get_configs = ximage_display_get_configs;
    582    xdpy->base.get_pixmap_format = ximage_display_get_pixmap_format;
    583    xdpy->base.copy_to_pixmap = ximage_display_copy_to_pixmap;
    584    xdpy->base.create_window_surface = ximage_display_create_window_surface;
    585    xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface;
    586 
    587    return &xdpy->base;
    588 }
    589