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