Merge branch 'mesa_7_5_branch' into mesa_7_6_branch
[mesa.git] / src / gallium / winsys / xlib / xlib_llvmpipe.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Bismarck, ND., USA
4 * All Rights Reserved.
5 *
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:
13 *
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.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 *
27 **************************************************************************/
28
29 /*
30 * Authors:
31 * Keith Whitwell
32 * Brian Paul
33 */
34
35
36 #if defined(GALLIUM_LLVMPIPE)
37
38 #include "xm_api.h"
39
40 #undef ASSERT
41 #undef Elements
42
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_math.h"
48 #include "util/u_memory.h"
49 #include "llvmpipe/lp_winsys.h"
50 #include "llvmpipe/lp_texture.h"
51
52 #include "xlib.h"
53
54 /**
55 * Subclass of pipe_buffer for Xlib winsys.
56 * Low-level OS/window system memory buffer
57 */
58 struct xm_displaytarget
59 {
60 enum pipe_format format;
61 struct pipe_format_block block;
62 unsigned width;
63 unsigned height;
64 unsigned stride;
65
66 void *data;
67 void *mapped;
68
69 XImage *tempImage;
70 #ifdef USE_XSHM
71 int shm;
72 XShmSegmentInfo shminfo;
73 #endif
74 };
75
76
77 /**
78 * Subclass of llvmpipe_winsys for Xlib winsys
79 */
80 struct xmesa_llvmpipe_winsys
81 {
82 struct llvmpipe_winsys base;
83 /* struct xmesa_visual *xm_visual; */
84 };
85
86
87
88 /** Cast wrapper */
89 static INLINE struct xm_displaytarget *
90 xm_displaytarget( struct llvmpipe_displaytarget *dt )
91 {
92 return (struct xm_displaytarget *)dt;
93 }
94
95
96 /**
97 * X Shared Memory Image extension code
98 */
99
100 #ifdef USE_XSHM
101
102 static volatile int mesaXErrorFlag = 0;
103
104 /**
105 * Catches potential Xlib errors.
106 */
107 static int
108 mesaHandleXError(Display *dpy, XErrorEvent *event)
109 {
110 (void) dpy;
111 (void) event;
112 mesaXErrorFlag = 1;
113 return 0;
114 }
115
116
117 static char *alloc_shm(struct xm_displaytarget *buf, unsigned size)
118 {
119 XShmSegmentInfo *const shminfo = & buf->shminfo;
120
121 shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777);
122 if (shminfo->shmid < 0) {
123 return NULL;
124 }
125
126 shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
127 if (shminfo->shmaddr == (char *) -1) {
128 shmctl(shminfo->shmid, IPC_RMID, 0);
129 return NULL;
130 }
131
132 shminfo->readOnly = False;
133 return shminfo->shmaddr;
134 }
135
136
137 /**
138 * Allocate a shared memory XImage back buffer for the given XMesaBuffer.
139 */
140 static void
141 alloc_shm_ximage(struct xm_displaytarget *xm_buffer,
142 struct xmesa_buffer *xmb,
143 unsigned width, unsigned height)
144 {
145 /*
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...
150 */
151 int (*old_handler)(Display *, XErrorEvent *);
152
153 xm_buffer->tempImage = XShmCreateImage(xmb->xm_visual->display,
154 xmb->xm_visual->visinfo->visual,
155 xmb->xm_visual->visinfo->depth,
156 ZPixmap,
157 NULL,
158 &xm_buffer->shminfo,
159 width, height);
160 if (xm_buffer->tempImage == NULL) {
161 xm_buffer->shm = 0;
162 return;
163 }
164
165
166 mesaXErrorFlag = 0;
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);
171
172 if (mesaXErrorFlag) {
173 /* we are on a remote display, this error is normal, don't print it */
174 XFlush(xmb->xm_visual->display);
175 mesaXErrorFlag = 0;
176 XDestroyImage(xm_buffer->tempImage);
177 xm_buffer->tempImage = NULL;
178 xm_buffer->shm = 0;
179 (void) XSetErrorHandler(old_handler);
180 return;
181 }
182
183 xm_buffer->shm = 1;
184 }
185
186 #endif /* USE_XSHM */
187
188 static boolean
189 xm_is_displaytarget_format_supported( struct llvmpipe_winsys *ws,
190 enum pipe_format format )
191 {
192 /* TODO: check visuals or other sensible thing here */
193 return TRUE;
194 }
195
196
197 static void *
198 xm_displaytarget_map(struct llvmpipe_winsys *ws,
199 struct llvmpipe_displaytarget *dt,
200 unsigned flags)
201 {
202 struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
203 xm_dt->mapped = xm_dt->data;
204 return xm_dt->mapped;
205 }
206
207 static void
208 xm_displaytarget_unmap(struct llvmpipe_winsys *ws,
209 struct llvmpipe_displaytarget *dt)
210 {
211 struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
212 xm_dt->mapped = NULL;
213 }
214
215 static void
216 xm_displaytarget_destroy(struct llvmpipe_winsys *ws,
217 struct llvmpipe_displaytarget *dt)
218 {
219 struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
220
221 if (xm_dt->data) {
222 #ifdef USE_XSHM
223 if (xm_dt->shminfo.shmid >= 0) {
224 shmdt(xm_dt->shminfo.shmaddr);
225 shmctl(xm_dt->shminfo.shmid, IPC_RMID, 0);
226
227 xm_dt->shminfo.shmid = -1;
228 xm_dt->shminfo.shmaddr = (char *) -1;
229 }
230 else
231 #endif
232 FREE(xm_dt->data);
233 }
234
235 FREE(xm_dt);
236 }
237
238
239 /**
240 * Display/copy the image in the surface into the X window specified
241 * by the XMesaBuffer.
242 */
243 static void
244 xm_llvmpipe_display(struct xmesa_buffer *xm_buffer,
245 struct llvmpipe_displaytarget *dt)
246 {
247 XImage *ximage;
248 struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
249 static boolean no_swap = 0;
250 static boolean firsttime = 1;
251
252 if (firsttime) {
253 no_swap = getenv("SP_NO_RAST") != NULL;
254 firsttime = 0;
255 }
256
257 if (no_swap)
258 return;
259
260 #ifdef USE_XSHM
261 if (xm_dt->shm)
262 {
263 if (xm_dt->tempImage == NULL)
264 {
265 assert(xm_dt->block.width == 1);
266 assert(xm_dt->block.height == 1);
267 alloc_shm_ximage(xm_dt, xm_buffer,
268 xm_dt->stride / xm_dt->block.size,
269 xm_dt->height);
270 }
271
272 ximage = xm_dt->tempImage;
273 ximage->data = xm_dt->data;
274
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);
278 }
279 else
280 #endif
281 {
282 /* display image in Window */
283 ximage = xm_dt->tempImage;
284 ximage->data = xm_dt->data;
285
286 /* check that the XImage has been previously initialized */
287 assert(ximage->format);
288 assert(ximage->bitmap_unit);
289
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;
294
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);
298 }
299 }
300
301 /**
302 * Display/copy the image in the surface into the X window specified
303 * by the XMesaBuffer.
304 */
305 static void
306 xm_displaytarget_display(struct llvmpipe_winsys *ws,
307 struct llvmpipe_displaytarget *dt,
308 void *context_private)
309 {
310 XMesaContext xmctx = (XMesaContext) context_private;
311 struct xmesa_buffer *xm_buffer = xmctx->xm_buffer;
312 xm_llvmpipe_display(xm_buffer, dt);
313 }
314
315
316 static struct llvmpipe_displaytarget *
317 xm_displaytarget_create(struct llvmpipe_winsys *winsys,
318 enum pipe_format format,
319 unsigned width, unsigned height,
320 unsigned alignment,
321 unsigned *stride)
322 {
323 struct xm_displaytarget *xm_dt = CALLOC_STRUCT(xm_displaytarget);
324 unsigned nblocksx, nblocksy, size;
325
326 xm_dt = CALLOC_STRUCT(xm_displaytarget);
327 if(!xm_dt)
328 goto no_xm_dt;
329
330 xm_dt->format = format;
331 xm_dt->width = width;
332 xm_dt->height = height;
333
334 pf_get_block(format, &xm_dt->block);
335 nblocksx = pf_get_nblocksx(&xm_dt->block, width);
336 nblocksy = pf_get_nblocksy(&xm_dt->block, height);
337 xm_dt->stride = align(nblocksx * xm_dt->block.size, alignment);
338 size = xm_dt->stride * nblocksy;
339
340 #ifdef USE_XSHM
341 if (!debug_get_bool_option("XLIB_NO_SHM", FALSE))
342 {
343 xm_dt->shminfo.shmid = -1;
344 xm_dt->shminfo.shmaddr = (char *) -1;
345 xm_dt->shm = TRUE;
346
347 xm_dt->data = alloc_shm(xm_dt, size);
348 if(!xm_dt->data)
349 goto no_data;
350 }
351 #endif
352
353 if(!xm_dt->data) {
354 xm_dt->data = align_malloc(size, alignment);
355 if(!xm_dt->data)
356 goto no_data;
357 }
358
359 *stride = xm_dt->stride;
360 return (struct llvmpipe_displaytarget *)xm_dt;
361
362 no_data:
363 FREE(xm_dt);
364 no_xm_dt:
365 return NULL;
366 }
367
368
369 static void
370 xm_destroy( struct llvmpipe_winsys *ws )
371 {
372 FREE(ws);
373 }
374
375
376 static struct llvmpipe_winsys *
377 xlib_create_llvmpipe_winsys( void )
378 {
379 struct xmesa_llvmpipe_winsys *ws;
380
381 ws = CALLOC_STRUCT(xmesa_llvmpipe_winsys);
382 if (!ws)
383 return NULL;
384
385 ws->base.destroy = xm_destroy;
386
387 ws->base.is_displaytarget_format_supported = xm_is_displaytarget_format_supported;
388
389 ws->base.displaytarget_create = xm_displaytarget_create;
390 ws->base.displaytarget_map = xm_displaytarget_map;
391 ws->base.displaytarget_unmap = xm_displaytarget_unmap;
392 ws->base.displaytarget_destroy = xm_displaytarget_destroy;
393
394 ws->base.displaytarget_display = xm_displaytarget_display;
395
396 return &ws->base;
397 }
398
399
400 static struct pipe_screen *
401 xlib_create_llvmpipe_screen( void )
402 {
403 struct llvmpipe_winsys *winsys;
404 struct pipe_screen *screen;
405
406 winsys = xlib_create_llvmpipe_winsys();
407 if (winsys == NULL)
408 return NULL;
409
410 screen = llvmpipe_create_screen(winsys);
411 if (screen == NULL)
412 goto fail;
413
414 return screen;
415
416 fail:
417 if (winsys)
418 winsys->destroy( winsys );
419
420 return NULL;
421 }
422
423
424 static struct pipe_context *
425 xlib_create_llvmpipe_context( struct pipe_screen *screen,
426 void *context_private )
427 {
428 struct pipe_context *pipe;
429
430 pipe = llvmpipe_create(screen);
431 if (pipe == NULL)
432 goto fail;
433
434 pipe->priv = context_private;
435 return pipe;
436
437 fail:
438 /* Free stuff here */
439 return NULL;
440 }
441
442
443 static void
444 xlib_llvmpipe_display_surface(struct xmesa_buffer *xm_buffer,
445 struct pipe_surface *surf)
446 {
447 struct llvmpipe_texture *texture = llvmpipe_texture(surf->texture);
448
449 assert(texture->dt);
450 if (texture->dt)
451 xm_llvmpipe_display(xm_buffer, texture->dt);
452 }
453
454
455 struct xm_driver xlib_llvmpipe_driver =
456 {
457 .create_pipe_screen = xlib_create_llvmpipe_screen,
458 .create_pipe_context = xlib_create_llvmpipe_context,
459 .display_surface = xlib_llvmpipe_display_surface
460 };
461
462
463
464 #endif /* GALLIUM_LLVMPIPE */