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 **************************************************************************/
36 #if defined(GALLIUM_LLVMPIPE)
43 #include "pipe/internal/p_winsys_screen.h"
44 #include "pipe/p_format.h"
45 #include "pipe/p_context.h"
46 #include "pipe/p_inlines.h"
47 #include "util/u_format.h"
48 #include "util/u_math.h"
49 #include "util/u_memory.h"
50 #include "llvmpipe/lp_winsys.h"
51 #include "llvmpipe/lp_texture.h"
56 * Subclass of pipe_buffer for Xlib winsys.
57 * Low-level OS/window system memory buffer
59 struct xm_displaytarget
61 enum pipe_format format
;
72 XShmSegmentInfo shminfo
;
78 * Subclass of llvmpipe_winsys for Xlib winsys
80 struct xmesa_llvmpipe_winsys
82 struct llvmpipe_winsys base
;
83 /* struct xmesa_visual *xm_visual; */
89 static INLINE
struct xm_displaytarget
*
90 xm_displaytarget( struct llvmpipe_displaytarget
*dt
)
92 return (struct xm_displaytarget
*)dt
;
97 * X Shared Memory Image extension code
102 static volatile int mesaXErrorFlag
= 0;
105 * Catches potential Xlib errors.
108 mesaHandleXError(Display
*dpy
, XErrorEvent
*event
)
117 static char *alloc_shm(struct xm_displaytarget
*buf
, unsigned size
)
119 XShmSegmentInfo
*const shminfo
= & buf
->shminfo
;
121 shminfo
->shmid
= shmget(IPC_PRIVATE
, size
, IPC_CREAT
|0777);
122 if (shminfo
->shmid
< 0) {
126 shminfo
->shmaddr
= (char *) shmat(shminfo
->shmid
, 0, 0);
127 if (shminfo
->shmaddr
== (char *) -1) {
128 shmctl(shminfo
->shmid
, IPC_RMID
, 0);
132 shminfo
->readOnly
= False
;
133 return shminfo
->shmaddr
;
138 * Allocate a shared memory XImage back buffer for the given XMesaBuffer.
141 alloc_shm_ximage(struct xm_displaytarget
*xm_buffer
,
142 struct xmesa_buffer
*xmb
,
143 unsigned width
, unsigned height
)
146 * We have to do a _lot_ of error checking here to be sure we can
147 * really use the XSHM extension. It seems different servers trigger
148 * errors at different points if the extension won't work. Therefore
149 * we have to be very careful...
151 int (*old_handler
)(Display
*, XErrorEvent
*);
153 xm_buffer
->tempImage
= XShmCreateImage(xmb
->xm_visual
->display
,
154 xmb
->xm_visual
->visinfo
->visual
,
155 xmb
->xm_visual
->visinfo
->depth
,
160 if (xm_buffer
->tempImage
== NULL
) {
167 old_handler
= XSetErrorHandler(mesaHandleXError
);
168 /* This may trigger the X protocol error we're ready to catch: */
169 XShmAttach(xmb
->xm_visual
->display
, &xm_buffer
->shminfo
);
170 XSync(xmb
->xm_visual
->display
, False
);
172 if (mesaXErrorFlag
) {
173 /* we are on a remote display, this error is normal, don't print it */
174 XFlush(xmb
->xm_visual
->display
);
176 XDestroyImage(xm_buffer
->tempImage
);
177 xm_buffer
->tempImage
= NULL
;
179 (void) XSetErrorHandler(old_handler
);
186 #endif /* USE_XSHM */
189 xm_is_displaytarget_format_supported( struct llvmpipe_winsys
*ws
,
190 enum pipe_format format
)
192 /* TODO: check visuals or other sensible thing here */
198 xm_displaytarget_map(struct llvmpipe_winsys
*ws
,
199 struct llvmpipe_displaytarget
*dt
,
202 struct xm_displaytarget
*xm_dt
= xm_displaytarget(dt
);
203 xm_dt
->mapped
= xm_dt
->data
;
204 return xm_dt
->mapped
;
208 xm_displaytarget_unmap(struct llvmpipe_winsys
*ws
,
209 struct llvmpipe_displaytarget
*dt
)
211 struct xm_displaytarget
*xm_dt
= xm_displaytarget(dt
);
212 xm_dt
->mapped
= NULL
;
216 xm_displaytarget_destroy(struct llvmpipe_winsys
*ws
,
217 struct llvmpipe_displaytarget
*dt
)
219 struct xm_displaytarget
*xm_dt
= xm_displaytarget(dt
);
223 if (xm_dt
->shminfo
.shmid
>= 0) {
224 shmdt(xm_dt
->shminfo
.shmaddr
);
225 shmctl(xm_dt
->shminfo
.shmid
, IPC_RMID
, 0);
227 xm_dt
->shminfo
.shmid
= -1;
228 xm_dt
->shminfo
.shmaddr
= (char *) -1;
240 * Display/copy the image in the surface into the X window specified
241 * by the XMesaBuffer.
244 xm_llvmpipe_display(struct xmesa_buffer
*xm_buffer
,
245 struct llvmpipe_displaytarget
*dt
)
248 struct xm_displaytarget
*xm_dt
= xm_displaytarget(dt
);
249 static boolean no_swap
= 0;
250 static boolean firsttime
= 1;
253 no_swap
= getenv("SP_NO_RAST") != NULL
;
263 if (xm_dt
->tempImage
== NULL
)
265 assert(util_format_get_blockwidth(xm_dt
->format
) == 1);
266 assert(util_format_get_blockheight(xm_dt
->format
) == 1);
267 alloc_shm_ximage(xm_dt
, xm_buffer
,
268 xm_dt
->stride
/ util_format_get_blocksize(xm_dt
->format
),
272 ximage
= xm_dt
->tempImage
;
273 ximage
->data
= xm_dt
->data
;
275 /* _debug_printf("XSHM\n"); */
276 XShmPutImage(xm_buffer
->xm_visual
->display
, xm_buffer
->drawable
, xm_buffer
->gc
,
277 ximage
, 0, 0, 0, 0, xm_dt
->width
, xm_dt
->height
, False
);
282 /* display image in Window */
283 ximage
= xm_dt
->tempImage
;
284 ximage
->data
= xm_dt
->data
;
286 /* check that the XImage has been previously initialized */
287 assert(ximage
->format
);
288 assert(ximage
->bitmap_unit
);
290 /* update XImage's fields */
291 ximage
->width
= xm_dt
->width
;
292 ximage
->height
= xm_dt
->height
;
293 ximage
->bytes_per_line
= xm_dt
->stride
;
295 /* _debug_printf("XPUT\n"); */
296 XPutImage(xm_buffer
->xm_visual
->display
, xm_buffer
->drawable
, xm_buffer
->gc
,
297 ximage
, 0, 0, 0, 0, xm_dt
->width
, xm_dt
->height
);
302 * Display/copy the image in the surface into the X window specified
303 * by the XMesaBuffer.
306 xm_displaytarget_display(struct llvmpipe_winsys
*ws
,
307 struct llvmpipe_displaytarget
*dt
,
308 void *context_private
)
310 XMesaContext xmctx
= (XMesaContext
) context_private
;
311 struct xmesa_buffer
*xm_buffer
= xmctx
->xm_buffer
;
312 xm_llvmpipe_display(xm_buffer
, dt
);
316 static struct llvmpipe_displaytarget
*
317 xm_displaytarget_create(struct llvmpipe_winsys
*winsys
,
318 enum pipe_format format
,
319 unsigned width
, unsigned height
,
323 struct xm_displaytarget
*xm_dt
= CALLOC_STRUCT(xm_displaytarget
);
324 unsigned nblocksy
, size
;
326 xm_dt
= CALLOC_STRUCT(xm_displaytarget
);
330 xm_dt
->format
= format
;
331 xm_dt
->width
= width
;
332 xm_dt
->height
= height
;
334 nblocksy
= util_format_get_nblocksy(format
, height
);
335 xm_dt
->stride
= align(util_format_get_stride(format
, width
), alignment
);
336 size
= xm_dt
->stride
* nblocksy
;
339 if (!debug_get_bool_option("XLIB_NO_SHM", FALSE
))
341 xm_dt
->shminfo
.shmid
= -1;
342 xm_dt
->shminfo
.shmaddr
= (char *) -1;
345 xm_dt
->data
= alloc_shm(xm_dt
, size
);
352 xm_dt
->data
= align_malloc(size
, alignment
);
357 *stride
= xm_dt
->stride
;
358 return (struct llvmpipe_displaytarget
*)xm_dt
;
368 xm_destroy( struct llvmpipe_winsys
*ws
)
374 static struct llvmpipe_winsys
*
375 xlib_create_llvmpipe_winsys( void )
377 struct xmesa_llvmpipe_winsys
*ws
;
379 ws
= CALLOC_STRUCT(xmesa_llvmpipe_winsys
);
383 ws
->base
.destroy
= xm_destroy
;
385 ws
->base
.is_displaytarget_format_supported
= xm_is_displaytarget_format_supported
;
387 ws
->base
.displaytarget_create
= xm_displaytarget_create
;
388 ws
->base
.displaytarget_map
= xm_displaytarget_map
;
389 ws
->base
.displaytarget_unmap
= xm_displaytarget_unmap
;
390 ws
->base
.displaytarget_destroy
= xm_displaytarget_destroy
;
392 ws
->base
.displaytarget_display
= xm_displaytarget_display
;
398 static struct pipe_screen
*
399 xlib_create_llvmpipe_screen( void )
401 struct llvmpipe_winsys
*winsys
;
402 struct pipe_screen
*screen
;
404 winsys
= xlib_create_llvmpipe_winsys();
408 screen
= llvmpipe_create_screen(winsys
);
416 winsys
->destroy( winsys
);
422 static struct pipe_context
*
423 xlib_create_llvmpipe_context( struct pipe_screen
*screen
,
424 void *context_private
)
426 struct pipe_context
*pipe
;
428 pipe
= llvmpipe_create(screen
);
432 pipe
->priv
= context_private
;
436 /* Free stuff here */
442 xlib_llvmpipe_display_surface(struct xmesa_buffer
*xm_buffer
,
443 struct pipe_surface
*surf
)
445 struct llvmpipe_texture
*texture
= llvmpipe_texture(surf
->texture
);
449 xm_llvmpipe_display(xm_buffer
, texture
->dt
);
453 struct xm_driver xlib_llvmpipe_driver
=
455 .create_pipe_screen
= xlib_create_llvmpipe_screen
,
456 .create_pipe_context
= xlib_create_llvmpipe_context
,
457 .display_surface
= xlib_llvmpipe_display_surface
462 #endif /* GALLIUM_LLVMPIPE */