Path: blob/21.2-virgl/src/gallium/winsys/sw/xlib/xlib_sw_winsys.c
4573 views
/**************************************************************************1*2* Copyright 2007 VMware, Inc., Bismarck, ND., USA3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL16* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,17* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR18* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE19* USE OR OTHER DEALINGS IN THE SOFTWARE.20*21* The above copyright notice and this permission notice (including the22* next paragraph) shall be included in all copies or substantial portions23* of the Software.24*25*26**************************************************************************/2728/*29* Authors:30* Keith Whitwell31* Brian Paul32*/3334#include "pipe/p_format.h"35#include "pipe/p_context.h"36#include "util/u_inlines.h"37#include "util/format/u_format.h"38#include "util/u_math.h"39#include "util/u_memory.h"4041#include "frontend/xlibsw_api.h"42#include "xlib_sw_winsys.h"4344#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>5051DEBUG_GET_ONCE_BOOL_OPTION(xlib_no_shm, "XLIB_NO_SHM", false)5253/**54* Display target for Xlib winsys.55* Low-level OS/window system memory buffer56*/57struct xlib_displaytarget58{59enum pipe_format format;60unsigned width;61unsigned height;62unsigned stride;6364void *data;65void *mapped;6667Display *display;68Visual *visual;69XImage *tempImage;70GC gc;7172/* This is the last drawable that this display target was presented73* against. May need to recreate gc, tempImage when this changes??74*/75Drawable drawable;7677XShmSegmentInfo shminfo;78Bool shm; /** Using shared memory images? */79};808182/**83* Subclass of sw_winsys for Xlib winsys84*/85struct xlib_sw_winsys86{87struct sw_winsys base;88Display *display;89};90919293/** Cast wrapper */94static inline struct xlib_displaytarget *95xlib_displaytarget(struct sw_displaytarget *dt)96{97return (struct xlib_displaytarget *) dt;98}99100101/**102* X Shared Memory Image extension code103*/104105static volatile int XErrorFlag = 0;106107/**108* Catches potential Xlib errors.109*/110static int111handle_xerror(Display *dpy, XErrorEvent *event)112{113(void) dpy;114(void) event;115XErrorFlag = 1;116return 0;117}118119120static char *121alloc_shm(struct xlib_displaytarget *buf, unsigned size)122{123XShmSegmentInfo *const shminfo = & buf->shminfo;124125shminfo->shmid = -1;126shminfo->shmaddr = (char *) -1;127128/* 0600 = user read+write */129shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);130if (shminfo->shmid < 0) {131return NULL;132}133134shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);135if (shminfo->shmaddr == (char *) -1) {136shmctl(shminfo->shmid, IPC_RMID, 0);137return NULL;138}139140shminfo->readOnly = False;141return shminfo->shmaddr;142}143144145/**146* Allocate a shared memory XImage back buffer for the given display target.147*/148static void149alloc_shm_ximage(struct xlib_displaytarget *xlib_dt,150struct xlib_drawable *xmb,151unsigned width, unsigned height)152{153/*154* We have to do a _lot_ of error checking here to be sure we can155* really use the XSHM extension. It seems different servers trigger156* errors at different points if the extension won't work. Therefore157* we have to be very careful...158*/159int (*old_handler)(Display *, XErrorEvent *);160161xlib_dt->tempImage = XShmCreateImage(xlib_dt->display,162xmb->visual,163xmb->depth,164ZPixmap,165NULL,166&xlib_dt->shminfo,167width, height);168if (xlib_dt->tempImage == NULL) {169shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);170xlib_dt->shm = False;171return;172}173174175XErrorFlag = 0;176old_handler = XSetErrorHandler(handle_xerror);177/* This may trigger the X protocol error we're ready to catch: */178XShmAttach(xlib_dt->display, &xlib_dt->shminfo);179XSync(xlib_dt->display, False);180181/* Mark the segment to be destroyed, so that it is automatically destroyed182* when this process dies. Needs to be after XShmAttach() for *BSD.183*/184shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);185186if (XErrorFlag) {187/* we are on a remote display, this error is normal, don't print it */188XFlush(xlib_dt->display);189XErrorFlag = 0;190XDestroyImage(xlib_dt->tempImage);191xlib_dt->tempImage = NULL;192xlib_dt->shm = False;193(void) XSetErrorHandler(old_handler);194return;195}196197xlib_dt->shm = True;198}199200201static void202alloc_ximage(struct xlib_displaytarget *xlib_dt,203struct xlib_drawable *xmb,204unsigned width, unsigned height)205{206/* try allocating a shared memory image first */207if (xlib_dt->shm) {208alloc_shm_ximage(xlib_dt, xmb, width, height);209if (xlib_dt->tempImage)210return; /* success */211}212213/* try regular (non-shared memory) image */214xlib_dt->tempImage = XCreateImage(xlib_dt->display,215xmb->visual,216xmb->depth,217ZPixmap, 0,218NULL, width, height,2198, 0);220}221222static bool223xlib_is_displaytarget_format_supported(struct sw_winsys *ws,224unsigned tex_usage,225enum pipe_format format)226{227/* TODO: check visuals or other sensible thing here */228return true;229}230231232static void *233xlib_displaytarget_map(struct sw_winsys *ws,234struct sw_displaytarget *dt,235unsigned flags)236{237struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);238xlib_dt->mapped = xlib_dt->data;239return xlib_dt->mapped;240}241242243static void244xlib_displaytarget_unmap(struct sw_winsys *ws,245struct sw_displaytarget *dt)246{247struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);248xlib_dt->mapped = NULL;249}250251252static void253xlib_displaytarget_destroy(struct sw_winsys *ws,254struct sw_displaytarget *dt)255{256struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);257258if (xlib_dt->data) {259if (xlib_dt->shminfo.shmid >= 0) {260shmdt(xlib_dt->shminfo.shmaddr);261shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);262263xlib_dt->shminfo.shmid = -1;264xlib_dt->shminfo.shmaddr = (char *) -1;265266xlib_dt->data = NULL;267if (xlib_dt->tempImage)268xlib_dt->tempImage->data = NULL;269}270else {271align_free(xlib_dt->data);272if (xlib_dt->tempImage && xlib_dt->tempImage->data == xlib_dt->data) {273xlib_dt->tempImage->data = NULL;274}275xlib_dt->data = NULL;276}277}278279if (xlib_dt->tempImage) {280XDestroyImage(xlib_dt->tempImage);281xlib_dt->tempImage = NULL;282}283284if (xlib_dt->gc)285XFreeGC(xlib_dt->display, xlib_dt->gc);286287FREE(xlib_dt);288}289290291/**292* Display/copy the image in the surface into the X window specified293* by the display target.294*/295static void296xlib_sw_display(struct xlib_drawable *xlib_drawable,297struct sw_displaytarget *dt,298struct pipe_box *box)299{300static bool no_swap = false;301static bool firsttime = true;302struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);303Display *display = xlib_dt->display;304XImage *ximage;305struct pipe_box _box = {};306307if (firsttime) {308no_swap = getenv("SP_NO_RAST") != NULL;309firsttime = 0;310}311312if (no_swap)313return;314315if (!box) {316_box.width = xlib_dt->width;317_box.height = xlib_dt->height;318box = &_box;319}320321if (xlib_dt->drawable != xlib_drawable->drawable) {322if (xlib_dt->gc) {323XFreeGC(display, xlib_dt->gc);324xlib_dt->gc = NULL;325}326327if (xlib_dt->tempImage) {328XDestroyImage(xlib_dt->tempImage);329xlib_dt->tempImage = NULL;330}331332xlib_dt->drawable = xlib_drawable->drawable;333}334335if (xlib_dt->tempImage == NULL) {336assert(util_format_get_blockwidth(xlib_dt->format) == 1);337assert(util_format_get_blockheight(xlib_dt->format) == 1);338alloc_ximage(xlib_dt, xlib_drawable,339xlib_dt->stride / util_format_get_blocksize(xlib_dt->format),340xlib_dt->height);341if (!xlib_dt->tempImage)342return;343}344345if (xlib_dt->gc == NULL) {346xlib_dt->gc = XCreateGC(display, xlib_drawable->drawable, 0, NULL);347XSetFunction(display, xlib_dt->gc, GXcopy);348}349350if (xlib_dt->shm) {351ximage = xlib_dt->tempImage;352ximage->data = xlib_dt->data;353354/* _debug_printf("XSHM\n"); */355XShmPutImage(xlib_dt->display, xlib_drawable->drawable, xlib_dt->gc,356ximage, box->x, box->y, box->x, box->y,357box->width, box->height, False);358}359else {360/* display image in Window */361ximage = xlib_dt->tempImage;362ximage->data = xlib_dt->data;363364/* check that the XImage has been previously initialized */365assert(ximage->format);366assert(ximage->bitmap_unit);367368/* update XImage's fields */369ximage->width = xlib_dt->width;370ximage->height = xlib_dt->height;371ximage->bytes_per_line = xlib_dt->stride;372373/* _debug_printf("XPUT\n"); */374XPutImage(xlib_dt->display, xlib_drawable->drawable, xlib_dt->gc,375ximage, box->x, box->y, box->x, box->y,376box->width, box->height);377}378379XFlush(xlib_dt->display);380}381382383/**384* Display/copy the image in the surface into the X window specified385* by the display target.386*/387static void388xlib_displaytarget_display(struct sw_winsys *ws,389struct sw_displaytarget *dt,390void *context_private,391struct pipe_box *box)392{393struct xlib_drawable *xlib_drawable = (struct xlib_drawable *)context_private;394xlib_sw_display(xlib_drawable, dt, box);395}396397398static struct sw_displaytarget *399xlib_displaytarget_create(struct sw_winsys *winsys,400unsigned tex_usage,401enum pipe_format format,402unsigned width, unsigned height,403unsigned alignment,404const void *front_private,405unsigned *stride)406{407struct xlib_displaytarget *xlib_dt;408unsigned nblocksy, size;409int ignore;410411xlib_dt = CALLOC_STRUCT(xlib_displaytarget);412if (!xlib_dt)413goto no_xlib_dt;414415xlib_dt->display = ((struct xlib_sw_winsys *)winsys)->display;416xlib_dt->format = format;417xlib_dt->width = width;418xlib_dt->height = height;419420nblocksy = util_format_get_nblocksy(format, height);421xlib_dt->stride = align(util_format_get_stride(format, width), alignment);422size = xlib_dt->stride * nblocksy;423424if (!debug_get_option_xlib_no_shm() &&425XQueryExtension(xlib_dt->display, "MIT-SHM", &ignore, &ignore, &ignore)) {426xlib_dt->data = alloc_shm(xlib_dt, size);427if (xlib_dt->data) {428xlib_dt->shm = True;429}430}431432if (!xlib_dt->data) {433xlib_dt->data = align_malloc(size, alignment);434if (!xlib_dt->data)435goto no_data;436}437438*stride = xlib_dt->stride;439return (struct sw_displaytarget *)xlib_dt;440441no_data:442FREE(xlib_dt);443no_xlib_dt:444return NULL;445}446447448static struct sw_displaytarget *449xlib_displaytarget_from_handle(struct sw_winsys *winsys,450const struct pipe_resource *templet,451struct winsys_handle *whandle,452unsigned *stride)453{454assert(0);455return NULL;456}457458459static bool460xlib_displaytarget_get_handle(struct sw_winsys *winsys,461struct sw_displaytarget *dt,462struct winsys_handle *whandle)463{464assert(0);465return false;466}467468469static void470xlib_destroy(struct sw_winsys *ws)471{472FREE(ws);473}474475476struct sw_winsys *477xlib_create_sw_winsys(Display *display)478{479struct xlib_sw_winsys *ws;480481ws = CALLOC_STRUCT(xlib_sw_winsys);482if (!ws)483return NULL;484485ws->display = display;486ws->base.destroy = xlib_destroy;487488ws->base.is_displaytarget_format_supported = xlib_is_displaytarget_format_supported;489490ws->base.displaytarget_create = xlib_displaytarget_create;491ws->base.displaytarget_from_handle = xlib_displaytarget_from_handle;492ws->base.displaytarget_get_handle = xlib_displaytarget_get_handle;493ws->base.displaytarget_map = xlib_displaytarget_map;494ws->base.displaytarget_unmap = xlib_displaytarget_unmap;495ws->base.displaytarget_destroy = xlib_displaytarget_destroy;496497ws->base.displaytarget_display = xlib_displaytarget_display;498499return &ws->base;500}501502503