1 /**************************************************************************
3 * Copyright 2007 VMware, 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/format/u_format.h"
39 #include "util/u_math.h"
40 #include "util/u_memory.h"
42 #include "frontend/xlibsw_api.h"
43 #include "xlib_sw_winsys.h"
46 #include <X11/Xlibint.h>
47 #include <X11/Xutil.h>
50 #include <X11/extensions/XShm.h>
52 DEBUG_GET_ONCE_BOOL_OPTION(xlib_no_shm
, "XLIB_NO_SHM", false)
55 * Display target for Xlib winsys.
56 * Low-level OS/window system memory buffer
58 struct xlib_displaytarget
60 enum pipe_format format
;
73 /* This is the last drawable that this display target was presented
74 * against. May need to recreate gc, tempImage when this changes??
78 XShmSegmentInfo shminfo
;
79 Bool shm
; /** Using shared memory images? */
84 * Subclass of sw_winsys for Xlib winsys
88 struct sw_winsys base
;
95 static inline struct xlib_displaytarget
*
96 xlib_displaytarget(struct sw_displaytarget
*dt
)
98 return (struct xlib_displaytarget
*) dt
;
103 * X Shared Memory Image extension code
106 static volatile int XErrorFlag
= 0;
109 * Catches potential Xlib errors.
112 handle_xerror(Display
*dpy
, XErrorEvent
*event
)
122 alloc_shm(struct xlib_displaytarget
*buf
, unsigned size
)
124 XShmSegmentInfo
*const shminfo
= & buf
->shminfo
;
127 shminfo
->shmaddr
= (char *) -1;
129 /* 0600 = user read+write */
130 shminfo
->shmid
= shmget(IPC_PRIVATE
, size
, IPC_CREAT
| 0600);
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 display target.
150 alloc_shm_ximage(struct xlib_displaytarget
*xlib_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 xlib_dt
->tempImage
= XShmCreateImage(xlib_dt
->display
,
169 if (xlib_dt
->tempImage
== NULL
) {
170 shmctl(xlib_dt
->shminfo
.shmid
, IPC_RMID
, 0);
171 xlib_dt
->shm
= False
;
177 old_handler
= XSetErrorHandler(handle_xerror
);
178 /* This may trigger the X protocol error we're ready to catch: */
179 XShmAttach(xlib_dt
->display
, &xlib_dt
->shminfo
);
180 XSync(xlib_dt
->display
, False
);
182 /* Mark the segment to be destroyed, so that it is automatically destroyed
183 * when this process dies. Needs to be after XShmAttach() for *BSD.
185 shmctl(xlib_dt
->shminfo
.shmid
, IPC_RMID
, 0);
188 /* we are on a remote display, this error is normal, don't print it */
189 XFlush(xlib_dt
->display
);
191 XDestroyImage(xlib_dt
->tempImage
);
192 xlib_dt
->tempImage
= NULL
;
193 xlib_dt
->shm
= False
;
194 (void) XSetErrorHandler(old_handler
);
203 alloc_ximage(struct xlib_displaytarget
*xlib_dt
,
204 struct xlib_drawable
*xmb
,
205 unsigned width
, unsigned height
)
207 /* try allocating a shared memory image first */
209 alloc_shm_ximage(xlib_dt
, xmb
, width
, height
);
210 if (xlib_dt
->tempImage
)
211 return; /* success */
214 /* try regular (non-shared memory) image */
215 xlib_dt
->tempImage
= XCreateImage(xlib_dt
->display
,
224 xlib_is_displaytarget_format_supported(struct sw_winsys
*ws
,
226 enum pipe_format format
)
228 /* TODO: check visuals or other sensible thing here */
234 xlib_displaytarget_map(struct sw_winsys
*ws
,
235 struct sw_displaytarget
*dt
,
238 struct xlib_displaytarget
*xlib_dt
= xlib_displaytarget(dt
);
239 xlib_dt
->mapped
= xlib_dt
->data
;
240 return xlib_dt
->mapped
;
245 xlib_displaytarget_unmap(struct sw_winsys
*ws
,
246 struct sw_displaytarget
*dt
)
248 struct xlib_displaytarget
*xlib_dt
= xlib_displaytarget(dt
);
249 xlib_dt
->mapped
= NULL
;
254 xlib_displaytarget_destroy(struct sw_winsys
*ws
,
255 struct sw_displaytarget
*dt
)
257 struct xlib_displaytarget
*xlib_dt
= xlib_displaytarget(dt
);
260 if (xlib_dt
->shminfo
.shmid
>= 0) {
261 shmdt(xlib_dt
->shminfo
.shmaddr
);
262 shmctl(xlib_dt
->shminfo
.shmid
, IPC_RMID
, 0);
264 xlib_dt
->shminfo
.shmid
= -1;
265 xlib_dt
->shminfo
.shmaddr
= (char *) -1;
267 xlib_dt
->data
= NULL
;
268 if (xlib_dt
->tempImage
)
269 xlib_dt
->tempImage
->data
= NULL
;
272 align_free(xlib_dt
->data
);
273 if (xlib_dt
->tempImage
&& xlib_dt
->tempImage
->data
== xlib_dt
->data
) {
274 xlib_dt
->tempImage
->data
= NULL
;
276 xlib_dt
->data
= NULL
;
280 if (xlib_dt
->tempImage
) {
281 XDestroyImage(xlib_dt
->tempImage
);
282 xlib_dt
->tempImage
= NULL
;
286 XFreeGC(xlib_dt
->display
, xlib_dt
->gc
);
293 * Display/copy the image in the surface into the X window specified
294 * by the display target.
297 xlib_sw_display(struct xlib_drawable
*xlib_drawable
,
298 struct sw_displaytarget
*dt
)
300 static bool no_swap
= false;
301 static bool firsttime
= true;
302 struct xlib_displaytarget
*xlib_dt
= xlib_displaytarget(dt
);
303 Display
*display
= xlib_dt
->display
;
307 no_swap
= getenv("SP_NO_RAST") != NULL
;
314 if (xlib_dt
->drawable
!= xlib_drawable
->drawable
) {
316 XFreeGC(display
, xlib_dt
->gc
);
320 if (xlib_dt
->tempImage
) {
321 XDestroyImage(xlib_dt
->tempImage
);
322 xlib_dt
->tempImage
= NULL
;
325 xlib_dt
->drawable
= xlib_drawable
->drawable
;
328 if (xlib_dt
->tempImage
== NULL
) {
329 assert(util_format_get_blockwidth(xlib_dt
->format
) == 1);
330 assert(util_format_get_blockheight(xlib_dt
->format
) == 1);
331 alloc_ximage(xlib_dt
, xlib_drawable
,
332 xlib_dt
->stride
/ util_format_get_blocksize(xlib_dt
->format
),
334 if (!xlib_dt
->tempImage
)
338 if (xlib_dt
->gc
== NULL
) {
339 xlib_dt
->gc
= XCreateGC(display
, xlib_drawable
->drawable
, 0, NULL
);
340 XSetFunction(display
, xlib_dt
->gc
, GXcopy
);
344 ximage
= xlib_dt
->tempImage
;
345 ximage
->data
= xlib_dt
->data
;
347 /* _debug_printf("XSHM\n"); */
348 XShmPutImage(xlib_dt
->display
, xlib_drawable
->drawable
, xlib_dt
->gc
,
349 ximage
, 0, 0, 0, 0, xlib_dt
->width
, xlib_dt
->height
, False
);
352 /* display image in Window */
353 ximage
= xlib_dt
->tempImage
;
354 ximage
->data
= xlib_dt
->data
;
356 /* check that the XImage has been previously initialized */
357 assert(ximage
->format
);
358 assert(ximage
->bitmap_unit
);
360 /* update XImage's fields */
361 ximage
->width
= xlib_dt
->width
;
362 ximage
->height
= xlib_dt
->height
;
363 ximage
->bytes_per_line
= xlib_dt
->stride
;
365 /* _debug_printf("XPUT\n"); */
366 XPutImage(xlib_dt
->display
, xlib_drawable
->drawable
, xlib_dt
->gc
,
367 ximage
, 0, 0, 0, 0, xlib_dt
->width
, xlib_dt
->height
);
370 XFlush(xlib_dt
->display
);
375 * Display/copy the image in the surface into the X window specified
376 * by the display target.
379 xlib_displaytarget_display(struct sw_winsys
*ws
,
380 struct sw_displaytarget
*dt
,
381 void *context_private
,
382 struct pipe_box
*box
)
384 struct xlib_drawable
*xlib_drawable
= (struct xlib_drawable
*)context_private
;
385 xlib_sw_display(xlib_drawable
, dt
);
389 static struct sw_displaytarget
*
390 xlib_displaytarget_create(struct sw_winsys
*winsys
,
392 enum pipe_format format
,
393 unsigned width
, unsigned height
,
395 const void *front_private
,
398 struct xlib_displaytarget
*xlib_dt
;
399 unsigned nblocksy
, size
;
402 xlib_dt
= CALLOC_STRUCT(xlib_displaytarget
);
406 xlib_dt
->display
= ((struct xlib_sw_winsys
*)winsys
)->display
;
407 xlib_dt
->format
= format
;
408 xlib_dt
->width
= width
;
409 xlib_dt
->height
= height
;
411 nblocksy
= util_format_get_nblocksy(format
, height
);
412 xlib_dt
->stride
= align(util_format_get_stride(format
, width
), alignment
);
413 size
= xlib_dt
->stride
* nblocksy
;
415 if (!debug_get_option_xlib_no_shm() &&
416 XQueryExtension(xlib_dt
->display
, "MIT-SHM", &ignore
, &ignore
, &ignore
)) {
417 xlib_dt
->data
= alloc_shm(xlib_dt
, size
);
423 if (!xlib_dt
->data
) {
424 xlib_dt
->data
= align_malloc(size
, alignment
);
429 *stride
= xlib_dt
->stride
;
430 return (struct sw_displaytarget
*)xlib_dt
;
439 static struct sw_displaytarget
*
440 xlib_displaytarget_from_handle(struct sw_winsys
*winsys
,
441 const struct pipe_resource
*templet
,
442 struct winsys_handle
*whandle
,
451 xlib_displaytarget_get_handle(struct sw_winsys
*winsys
,
452 struct sw_displaytarget
*dt
,
453 struct winsys_handle
*whandle
)
461 xlib_destroy(struct sw_winsys
*ws
)
468 xlib_create_sw_winsys(Display
*display
)
470 struct xlib_sw_winsys
*ws
;
472 ws
= CALLOC_STRUCT(xlib_sw_winsys
);
476 ws
->display
= display
;
477 ws
->base
.destroy
= xlib_destroy
;
479 ws
->base
.is_displaytarget_format_supported
= xlib_is_displaytarget_format_supported
;
481 ws
->base
.displaytarget_create
= xlib_displaytarget_create
;
482 ws
->base
.displaytarget_from_handle
= xlib_displaytarget_from_handle
;
483 ws
->base
.displaytarget_get_handle
= xlib_displaytarget_get_handle
;
484 ws
->base
.displaytarget_map
= xlib_displaytarget_map
;
485 ws
->base
.displaytarget_unmap
= xlib_displaytarget_unmap
;
486 ws
->base
.displaytarget_destroy
= xlib_displaytarget_destroy
;
488 ws
->base
.displaytarget_display
= xlib_displaytarget_display
;