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
;
94 static INLINE
struct xm_displaytarget
*
95 xm_displaytarget( struct sw_displaytarget
*dt
)
97 return (struct xm_displaytarget
*)dt
;
102 * X Shared Memory Image extension code
105 static volatile int mesaXErrorFlag
= 0;
108 * Catches potential Xlib errors.
111 mesaHandleXError(Display
*dpy
, XErrorEvent
*event
)
121 alloc_shm(struct xm_displaytarget
*buf
, unsigned size
)
123 XShmSegmentInfo
*const shminfo
= & buf
->shminfo
;
126 shminfo
->shmaddr
= (char *) -1;
128 shminfo
->shmid
= shmget(IPC_PRIVATE
, size
, IPC_CREAT
|0777);
129 if (shminfo
->shmid
< 0) {
133 shminfo
->shmaddr
= (char *) shmat(shminfo
->shmid
, 0, 0);
134 if (shminfo
->shmaddr
== (char *) -1) {
135 shmctl(shminfo
->shmid
, IPC_RMID
, 0);
139 shminfo
->readOnly
= False
;
140 return shminfo
->shmaddr
;
145 * Allocate a shared memory XImage back buffer for the given XMesaBuffer.
148 alloc_shm_ximage(struct xm_displaytarget
*xm_dt
,
149 struct xlib_drawable
*xmb
,
150 unsigned width
, unsigned height
)
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...
158 int (*old_handler
)(Display
*, XErrorEvent
*);
160 xm_dt
->tempImage
= XShmCreateImage(xm_dt
->display
,
167 if (xm_dt
->tempImage
== NULL
) {
174 old_handler
= XSetErrorHandler(mesaHandleXError
);
175 /* This may trigger the X protocol error we're ready to catch: */
176 XShmAttach(xm_dt
->display
, &xm_dt
->shminfo
);
177 XSync(xm_dt
->display
, False
);
179 if (mesaXErrorFlag
) {
180 /* we are on a remote display, this error is normal, don't print it */
181 XFlush(xm_dt
->display
);
183 XDestroyImage(xm_dt
->tempImage
);
184 xm_dt
->tempImage
= NULL
;
186 (void) XSetErrorHandler(old_handler
);
195 alloc_ximage(struct xm_displaytarget
*xm_dt
,
196 struct xlib_drawable
*xmb
,
197 unsigned width
, unsigned height
)
200 alloc_shm_ximage(xm_dt
, xmb
, width
, height
);
204 xm_dt
->tempImage
= XCreateImage(xm_dt
->display
,
213 xm_is_displaytarget_format_supported( struct sw_winsys
*ws
,
215 enum pipe_format format
)
217 /* TODO: check visuals or other sensible thing here */
223 xm_displaytarget_map(struct sw_winsys
*ws
,
224 struct sw_displaytarget
*dt
,
227 struct xm_displaytarget
*xm_dt
= xm_displaytarget(dt
);
228 xm_dt
->mapped
= xm_dt
->data
;
229 return xm_dt
->mapped
;
234 xm_displaytarget_unmap(struct sw_winsys
*ws
,
235 struct sw_displaytarget
*dt
)
237 struct xm_displaytarget
*xm_dt
= xm_displaytarget(dt
);
238 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
);
329 ximage
= xm_dt
->tempImage
;
330 ximage
->data
= xm_dt
->data
;
332 /* _debug_printf("XSHM\n"); */
333 XShmPutImage(xm_dt
->display
, xlib_drawable
->drawable
, xm_dt
->gc
,
334 ximage
, 0, 0, 0, 0, xm_dt
->width
, xm_dt
->height
, False
);
337 /* display image in Window */
338 ximage
= xm_dt
->tempImage
;
339 ximage
->data
= xm_dt
->data
;
341 /* check that the XImage has been previously initialized */
342 assert(ximage
->format
);
343 assert(ximage
->bitmap_unit
);
345 /* update XImage's fields */
346 ximage
->width
= xm_dt
->width
;
347 ximage
->height
= xm_dt
->height
;
348 ximage
->bytes_per_line
= xm_dt
->stride
;
350 /* _debug_printf("XPUT\n"); */
351 XPutImage(xm_dt
->display
, xlib_drawable
->drawable
, xm_dt
->gc
,
352 ximage
, 0, 0, 0, 0, xm_dt
->width
, xm_dt
->height
);
355 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
;