Subversion Repositories Kolibri OS

Rev

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

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