diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2015-11-22 02:46:45 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2015-11-22 02:46:45 +0000 |
commit | 0784c49c0f8fcc8b3abd4c9286d9fd8bc089dd7d (patch) | |
tree | a6394e3e264a0f80b57f4ce0f5d9526aa543d4b0 /lib/mesa/src/gallium/winsys/sw/xlib/xlib_sw_winsys.c | |
parent | d91d0007eecf589ea5699e34aa4d748fce2c57b2 (diff) |
import Mesa 11.0.6
Diffstat (limited to 'lib/mesa/src/gallium/winsys/sw/xlib/xlib_sw_winsys.c')
-rw-r--r-- | lib/mesa/src/gallium/winsys/sw/xlib/xlib_sw_winsys.c | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/lib/mesa/src/gallium/winsys/sw/xlib/xlib_sw_winsys.c b/lib/mesa/src/gallium/winsys/sw/xlib/xlib_sw_winsys.c new file mode 100644 index 000000000..515ecd9f7 --- /dev/null +++ b/lib/mesa/src/gallium/winsys/sw/xlib/xlib_sw_winsys.c @@ -0,0 +1,487 @@ +/************************************************************************** + * + * Copyright 2007 VMware, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +/* + * Authors: + * Keith Whitwell + * Brian Paul + */ + +#include "pipe/p_format.h" +#include "pipe/p_context.h" +#include "util/u_inlines.h" +#include "util/u_format.h" +#include "util/u_math.h" +#include "util/u_memory.h" + +#include "state_tracker/xlibsw_api.h" +#include "xlib_sw_winsys.h" + +#include <X11/Xlib.h> +#include <X11/Xlibint.h> +#include <X11/Xutil.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/extensions/XShm.h> + +DEBUG_GET_ONCE_BOOL_OPTION(xlib_no_shm, "XLIB_NO_SHM", FALSE) + +/** + * Display target for Xlib winsys. + * Low-level OS/window system memory buffer + */ +struct xlib_displaytarget +{ + enum pipe_format format; + unsigned width; + unsigned height; + unsigned stride; + + void *data; + void *mapped; + + Display *display; + Visual *visual; + XImage *tempImage; + GC gc; + + /* This is the last drawable that this display target was presented + * against. May need to recreate gc, tempImage when this changes?? + */ + Drawable drawable; + + XShmSegmentInfo shminfo; + Bool shm; /** Using shared memory images? */ +}; + + +/** + * Subclass of sw_winsys for Xlib winsys + */ +struct xlib_sw_winsys +{ + struct sw_winsys base; + Display *display; +}; + + + +/** Cast wrapper */ +static inline struct xlib_displaytarget * +xlib_displaytarget(struct sw_displaytarget *dt) +{ + return (struct xlib_displaytarget *) dt; +} + + +/** + * X Shared Memory Image extension code + */ + +static volatile int XErrorFlag = 0; + +/** + * Catches potential Xlib errors. + */ +static int +handle_xerror(Display *dpy, XErrorEvent *event) +{ + (void) dpy; + (void) event; + XErrorFlag = 1; + return 0; +} + + +static char * +alloc_shm(struct xlib_displaytarget *buf, unsigned size) +{ + XShmSegmentInfo *const shminfo = & buf->shminfo; + + shminfo->shmid = -1; + shminfo->shmaddr = (char *) -1; + + shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777); + if (shminfo->shmid < 0) { + return NULL; + } + + shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0); + if (shminfo->shmaddr == (char *) -1) { + shmctl(shminfo->shmid, IPC_RMID, 0); + return NULL; + } + + shminfo->readOnly = False; + return shminfo->shmaddr; +} + + +/** + * Allocate a shared memory XImage back buffer for the given display target. + */ +static void +alloc_shm_ximage(struct xlib_displaytarget *xlib_dt, + struct xlib_drawable *xmb, + unsigned width, unsigned height) +{ + /* + * We have to do a _lot_ of error checking here to be sure we can + * really use the XSHM extension. It seems different servers trigger + * errors at different points if the extension won't work. Therefore + * we have to be very careful... + */ + int (*old_handler)(Display *, XErrorEvent *); + + xlib_dt->tempImage = XShmCreateImage(xlib_dt->display, + xmb->visual, + xmb->depth, + ZPixmap, + NULL, + &xlib_dt->shminfo, + width, height); + if (xlib_dt->tempImage == NULL) { + shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0); + xlib_dt->shm = False; + return; + } + + + XErrorFlag = 0; + old_handler = XSetErrorHandler(handle_xerror); + /* This may trigger the X protocol error we're ready to catch: */ + XShmAttach(xlib_dt->display, &xlib_dt->shminfo); + XSync(xlib_dt->display, False); + + /* Mark the segment to be destroyed, so that it is automatically destroyed + * when this process dies. Needs to be after XShmAttach() for *BSD. + */ + shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0); + + if (XErrorFlag) { + /* we are on a remote display, this error is normal, don't print it */ + XFlush(xlib_dt->display); + XErrorFlag = 0; + XDestroyImage(xlib_dt->tempImage); + xlib_dt->tempImage = NULL; + xlib_dt->shm = False; + (void) XSetErrorHandler(old_handler); + return; + } + + xlib_dt->shm = True; +} + + +static void +alloc_ximage(struct xlib_displaytarget *xlib_dt, + struct xlib_drawable *xmb, + unsigned width, unsigned height) +{ + /* try allocating a shared memory image first */ + if (xlib_dt->shm) { + alloc_shm_ximage(xlib_dt, xmb, width, height); + if (xlib_dt->tempImage) + return; /* success */ + } + + /* try regular (non-shared memory) image */ + xlib_dt->tempImage = XCreateImage(xlib_dt->display, + xmb->visual, + xmb->depth, + ZPixmap, 0, + NULL, width, height, + 8, 0); +} + +static boolean +xlib_is_displaytarget_format_supported(struct sw_winsys *ws, + unsigned tex_usage, + enum pipe_format format) +{ + /* TODO: check visuals or other sensible thing here */ + return TRUE; +} + + +static void * +xlib_displaytarget_map(struct sw_winsys *ws, + struct sw_displaytarget *dt, + unsigned flags) +{ + struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt); + xlib_dt->mapped = xlib_dt->data; + return xlib_dt->mapped; +} + + +static void +xlib_displaytarget_unmap(struct sw_winsys *ws, + struct sw_displaytarget *dt) +{ + struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt); + xlib_dt->mapped = NULL; +} + + +static void +xlib_displaytarget_destroy(struct sw_winsys *ws, + struct sw_displaytarget *dt) +{ + struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt); + + if (xlib_dt->data) { + if (xlib_dt->shminfo.shmid >= 0) { + shmdt(xlib_dt->shminfo.shmaddr); + shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0); + + xlib_dt->shminfo.shmid = -1; + xlib_dt->shminfo.shmaddr = (char *) -1; + + xlib_dt->data = NULL; + if (xlib_dt->tempImage) + xlib_dt->tempImage->data = NULL; + } + else { + FREE(xlib_dt->data); + if (xlib_dt->tempImage && xlib_dt->tempImage->data == xlib_dt->data) { + xlib_dt->tempImage->data = NULL; + } + xlib_dt->data = NULL; + } + } + + if (xlib_dt->tempImage) { + XDestroyImage(xlib_dt->tempImage); + xlib_dt->tempImage = NULL; + } + + if (xlib_dt->gc) + XFreeGC(xlib_dt->display, xlib_dt->gc); + + FREE(xlib_dt); +} + + +/** + * Display/copy the image in the surface into the X window specified + * by the display target. + */ +static void +xlib_sw_display(struct xlib_drawable *xlib_drawable, + struct sw_displaytarget *dt) +{ + static boolean no_swap = 0; + static boolean firsttime = 1; + struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt); + Display *display = xlib_dt->display; + XImage *ximage; + + if (firsttime) { + no_swap = getenv("SP_NO_RAST") != NULL; + firsttime = 0; + } + + if (no_swap) + return; + + if (xlib_dt->drawable != xlib_drawable->drawable) { + if (xlib_dt->gc) { + XFreeGC(display, xlib_dt->gc); + xlib_dt->gc = NULL; + } + + if (xlib_dt->tempImage) { + XDestroyImage(xlib_dt->tempImage); + xlib_dt->tempImage = NULL; + } + + xlib_dt->drawable = xlib_drawable->drawable; + } + + if (xlib_dt->tempImage == NULL) { + assert(util_format_get_blockwidth(xlib_dt->format) == 1); + assert(util_format_get_blockheight(xlib_dt->format) == 1); + alloc_ximage(xlib_dt, xlib_drawable, + xlib_dt->stride / util_format_get_blocksize(xlib_dt->format), + xlib_dt->height); + if (!xlib_dt->tempImage) + return; + } + + if (xlib_dt->gc == NULL) { + xlib_dt->gc = XCreateGC(display, xlib_drawable->drawable, 0, NULL); + XSetFunction(display, xlib_dt->gc, GXcopy); + } + + if (xlib_dt->shm) { + ximage = xlib_dt->tempImage; + ximage->data = xlib_dt->data; + + /* _debug_printf("XSHM\n"); */ + XShmPutImage(xlib_dt->display, xlib_drawable->drawable, xlib_dt->gc, + ximage, 0, 0, 0, 0, xlib_dt->width, xlib_dt->height, False); + } + else { + /* display image in Window */ + ximage = xlib_dt->tempImage; + ximage->data = xlib_dt->data; + + /* check that the XImage has been previously initialized */ + assert(ximage->format); + assert(ximage->bitmap_unit); + + /* update XImage's fields */ + ximage->width = xlib_dt->width; + ximage->height = xlib_dt->height; + ximage->bytes_per_line = xlib_dt->stride; + + /* _debug_printf("XPUT\n"); */ + XPutImage(xlib_dt->display, xlib_drawable->drawable, xlib_dt->gc, + ximage, 0, 0, 0, 0, xlib_dt->width, xlib_dt->height); + } + + XFlush(xlib_dt->display); +} + + +/** + * Display/copy the image in the surface into the X window specified + * by the display target. + */ +static void +xlib_displaytarget_display(struct sw_winsys *ws, + struct sw_displaytarget *dt, + void *context_private, + struct pipe_box *box) +{ + struct xlib_drawable *xlib_drawable = (struct xlib_drawable *)context_private; + xlib_sw_display(xlib_drawable, dt); +} + + +static struct sw_displaytarget * +xlib_displaytarget_create(struct sw_winsys *winsys, + unsigned tex_usage, + enum pipe_format format, + unsigned width, unsigned height, + unsigned alignment, + unsigned *stride) +{ + struct xlib_displaytarget *xlib_dt; + unsigned nblocksy, size; + + xlib_dt = CALLOC_STRUCT(xlib_displaytarget); + if (!xlib_dt) + goto no_xlib_dt; + + xlib_dt->display = ((struct xlib_sw_winsys *)winsys)->display; + xlib_dt->format = format; + xlib_dt->width = width; + xlib_dt->height = height; + + nblocksy = util_format_get_nblocksy(format, height); + xlib_dt->stride = align(util_format_get_stride(format, width), alignment); + size = xlib_dt->stride * nblocksy; + + if (!debug_get_option_xlib_no_shm()) { + xlib_dt->data = alloc_shm(xlib_dt, size); + if (xlib_dt->data) { + xlib_dt->shm = True; + } + } + + if (!xlib_dt->data) { + xlib_dt->data = align_malloc(size, alignment); + if (!xlib_dt->data) + goto no_data; + } + + *stride = xlib_dt->stride; + return (struct sw_displaytarget *)xlib_dt; + +no_data: + FREE(xlib_dt); +no_xlib_dt: + return NULL; +} + + +static struct sw_displaytarget * +xlib_displaytarget_from_handle(struct sw_winsys *winsys, + const struct pipe_resource *templet, + struct winsys_handle *whandle, + unsigned *stride) +{ + assert(0); + return NULL; +} + + +static boolean +xlib_displaytarget_get_handle(struct sw_winsys *winsys, + struct sw_displaytarget *dt, + struct winsys_handle *whandle) +{ + assert(0); + return FALSE; +} + + +static void +xlib_destroy(struct sw_winsys *ws) +{ + FREE(ws); +} + + +struct sw_winsys * +xlib_create_sw_winsys(Display *display) +{ + struct xlib_sw_winsys *ws; + + ws = CALLOC_STRUCT(xlib_sw_winsys); + if (!ws) + return NULL; + + ws->display = display; + ws->base.destroy = xlib_destroy; + + ws->base.is_displaytarget_format_supported = xlib_is_displaytarget_format_supported; + + ws->base.displaytarget_create = xlib_displaytarget_create; + ws->base.displaytarget_from_handle = xlib_displaytarget_from_handle; + ws->base.displaytarget_get_handle = xlib_displaytarget_get_handle; + ws->base.displaytarget_map = xlib_displaytarget_map; + ws->base.displaytarget_unmap = xlib_displaytarget_unmap; + ws->base.displaytarget_destroy = xlib_displaytarget_destroy; + + ws->base.displaytarget_display = xlib_displaytarget_display; + + return &ws->base; +} |