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 <unistd.h>
     27 #include <fcntl.h>
     28 #include <sys/types.h>
     29 #include <sys/stat.h>
     30 #include <xf86drm.h>
     31 #include <X11/Xlibint.h>
     32 #include <X11/extensions/XShm.h>
     33 
     34 #include "util/u_memory.h"
     35 #include "egllog.h"
     36 
     37 #include "x11_screen.h"
     38 #include "dri2.h"
     39 #include "glxinit.h"
     40 
     41 struct x11_screen {
     42    Display *dpy;
     43    int number;
     44 
     45    /*
     46     * This is used to fetch GLX visuals/fbconfigs.  It steals code from GLX.
     47     * It might be better to rewrite the part in Xlib or XCB.
     48     */
     49    __GLXdisplayPrivate *glx_dpy;
     50 
     51    int dri_major, dri_minor;
     52    char *dri_driver;
     53    char *dri_device;
     54    int dri_fd;
     55 
     56    x11_drawable_invalidate_buffers dri_invalidate_buffers;
     57    void *dri_user_data;
     58 
     59    XVisualInfo *visuals;
     60    int num_visuals;
     61 
     62    /* cached values for x11_drawable_get_depth */
     63    Drawable last_drawable;
     64    unsigned int last_depth;
     65 };
     66 
     67 
     68 /**
     69  * Create a X11 screen.
     70  */
     71 struct x11_screen *
     72 x11_screen_create(Display *dpy, int screen)
     73 {
     74    struct x11_screen *xscr;
     75 
     76    if (screen >= ScreenCount(dpy))
     77       return NULL;
     78 
     79    xscr = CALLOC_STRUCT(x11_screen);
     80    if (xscr) {
     81       xscr->dpy = dpy;
     82       xscr->number = screen;
     83 
     84       xscr->dri_major = -1;
     85       xscr->dri_fd = -1;
     86    }
     87    return xscr;
     88 }
     89 
     90 /**
     91  * Destroy a X11 screen.
     92  */
     93 void
     94 x11_screen_destroy(struct x11_screen *xscr)
     95 {
     96    if (xscr->dri_fd >= 0)
     97       close(xscr->dri_fd);
     98    if (xscr->dri_driver)
     99       Xfree(xscr->dri_driver);
    100    if (xscr->dri_device)
    101       Xfree(xscr->dri_device);
    102 
    103 #ifdef GLX_DIRECT_RENDERING
    104    /* xscr->glx_dpy will be destroyed with the X display */
    105    if (xscr->glx_dpy)
    106       xscr->glx_dpy->xscr = NULL;
    107 #endif
    108 
    109    if (xscr->visuals)
    110       XFree(xscr->visuals);
    111    FREE(xscr);
    112 }
    113 
    114 #ifdef GLX_DIRECT_RENDERING
    115 
    116 static boolean
    117 x11_screen_init_dri2(struct x11_screen *xscr)
    118 {
    119    if (xscr->dri_major < 0) {
    120       int eventBase, errorBase;
    121 
    122       if (!DRI2QueryExtension(xscr->dpy, &eventBase, &errorBase) ||
    123           !DRI2QueryVersion(xscr->dpy, &xscr->dri_major, &xscr->dri_minor))
    124          xscr->dri_major = -1;
    125    }
    126    return (xscr->dri_major >= 0);
    127 }
    128 
    129 static boolean
    130 x11_screen_init_glx(struct x11_screen *xscr)
    131 {
    132    if (!xscr->glx_dpy)
    133       xscr->glx_dpy = __glXInitialize(xscr->dpy);
    134    return (xscr->glx_dpy != NULL);
    135 }
    136 
    137 #endif /* GLX_DIRECT_RENDERING */
    138 
    139 /**
    140  * Return true if the screen supports the extension.
    141  */
    142 boolean
    143 x11_screen_support(struct x11_screen *xscr, enum x11_screen_extension ext)
    144 {
    145    boolean supported = FALSE;
    146 
    147    switch (ext) {
    148    case X11_SCREEN_EXTENSION_XSHM:
    149       supported = XShmQueryExtension(xscr->dpy);
    150       break;
    151 #ifdef GLX_DIRECT_RENDERING
    152    case X11_SCREEN_EXTENSION_GLX:
    153       supported = x11_screen_init_glx(xscr);
    154       break;
    155    case X11_SCREEN_EXTENSION_DRI2:
    156       supported = x11_screen_init_dri2(xscr);
    157       break;
    158 #endif
    159    default:
    160       break;
    161    }
    162 
    163    return supported;
    164 }
    165 
    166 /**
    167  * Return the X visuals.
    168  */
    169 const XVisualInfo *
    170 x11_screen_get_visuals(struct x11_screen *xscr, int *num_visuals)
    171 {
    172    if (!xscr->visuals) {
    173       XVisualInfo vinfo_template;
    174       vinfo_template.screen = xscr->number;
    175       xscr->visuals = XGetVisualInfo(xscr->dpy, VisualScreenMask,
    176             &vinfo_template, &xscr->num_visuals);
    177    }
    178 
    179    if (num_visuals)
    180       *num_visuals = xscr->num_visuals;
    181    return xscr->visuals;
    182 }
    183 
    184 /**
    185  * Return the depth of a drawable.
    186  *
    187  * Unlike other drawable functions, the drawable needs not be a DRI2 drawable.
    188  */
    189 uint
    190 x11_drawable_get_depth(struct x11_screen *xscr, Drawable drawable)
    191 {
    192    unsigned int depth;
    193 
    194    if (drawable != xscr->last_drawable) {
    195       Window root;
    196       int x, y;
    197       unsigned int w, h, border;
    198       Status ok;
    199 
    200       ok = XGetGeometry(xscr->dpy, drawable, &root,
    201             &x, &y, &w, &h, &border, &depth);
    202       if (!ok)
    203          depth = 0;
    204 
    205       xscr->last_drawable = drawable;
    206       xscr->last_depth = depth;
    207    }
    208    else {
    209       depth = xscr->last_depth;
    210    }
    211 
    212    return depth;
    213 }
    214 
    215 #ifdef GLX_DIRECT_RENDERING
    216 
    217 /**
    218  * Return the GLX fbconfigs.
    219  */
    220 const __GLcontextModes *
    221 x11_screen_get_glx_configs(struct x11_screen *xscr)
    222 {
    223    return (x11_screen_init_glx(xscr))
    224       ? xscr->glx_dpy->screenConfigs[xscr->number]->configs
    225       : NULL;
    226 }
    227 
    228 /**
    229  * Probe the screen for the DRI2 driver name.
    230  */
    231 const char *
    232 x11_screen_probe_dri2(struct x11_screen *xscr, int *major, int *minor)
    233 {
    234    if (!x11_screen_init_dri2(xscr))
    235       return NULL;
    236 
    237    /* get the driver name and the device name */
    238    if (!xscr->dri_driver) {
    239       if (!DRI2Connect(xscr->dpy, RootWindow(xscr->dpy, xscr->number),
    240                &xscr->dri_driver, &xscr->dri_device))
    241          xscr->dri_driver = xscr->dri_device = NULL;
    242    }
    243    if (major)
    244       *major = xscr->dri_major;
    245    if (minor)
    246       *minor = xscr->dri_minor;
    247 
    248    return xscr->dri_driver;
    249 }
    250 
    251 /**
    252  * Enable DRI2 and returns the file descriptor of the DRM device.  The file
    253  * descriptor will be closed automatically when the screen is destoryed.
    254  */
    255 int
    256 x11_screen_enable_dri2(struct x11_screen *xscr,
    257                        x11_drawable_invalidate_buffers invalidate_buffers,
    258                        void *user_data)
    259 {
    260    if (xscr->dri_fd < 0) {
    261       int fd;
    262       drm_magic_t magic;
    263 
    264       /* get the driver name and the device name first */
    265       if (!x11_screen_probe_dri2(xscr, NULL, NULL))
    266          return -1;
    267 
    268 #ifdef O_CLOEXEC
    269       fd = open(xscr->dri_device, O_RDWR | O_CLOEXEC);
    270       if (fd == -1 && errno == EINVAL)
    271 #endif
    272       {
    273          fd = open(xscr->dri_device, O_RDWR);
    274          if (fd != -1)
    275             fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
    276       }
    277       if (fd < 0) {
    278          _eglLog(_EGL_WARNING, "failed to open %s", xscr->dri_device);
    279          return -1;
    280       }
    281 
    282       memset(&magic, 0, sizeof(magic));
    283       if (drmGetMagic(fd, &magic)) {
    284          _eglLog(_EGL_WARNING, "failed to get magic");
    285          close(fd);
    286          return -1;
    287       }
    288 
    289       if (!DRI2Authenticate(xscr->dpy,
    290                RootWindow(xscr->dpy, xscr->number), magic)) {
    291          _eglLog(_EGL_WARNING, "failed to authenticate magic");
    292          close(fd);
    293          return -1;
    294       }
    295 
    296       if (!x11_screen_init_glx(xscr)) {
    297          _eglLog(_EGL_WARNING, "failed to initialize GLX");
    298          close(fd);
    299          return -1;
    300       }
    301       if (xscr->glx_dpy->xscr) {
    302          _eglLog(_EGL_WARNING,
    303                "display is already managed by another x11 screen");
    304          close(fd);
    305          return -1;
    306       }
    307 
    308       xscr->glx_dpy->xscr = xscr;
    309       xscr->dri_invalidate_buffers = invalidate_buffers;
    310       xscr->dri_user_data = user_data;
    311 
    312       xscr->dri_fd = fd;
    313    }
    314 
    315    return xscr->dri_fd;
    316 }
    317 
    318 char *
    319 x11_screen_get_device_name(struct x11_screen *xscr)
    320 {
    321    return xscr->dri_device;
    322 }
    323 
    324 int
    325 x11_screen_authenticate(struct x11_screen *xscr, uint32_t id)
    326 {
    327    boolean authenticated;
    328 
    329    authenticated = DRI2Authenticate(xscr->dpy,
    330          RootWindow(xscr->dpy, xscr->number), id);
    331 
    332    return authenticated ? 0 : -1;
    333 }
    334 
    335 /**
    336  * Create/Destroy the DRI drawable.
    337  */
    338 void
    339 x11_drawable_enable_dri2(struct x11_screen *xscr,
    340                          Drawable drawable, boolean on)
    341 {
    342    if (on)
    343       DRI2CreateDrawable(xscr->dpy, drawable);
    344    else
    345       DRI2DestroyDrawable(xscr->dpy, drawable);
    346 }
    347 
    348 /**
    349  * Copy between buffers of the DRI2 drawable.
    350  */
    351 void
    352 x11_drawable_copy_buffers_region(struct x11_screen *xscr, Drawable drawable,
    353                                  int num_rects, const int *rects,
    354                                  int src_buf, int dst_buf)
    355 {
    356    XserverRegion region;
    357    XRectangle *rectangles = CALLOC(num_rects, sizeof(XRectangle));
    358 
    359    for (int i = 0; i < num_rects; i++) {
    360       rectangles[i].x = rects[i * 4 + 0];
    361       rectangles[i].y = rects[i * 4 + 1];
    362       rectangles[i].width = rects[i * 4 + 2];
    363       rectangles[i].height = rects[i * 4 + 3];
    364    }
    365 
    366    region = XFixesCreateRegion(xscr->dpy, rectangles, num_rects);
    367    DRI2CopyRegion(xscr->dpy, drawable, region, dst_buf, src_buf);
    368    XFixesDestroyRegion(xscr->dpy, region);
    369    FREE(rectangles);
    370 }
    371 
    372 /**
    373  * Get the buffers of the DRI2 drawable.  The returned array should be freed.
    374  */
    375 struct x11_drawable_buffer *
    376 x11_drawable_get_buffers(struct x11_screen *xscr, Drawable drawable,
    377                          int *width, int *height, unsigned int *attachments,
    378                          boolean with_format, int num_ins, int *num_outs)
    379 {
    380    DRI2Buffer *dri2bufs;
    381 
    382    if (with_format)
    383       dri2bufs = DRI2GetBuffersWithFormat(xscr->dpy, drawable, width, height,
    384             attachments, num_ins, num_outs);
    385    else
    386       dri2bufs = DRI2GetBuffers(xscr->dpy, drawable, width, height,
    387             attachments, num_ins, num_outs);
    388 
    389    return (struct x11_drawable_buffer *) dri2bufs;
    390 }
    391 
    392 /**
    393  * Create a mode list of the given size.
    394  */
    395 __GLcontextModes *
    396 x11_context_modes_create(unsigned count)
    397 {
    398    const size_t size = sizeof(__GLcontextModes);
    399    __GLcontextModes *base = NULL;
    400    __GLcontextModes **next;
    401    unsigned i;
    402 
    403    next = &base;
    404    for (i = 0; i < count; i++) {
    405       *next = (__GLcontextModes *) CALLOC(1, size);
    406       if (*next == NULL) {
    407          x11_context_modes_destroy(base);
    408          base = NULL;
    409          break;
    410       }
    411       next = &((*next)->next);
    412    }
    413 
    414    return base;
    415 }
    416 
    417 /**
    418  * Destroy a mode list.
    419  */
    420 void
    421 x11_context_modes_destroy(__GLcontextModes *modes)
    422 {
    423    while (modes != NULL) {
    424       __GLcontextModes *next = modes->next;
    425       FREE(modes);
    426       modes = next;
    427    }
    428 }
    429 
    430 /**
    431  * Return the number of the modes in the mode list.
    432  */
    433 unsigned
    434 x11_context_modes_count(const __GLcontextModes *modes)
    435 {
    436    const __GLcontextModes *mode;
    437    int count = 0;
    438    for (mode = modes; mode; mode = mode->next)
    439       count++;
    440    return count;
    441 }
    442 
    443 extern void
    444 dri2InvalidateBuffers(Display *dpy, XID drawable);
    445 
    446 /**
    447  * This is called from src/glx/dri2.c.
    448  */
    449 void
    450 dri2InvalidateBuffers(Display *dpy, XID drawable)
    451 {
    452    __GLXdisplayPrivate *priv = __glXInitialize(dpy);
    453    struct x11_screen *xscr = NULL;
    454 
    455    if (priv && priv->xscr)
    456       xscr = priv->xscr;
    457    if (!xscr || !xscr->dri_invalidate_buffers)
    458       return;
    459 
    460    xscr->dri_invalidate_buffers(xscr, drawable, xscr->dri_user_data);
    461 }
    462 
    463 extern unsigned
    464 dri2GetSwapEventType(Display *dpy, XID drawable);
    465 
    466 extern void *
    467 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id);
    468 
    469 extern void *
    470 GetGLXDrawable(Display *dpy, XID drawable);
    471 
    472 /**
    473  * This is also called from src/glx/dri2.c.
    474  */
    475 unsigned dri2GetSwapEventType(Display *dpy, XID drawable)
    476 {
    477    return 0;
    478 }
    479 
    480 void *
    481 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
    482 {
    483    return NULL;
    484 }
    485 
    486 void *
    487 GetGLXDrawable(Display *dpy, XID drawable)
    488 {
    489    return NULL;
    490 }
    491 
    492 #endif /* GLX_DIRECT_RENDERING */
    493