1
/**************************************************************************
3
* Copyright 2007 Tungsten Graphics, Inc., Bismarck, ND., USA
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:
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.
22
* The above copyright notice and this permission notice (including the
23
* next paragraph) shall be included in all copies or substantial portions
27
**************************************************************************/
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"
42
#include "state_tracker/xlib_sw_winsys.h"
45
#include <X11/Xlibint.h>
46
#include <X11/Xutil.h>
49
#include <X11/extensions/XShm.h>
51
DEBUG_GET_ONCE_BOOL_OPTION(xlib_no_shm, "XLIB_NO_SHM", FALSE)
54
* Display target for Xlib winsys.
55
* Low-level OS/window system memory buffer
57
struct xm_displaytarget
59
enum pipe_format format;
72
/* This is the last drawable that this display target was presented
73
* against. May need to recreate gc, tempImage when this changes??
77
XShmSegmentInfo shminfo;
83
* Subclass of sw_winsys for Xlib winsys
87
struct sw_winsys base;
97
static INLINE struct xm_displaytarget *
98
xm_displaytarget( struct sw_displaytarget *dt )
100
return (struct xm_displaytarget *)dt;
105
* X Shared Memory Image extension code
108
static volatile int mesaXErrorFlag = 0;
111
* Catches potential Xlib errors.
114
mesaHandleXError(Display *dpy, XErrorEvent *event)
123
static char *alloc_shm(struct xm_displaytarget *buf, unsigned size)
125
XShmSegmentInfo *const shminfo = & buf->shminfo;
128
shminfo->shmaddr = (char *) -1;
130
shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777);
131
if (shminfo->shmid < 0) {
135
shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
136
if (shminfo->shmaddr == (char *) -1) {
137
shmctl(shminfo->shmid, IPC_RMID, 0);
141
shminfo->readOnly = False;
142
return shminfo->shmaddr;
147
* Allocate a shared memory XImage back buffer for the given XMesaBuffer.
150
alloc_shm_ximage(struct xm_displaytarget *xm_dt,
151
struct xlib_drawable *xmb,
152
unsigned width, unsigned height)
155
* We have to do a _lot_ of error checking here to be sure we can
156
* really use the XSHM extension. It seems different servers trigger
157
* errors at different points if the extension won't work. Therefore
158
* we have to be very careful...
160
int (*old_handler)(Display *, XErrorEvent *);
162
xm_dt->tempImage = XShmCreateImage(xm_dt->display,
169
if (xm_dt->tempImage == NULL) {
176
old_handler = XSetErrorHandler(mesaHandleXError);
177
/* This may trigger the X protocol error we're ready to catch: */
178
XShmAttach(xm_dt->display, &xm_dt->shminfo);
179
XSync(xm_dt->display, False);
181
if (mesaXErrorFlag) {
182
/* we are on a remote display, this error is normal, don't print it */
183
XFlush(xm_dt->display);
185
XDestroyImage(xm_dt->tempImage);
186
xm_dt->tempImage = NULL;
188
(void) XSetErrorHandler(old_handler);
197
alloc_ximage(struct xm_displaytarget *xm_dt,
198
struct xlib_drawable *xmb,
199
unsigned width, unsigned height)
202
alloc_shm_ximage(xm_dt, xmb, width, height);
206
xm_dt->tempImage = XCreateImage(xm_dt->display,
215
xm_is_displaytarget_format_supported( struct sw_winsys *ws,
217
enum pipe_format format )
219
/* TODO: check visuals or other sensible thing here */
225
xm_displaytarget_map(struct sw_winsys *ws,
226
struct sw_displaytarget *dt,
229
struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
230
xm_dt->mapped = xm_dt->data;
231
return xm_dt->mapped;
235
xm_displaytarget_unmap(struct sw_winsys *ws,
236
struct sw_displaytarget *dt)
238
struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
239
xm_dt->mapped = NULL;
243
xm_displaytarget_destroy(struct sw_winsys *ws,
244
struct sw_displaytarget *dt)
246
struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
249
if (xm_dt->shminfo.shmid >= 0) {
250
shmdt(xm_dt->shminfo.shmaddr);
251
shmctl(xm_dt->shminfo.shmid, IPC_RMID, 0);
253
xm_dt->shminfo.shmid = -1;
254
xm_dt->shminfo.shmaddr = (char *) -1;
258
if (xm_dt->tempImage && xm_dt->tempImage->data == xm_dt->data) {
259
xm_dt->tempImage->data = NULL;
265
if (xm_dt->tempImage) {
266
XDestroyImage(xm_dt->tempImage);
267
xm_dt->tempImage = NULL;
271
XFreeGC(xm_dt->display, xm_dt->gc);
278
* Display/copy the image in the surface into the X window specified
279
* by the XMesaBuffer.
282
xlib_sw_display(struct xlib_drawable *xlib_drawable,
283
struct sw_displaytarget *dt)
285
static boolean no_swap = 0;
286
static boolean firsttime = 1;
287
struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
288
Display *display = xm_dt->display;
292
no_swap = getenv("SP_NO_RAST") != NULL;
299
if (xm_dt->drawable != xlib_drawable->drawable) {
301
XFreeGC( display, xm_dt->gc );
305
if (xm_dt->tempImage) {
306
XDestroyImage( xm_dt->tempImage );
307
xm_dt->tempImage = NULL;
310
xm_dt->drawable = xlib_drawable->drawable;
313
if (xm_dt->tempImage == NULL) {
314
assert(util_format_get_blockwidth(xm_dt->format) == 1);
315
assert(util_format_get_blockheight(xm_dt->format) == 1);
316
alloc_ximage(xm_dt, xlib_drawable,
317
xm_dt->stride / util_format_get_blocksize(xm_dt->format),
319
if (!xm_dt->tempImage)
323
if (xm_dt->gc == NULL) {
324
xm_dt->gc = XCreateGC( display, xlib_drawable->drawable, 0, NULL );
325
XSetFunction( display, xm_dt->gc, GXcopy );
330
ximage = xm_dt->tempImage;
331
ximage->data = xm_dt->data;
333
/* _debug_printf("XSHM\n"); */
334
XShmPutImage(xm_dt->display, xlib_drawable->drawable, xm_dt->gc,
335
ximage, 0, 0, 0, 0, xm_dt->width, xm_dt->height, False);
338
/* display image in Window */
339
ximage = xm_dt->tempImage;
340
ximage->data = xm_dt->data;
342
/* check that the XImage has been previously initialized */
343
assert(ximage->format);
344
assert(ximage->bitmap_unit);
346
/* update XImage's fields */
347
ximage->width = xm_dt->width;
348
ximage->height = xm_dt->height;
349
ximage->bytes_per_line = xm_dt->stride;
351
/* _debug_printf("XPUT\n"); */
352
XPutImage(xm_dt->display, xlib_drawable->drawable, xm_dt->gc,
353
ximage, 0, 0, 0, 0, xm_dt->width, xm_dt->height);
356
XFlush(xm_dt->display);
360
* Display/copy the image in the surface into the X window specified
361
* by the XMesaBuffer.
364
xm_displaytarget_display(struct sw_winsys *ws,
365
struct sw_displaytarget *dt,
366
void *context_private)
368
struct xlib_drawable *xlib_drawable = (struct xlib_drawable *)context_private;
369
xlib_sw_display(xlib_drawable, dt);
373
static struct sw_displaytarget *
374
xm_displaytarget_create(struct sw_winsys *winsys,
376
enum pipe_format format,
377
unsigned width, unsigned height,
381
struct xm_displaytarget *xm_dt;
382
unsigned nblocksy, size;
384
xm_dt = CALLOC_STRUCT(xm_displaytarget);
388
xm_dt->display = ((struct xlib_sw_winsys *)winsys)->display;
389
xm_dt->format = format;
390
xm_dt->width = width;
391
xm_dt->height = height;
393
nblocksy = util_format_get_nblocksy(format, height);
394
xm_dt->stride = align(util_format_get_stride(format, width), alignment);
395
size = xm_dt->stride * nblocksy;
397
if (!debug_get_option_xlib_no_shm()) {
398
xm_dt->data = alloc_shm(xm_dt, size);
405
xm_dt->data = align_malloc(size, alignment);
410
*stride = xm_dt->stride;
411
return (struct sw_displaytarget *)xm_dt;
420
static struct sw_displaytarget *
421
xm_displaytarget_from_handle(struct sw_winsys *winsys,
422
const struct pipe_resource *templet,
423
struct winsys_handle *whandle,
432
xm_displaytarget_get_handle(struct sw_winsys *winsys,
433
struct sw_displaytarget *dt,
434
struct winsys_handle *whandle)
442
xm_destroy( struct sw_winsys *ws )
449
xlib_create_sw_winsys( Display *display )
451
struct xlib_sw_winsys *ws;
453
ws = CALLOC_STRUCT(xlib_sw_winsys);
457
ws->display = display;
458
ws->base.destroy = xm_destroy;
460
ws->base.is_displaytarget_format_supported = xm_is_displaytarget_format_supported;
462
ws->base.displaytarget_create = xm_displaytarget_create;
463
ws->base.displaytarget_from_handle = xm_displaytarget_from_handle;
464
ws->base.displaytarget_get_handle = xm_displaytarget_get_handle;
465
ws->base.displaytarget_map = xm_displaytarget_map;
466
ws->base.displaytarget_unmap = xm_displaytarget_unmap;
467
ws->base.displaytarget_destroy = xm_displaytarget_destroy;
469
ws->base.displaytarget_display = xm_displaytarget_display;