summaryrefslogtreecommitdiff
path: root/lib/mesa/src/gallium/winsys/sw/xlib/xlib_sw_winsys.c
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2015-11-22 02:46:45 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2015-11-22 02:46:45 +0000
commit0784c49c0f8fcc8b3abd4c9286d9fd8bc089dd7d (patch)
treea6394e3e264a0f80b57f4ce0f5d9526aa543d4b0 /lib/mesa/src/gallium/winsys/sw/xlib/xlib_sw_winsys.c
parentd91d0007eecf589ea5699e34aa4d748fce2c57b2 (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.c487
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;
+}