Subversion Repositories Kolibri OS

Rev

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

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2007 VMware, Inc., Bismarck, ND., USA
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16.  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  17.  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  18.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  19.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  20.  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  21.  *
  22.  * The above copyright notice and this permission notice (including the
  23.  * next paragraph) shall be included in all copies or substantial portions
  24.  * of the Software.
  25.  *
  26.  *
  27.  **************************************************************************/
  28.  
  29. /*
  30.  * Authors:
  31.  *   Keith Whitwell
  32.  *   Brian Paul
  33.  */
  34.  
  35. #include "pipe/p_format.h"
  36. #include "pipe/p_context.h"
  37. #include "util/u_inlines.h"
  38. #include "util/u_format.h"
  39. #include "util/u_math.h"
  40. #include "util/u_memory.h"
  41.  
  42. #include "state_tracker/xlibsw_api.h"
  43. #include "xlib_sw_winsys.h"
  44.  
  45. #include <X11/Xlib.h>
  46. #include <X11/Xlibint.h>
  47. #include <X11/Xutil.h>
  48. #include <sys/ipc.h>
  49. #include <sys/shm.h>
  50. #include <X11/extensions/XShm.h>
  51.  
  52. DEBUG_GET_ONCE_BOOL_OPTION(xlib_no_shm, "XLIB_NO_SHM", FALSE)
  53.  
  54. /**
  55.  * Display target for Xlib winsys.
  56.  * Low-level OS/window system memory buffer
  57.  */
  58. struct xlib_displaytarget
  59. {
  60.    enum pipe_format format;
  61.    unsigned width;
  62.    unsigned height;
  63.    unsigned stride;
  64.  
  65.    void *data;
  66.    void *mapped;
  67.  
  68.    Display *display;
  69.    Visual *visual;
  70.    XImage *tempImage;
  71.    GC gc;
  72.  
  73.    /* This is the last drawable that this display target was presented
  74.     * against.  May need to recreate gc, tempImage when this changes??
  75.     */
  76.    Drawable drawable;
  77.  
  78.    XShmSegmentInfo shminfo;
  79.    Bool shm;  /** Using shared memory images? */
  80. };
  81.  
  82.  
  83. /**
  84.  * Subclass of sw_winsys for Xlib winsys
  85.  */
  86. struct xlib_sw_winsys
  87. {
  88.    struct sw_winsys base;
  89.    Display *display;
  90. };
  91.  
  92.  
  93.  
  94. /** Cast wrapper */
  95. static INLINE struct xlib_displaytarget *
  96. xlib_displaytarget(struct sw_displaytarget *dt)
  97. {
  98.    return (struct xlib_displaytarget *) dt;
  99. }
  100.  
  101.  
  102. /**
  103.  * X Shared Memory Image extension code
  104.  */
  105.  
  106. static volatile int XErrorFlag = 0;
  107.  
  108. /**
  109.  * Catches potential Xlib errors.
  110.  */
  111. static int
  112. handle_xerror(Display *dpy, XErrorEvent *event)
  113. {
  114.    (void) dpy;
  115.    (void) event;
  116.    XErrorFlag = 1;
  117.    return 0;
  118. }
  119.  
  120.  
  121. static char *
  122. alloc_shm(struct xlib_displaytarget *buf, unsigned size)
  123. {
  124.    XShmSegmentInfo *const shminfo = & buf->shminfo;
  125.  
  126.    shminfo->shmid = -1;
  127.    shminfo->shmaddr = (char *) -1;
  128.  
  129.    shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777);
  130.    if (shminfo->shmid < 0) {
  131.       return NULL;
  132.    }
  133.  
  134.    shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
  135.    if (shminfo->shmaddr == (char *) -1) {
  136.       shmctl(shminfo->shmid, IPC_RMID, 0);
  137.       return NULL;
  138.    }
  139.  
  140.    shminfo->readOnly = False;
  141.    return shminfo->shmaddr;
  142. }
  143.  
  144.  
  145. /**
  146.  * Allocate a shared memory XImage back buffer for the given display target.
  147.  */
  148. static void
  149. alloc_shm_ximage(struct xlib_displaytarget *xlib_dt,
  150.                  struct xlib_drawable *xmb,
  151.                  unsigned width, unsigned height)
  152. {
  153.    /*
  154.     * We have to do a _lot_ of error checking here to be sure we can
  155.     * really use the XSHM extension.  It seems different servers trigger
  156.     * errors at different points if the extension won't work.  Therefore
  157.     * we have to be very careful...
  158.     */
  159.    int (*old_handler)(Display *, XErrorEvent *);
  160.  
  161.    xlib_dt->tempImage = XShmCreateImage(xlib_dt->display,
  162.                                       xmb->visual,
  163.                                       xmb->depth,
  164.                                       ZPixmap,
  165.                                       NULL,
  166.                                       &xlib_dt->shminfo,
  167.                                       width, height);
  168.    if (xlib_dt->tempImage == NULL) {
  169.       shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);
  170.       xlib_dt->shm = False;
  171.       return;
  172.    }
  173.  
  174.  
  175.    XErrorFlag = 0;
  176.    old_handler = XSetErrorHandler(handle_xerror);
  177.    /* This may trigger the X protocol error we're ready to catch: */
  178.    XShmAttach(xlib_dt->display, &xlib_dt->shminfo);
  179.    XSync(xlib_dt->display, False);
  180.  
  181.    /* Mark the segment to be destroyed, so that it is automatically destroyed
  182.     * when this process dies.  Needs to be after XShmAttach() for *BSD.
  183.     */
  184.    shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);
  185.  
  186.    if (XErrorFlag) {
  187.       /* we are on a remote display, this error is normal, don't print it */
  188.       XFlush(xlib_dt->display);
  189.       XErrorFlag = 0;
  190.       XDestroyImage(xlib_dt->tempImage);
  191.       xlib_dt->tempImage = NULL;
  192.       xlib_dt->shm = False;
  193.       (void) XSetErrorHandler(old_handler);
  194.       return;
  195.    }
  196.  
  197.    xlib_dt->shm = True;
  198. }
  199.  
  200.  
  201. static void
  202. alloc_ximage(struct xlib_displaytarget *xlib_dt,
  203.              struct xlib_drawable *xmb,
  204.              unsigned width, unsigned height)
  205. {
  206.    /* try allocating a shared memory image first */
  207.    if (xlib_dt->shm) {
  208.       alloc_shm_ximage(xlib_dt, xmb, width, height);
  209.       if (xlib_dt->tempImage)
  210.          return; /* success */
  211.    }
  212.  
  213.    /* try regular (non-shared memory) image */
  214.    xlib_dt->tempImage = XCreateImage(xlib_dt->display,
  215.                                    xmb->visual,
  216.                                    xmb->depth,
  217.                                    ZPixmap, 0,
  218.                                    NULL, width, height,
  219.                                    8, 0);
  220. }
  221.  
  222. static boolean
  223. xlib_is_displaytarget_format_supported(struct sw_winsys *ws,
  224.                                        unsigned tex_usage,
  225.                                        enum pipe_format format)
  226. {
  227.    /* TODO: check visuals or other sensible thing here */
  228.    return TRUE;
  229. }
  230.  
  231.  
  232. static void *
  233. xlib_displaytarget_map(struct sw_winsys *ws,
  234.                        struct sw_displaytarget *dt,
  235.                        unsigned flags)
  236. {
  237.    struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
  238.    xlib_dt->mapped = xlib_dt->data;
  239.    return xlib_dt->mapped;
  240. }
  241.  
  242.  
  243. static void
  244. xlib_displaytarget_unmap(struct sw_winsys *ws,
  245.                          struct sw_displaytarget *dt)
  246. {
  247.    struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
  248.    xlib_dt->mapped = NULL;
  249. }
  250.  
  251.  
  252. static void
  253. xlib_displaytarget_destroy(struct sw_winsys *ws,
  254.                            struct sw_displaytarget *dt)
  255. {
  256.    struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
  257.  
  258.    if (xlib_dt->data) {
  259.       if (xlib_dt->shminfo.shmid >= 0) {
  260.          shmdt(xlib_dt->shminfo.shmaddr);
  261.          shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);
  262.          
  263.          xlib_dt->shminfo.shmid = -1;
  264.          xlib_dt->shminfo.shmaddr = (char *) -1;
  265.  
  266.          xlib_dt->data = NULL;
  267.          if (xlib_dt->tempImage)
  268.             xlib_dt->tempImage->data = NULL;
  269.       }
  270.       else {
  271.          FREE(xlib_dt->data);
  272.          if (xlib_dt->tempImage && xlib_dt->tempImage->data == xlib_dt->data) {
  273.             xlib_dt->tempImage->data = NULL;
  274.          }
  275.          xlib_dt->data = NULL;
  276.       }
  277.    }
  278.  
  279.    if (xlib_dt->tempImage) {
  280.       XDestroyImage(xlib_dt->tempImage);
  281.       xlib_dt->tempImage = NULL;
  282.    }
  283.  
  284.    if (xlib_dt->gc)
  285.       XFreeGC(xlib_dt->display, xlib_dt->gc);
  286.  
  287.    FREE(xlib_dt);
  288. }
  289.  
  290.  
  291. /**
  292.  * Display/copy the image in the surface into the X window specified
  293.  * by the display target.
  294.  */
  295. static void
  296. xlib_sw_display(struct xlib_drawable *xlib_drawable,
  297.                 struct sw_displaytarget *dt)
  298. {
  299.    static boolean no_swap = 0;
  300.    static boolean firsttime = 1;
  301.    struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
  302.    Display *display = xlib_dt->display;
  303.    XImage *ximage;
  304.  
  305.    if (firsttime) {
  306.       no_swap = getenv("SP_NO_RAST") != NULL;
  307.       firsttime = 0;
  308.    }
  309.  
  310.    if (no_swap)
  311.       return;
  312.  
  313.    if (xlib_dt->drawable != xlib_drawable->drawable) {
  314.       if (xlib_dt->gc) {
  315.          XFreeGC(display, xlib_dt->gc);
  316.          xlib_dt->gc = NULL;
  317.       }
  318.  
  319.       if (xlib_dt->tempImage) {
  320.          XDestroyImage(xlib_dt->tempImage);
  321.          xlib_dt->tempImage = NULL;
  322.       }
  323.  
  324.       xlib_dt->drawable = xlib_drawable->drawable;
  325.    }
  326.  
  327.    if (xlib_dt->tempImage == NULL) {
  328.       assert(util_format_get_blockwidth(xlib_dt->format) == 1);
  329.       assert(util_format_get_blockheight(xlib_dt->format) == 1);
  330.       alloc_ximage(xlib_dt, xlib_drawable,
  331.                    xlib_dt->stride / util_format_get_blocksize(xlib_dt->format),
  332.                    xlib_dt->height);
  333.       if (!xlib_dt->tempImage)
  334.          return;
  335.    }
  336.  
  337.    if (xlib_dt->gc == NULL) {
  338.       xlib_dt->gc = XCreateGC(display, xlib_drawable->drawable, 0, NULL);
  339.       XSetFunction(display, xlib_dt->gc, GXcopy);
  340.    }
  341.  
  342.    if (xlib_dt->shm) {
  343.       ximage = xlib_dt->tempImage;
  344.       ximage->data = xlib_dt->data;
  345.  
  346.       /* _debug_printf("XSHM\n"); */
  347.       XShmPutImage(xlib_dt->display, xlib_drawable->drawable, xlib_dt->gc,
  348.                    ximage, 0, 0, 0, 0, xlib_dt->width, xlib_dt->height, False);
  349.    }
  350.    else {
  351.       /* display image in Window */
  352.       ximage = xlib_dt->tempImage;
  353.       ximage->data = xlib_dt->data;
  354.  
  355.       /* check that the XImage has been previously initialized */
  356.       assert(ximage->format);
  357.       assert(ximage->bitmap_unit);
  358.  
  359.       /* update XImage's fields */
  360.       ximage->width = xlib_dt->width;
  361.       ximage->height = xlib_dt->height;
  362.       ximage->bytes_per_line = xlib_dt->stride;
  363.  
  364.       /* _debug_printf("XPUT\n"); */
  365.       XPutImage(xlib_dt->display, xlib_drawable->drawable, xlib_dt->gc,
  366.                 ximage, 0, 0, 0, 0, xlib_dt->width, xlib_dt->height);
  367.    }
  368.  
  369.    XFlush(xlib_dt->display);
  370. }
  371.  
  372.  
  373. /**
  374.  * Display/copy the image in the surface into the X window specified
  375.  * by the display target.
  376.  */
  377. static void
  378. xlib_displaytarget_display(struct sw_winsys *ws,
  379.                            struct sw_displaytarget *dt,
  380.                            void *context_private,
  381.                            struct pipe_box *box)
  382. {
  383.    struct xlib_drawable *xlib_drawable = (struct xlib_drawable *)context_private;
  384.    xlib_sw_display(xlib_drawable, dt);
  385. }
  386.  
  387.  
  388. static struct sw_displaytarget *
  389. xlib_displaytarget_create(struct sw_winsys *winsys,
  390.                           unsigned tex_usage,
  391.                           enum pipe_format format,
  392.                           unsigned width, unsigned height,
  393.                           unsigned alignment,
  394.                           unsigned *stride)
  395. {
  396.    struct xlib_displaytarget *xlib_dt;
  397.    unsigned nblocksy, size;
  398.  
  399.    xlib_dt = CALLOC_STRUCT(xlib_displaytarget);
  400.    if (!xlib_dt)
  401.       goto no_xlib_dt;
  402.  
  403.    xlib_dt->display = ((struct xlib_sw_winsys *)winsys)->display;
  404.    xlib_dt->format = format;
  405.    xlib_dt->width = width;
  406.    xlib_dt->height = height;
  407.  
  408.    nblocksy = util_format_get_nblocksy(format, height);
  409.    xlib_dt->stride = align(util_format_get_stride(format, width), alignment);
  410.    size = xlib_dt->stride * nblocksy;
  411.  
  412.    if (!debug_get_option_xlib_no_shm()) {
  413.       xlib_dt->data = alloc_shm(xlib_dt, size);
  414.       if (xlib_dt->data) {
  415.          xlib_dt->shm = True;
  416.       }
  417.    }
  418.  
  419.    if (!xlib_dt->data) {
  420.       xlib_dt->data = align_malloc(size, alignment);
  421.       if (!xlib_dt->data)
  422.          goto no_data;
  423.    }
  424.  
  425.    *stride = xlib_dt->stride;
  426.    return (struct sw_displaytarget *)xlib_dt;
  427.  
  428. no_data:
  429.    FREE(xlib_dt);
  430. no_xlib_dt:
  431.    return NULL;
  432. }
  433.  
  434.  
  435. static struct sw_displaytarget *
  436. xlib_displaytarget_from_handle(struct sw_winsys *winsys,
  437.                                const struct pipe_resource *templet,
  438.                                struct winsys_handle *whandle,
  439.                                unsigned *stride)
  440. {
  441.    assert(0);
  442.    return NULL;
  443. }
  444.  
  445.  
  446. static boolean
  447. xlib_displaytarget_get_handle(struct sw_winsys *winsys,
  448.                               struct sw_displaytarget *dt,
  449.                               struct winsys_handle *whandle)
  450. {
  451.    assert(0);
  452.    return FALSE;
  453. }
  454.  
  455.  
  456. static void
  457. xlib_destroy(struct sw_winsys *ws)
  458. {
  459.    FREE(ws);
  460. }
  461.  
  462.  
  463. struct sw_winsys *
  464. xlib_create_sw_winsys(Display *display)
  465. {
  466.    struct xlib_sw_winsys *ws;
  467.  
  468.    ws = CALLOC_STRUCT(xlib_sw_winsys);
  469.    if (!ws)
  470.       return NULL;
  471.  
  472.    ws->display = display;
  473.    ws->base.destroy = xlib_destroy;
  474.  
  475.    ws->base.is_displaytarget_format_supported = xlib_is_displaytarget_format_supported;
  476.  
  477.    ws->base.displaytarget_create = xlib_displaytarget_create;
  478.    ws->base.displaytarget_from_handle = xlib_displaytarget_from_handle;
  479.    ws->base.displaytarget_get_handle = xlib_displaytarget_get_handle;
  480.    ws->base.displaytarget_map = xlib_displaytarget_map;
  481.    ws->base.displaytarget_unmap = xlib_displaytarget_unmap;
  482.    ws->base.displaytarget_destroy = xlib_displaytarget_destroy;
  483.  
  484.    ws->base.displaytarget_display = xlib_displaytarget_display;
  485.  
  486.    return &ws->base;
  487. }
  488.