softpipe: rework to use the llvmpipe winsys
[mesa.git] / src / gallium / winsys / xlib / xlib_sw_winsys.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
37 #include "xm_api.h"
38
39 #undef ASSERT
40 #undef Elements
41
42 #include "pipe/p_format.h"
43 #include "pipe/p_context.h"
44 #include "util/u_inlines.h"
45 #include "util/u_format.h"
46 #include "util/u_math.h"
47 #include "util/u_memory.h"
48
49 #include "state_tracker/sw_winsys.h"
50
51 #include "xlib.h"
52
53 /**
54 * Subclass of pipe_buffer for Xlib winsys.
55 * Low-level OS/window system memory buffer
56 */
57 struct xm_displaytarget
58 {
59 enum pipe_format format;
60 unsigned width;
61 unsigned height;
62 unsigned stride;
63
64 void *data;
65 void *mapped;
66
67 XImage *tempImage;
68 #ifdef USE_XSHM
69 int shm;
70 XShmSegmentInfo shminfo;
71 #endif
72 };
73
74
75 /**
76 * Subclass of sw_winsys for Xlib winsys
77 */
78 struct xmesa_sw_winsys
79 {
80 struct sw_winsys base;
81 /* struct xmesa_visual *xm_visual; */
82 };
83
84
85
86 /** Cast wrapper */
87 static INLINE struct xm_displaytarget *
88 xm_displaytarget( struct sw_displaytarget *dt )
89 {
90 return (struct xm_displaytarget *)dt;
91 }
92
93
94 /**
95 * X Shared Memory Image extension code
96 */
97
98 #ifdef USE_XSHM
99
100 static volatile int mesaXErrorFlag = 0;
101
102 /**
103 * Catches potential Xlib errors.
104 */
105 static int
106 mesaHandleXError(Display *dpy, XErrorEvent *event)
107 {
108 (void) dpy;
109 (void) event;
110 mesaXErrorFlag = 1;
111 return 0;
112 }
113
114
115 static char *alloc_shm(struct xm_displaytarget *buf, unsigned size)
116 {
117 XShmSegmentInfo *const shminfo = & buf->shminfo;
118
119 shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777);
120 if (shminfo->shmid < 0) {
121 return NULL;
122 }
123
124 shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
125 if (shminfo->shmaddr == (char *) -1) {
126 shmctl(shminfo->shmid, IPC_RMID, 0);
127 return NULL;
128 }
129
130 shminfo->readOnly = False;
131 return shminfo->shmaddr;
132 }
133
134
135 /**
136 * Allocate a shared memory XImage back buffer for the given XMesaBuffer.
137 */
138 static void
139 alloc_shm_ximage(struct xm_displaytarget *xm_buffer,
140 struct xmesa_buffer *xmb,
141 unsigned width, unsigned height)
142 {
143 /*
144 * We have to do a _lot_ of error checking here to be sure we can
145 * really use the XSHM extension. It seems different servers trigger
146 * errors at different points if the extension won't work. Therefore
147 * we have to be very careful...
148 */
149 int (*old_handler)(Display *, XErrorEvent *);
150
151 xm_buffer->tempImage = XShmCreateImage(xmb->xm_visual->display,
152 xmb->xm_visual->visinfo->visual,
153 xmb->xm_visual->visinfo->depth,
154 ZPixmap,
155 NULL,
156 &xm_buffer->shminfo,
157 width, height);
158 if (xm_buffer->tempImage == NULL) {
159 xm_buffer->shm = 0;
160 return;
161 }
162
163
164 mesaXErrorFlag = 0;
165 old_handler = XSetErrorHandler(mesaHandleXError);
166 /* This may trigger the X protocol error we're ready to catch: */
167 XShmAttach(xmb->xm_visual->display, &xm_buffer->shminfo);
168 XSync(xmb->xm_visual->display, False);
169
170 if (mesaXErrorFlag) {
171 /* we are on a remote display, this error is normal, don't print it */
172 XFlush(xmb->xm_visual->display);
173 mesaXErrorFlag = 0;
174 XDestroyImage(xm_buffer->tempImage);
175 xm_buffer->tempImage = NULL;
176 xm_buffer->shm = 0;
177 (void) XSetErrorHandler(old_handler);
178 return;
179 }
180
181 xm_buffer->shm = 1;
182 }
183
184 #endif /* USE_XSHM */
185
186 static boolean
187 xm_is_displaytarget_format_supported( struct sw_winsys *ws,
188 enum pipe_format format )
189 {
190 /* TODO: check visuals or other sensible thing here */
191 return TRUE;
192 }
193
194
195 static void *
196 xm_displaytarget_map(struct sw_winsys *ws,
197 struct sw_displaytarget *dt,
198 unsigned flags)
199 {
200 struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
201 xm_dt->mapped = xm_dt->data;
202 return xm_dt->mapped;
203 }
204
205 static void
206 xm_displaytarget_unmap(struct sw_winsys *ws,
207 struct sw_displaytarget *dt)
208 {
209 struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
210 xm_dt->mapped = NULL;
211 }
212
213 static void
214 xm_displaytarget_destroy(struct sw_winsys *ws,
215 struct sw_displaytarget *dt)
216 {
217 struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
218
219 if (xm_dt->data) {
220 #ifdef USE_XSHM
221 if (xm_dt->shminfo.shmid >= 0) {
222 shmdt(xm_dt->shminfo.shmaddr);
223 shmctl(xm_dt->shminfo.shmid, IPC_RMID, 0);
224
225 xm_dt->shminfo.shmid = -1;
226 xm_dt->shminfo.shmaddr = (char *) -1;
227 }
228 else
229 #endif
230 FREE(xm_dt->data);
231 }
232
233 FREE(xm_dt);
234 }
235
236
237 /**
238 * Display/copy the image in the surface into the X window specified
239 * by the XMesaBuffer.
240 */
241 void
242 xlib_sw_display(struct xmesa_buffer *xm_buffer,
243 struct sw_displaytarget *dt)
244 {
245 XImage *ximage;
246 struct xm_displaytarget *xm_dt = xm_displaytarget(dt);
247 static boolean no_swap = 0;
248 static boolean firsttime = 1;
249
250 if (firsttime) {
251 no_swap = getenv("SP_NO_RAST") != NULL;
252 firsttime = 0;
253 }
254
255 if (no_swap)
256 return;
257
258 #ifdef USE_XSHM
259 if (xm_dt->shm)
260 {
261 if (xm_dt->tempImage == NULL)
262 {
263 assert(util_format_get_blockwidth(xm_dt->format) == 1);
264 assert(util_format_get_blockheight(xm_dt->format) == 1);
265 alloc_shm_ximage(xm_dt, xm_buffer,
266 xm_dt->stride / util_format_get_blocksize(xm_dt->format),
267 xm_dt->height);
268 }
269
270 ximage = xm_dt->tempImage;
271 ximage->data = xm_dt->data;
272
273 /* _debug_printf("XSHM\n"); */
274 XShmPutImage(xm_buffer->xm_visual->display, xm_buffer->drawable, xm_buffer->gc,
275 ximage, 0, 0, 0, 0, xm_dt->width, xm_dt->height, False);
276 }
277 else
278 #endif
279 {
280 /* display image in Window */
281 ximage = xm_dt->tempImage;
282 ximage->data = xm_dt->data;
283
284 /* check that the XImage has been previously initialized */
285 assert(ximage->format);
286 assert(ximage->bitmap_unit);
287
288 /* update XImage's fields */
289 ximage->width = xm_dt->width;
290 ximage->height = xm_dt->height;
291 ximage->bytes_per_line = xm_dt->stride;
292
293 /* _debug_printf("XPUT\n"); */
294 XPutImage(xm_buffer->xm_visual->display, xm_buffer->drawable, xm_buffer->gc,
295 ximage, 0, 0, 0, 0, xm_dt->width, xm_dt->height);
296 }
297 }
298
299 /**
300 * Display/copy the image in the surface into the X window specified
301 * by the XMesaBuffer.
302 */
303 static void
304 xm_displaytarget_display(struct sw_winsys *ws,
305 struct sw_displaytarget *dt,
306 void *context_private)
307 {
308 XMesaContext xmctx = (XMesaContext) context_private;
309 struct xmesa_buffer *xm_buffer = xmctx->xm_buffer;
310 xm_sw_display(xm_buffer, dt);
311 }
312
313
314 static struct sw_displaytarget *
315 xm_displaytarget_create(struct sw_winsys *winsys,
316 enum pipe_format format,
317 unsigned width, unsigned height,
318 unsigned alignment,
319 unsigned *stride)
320 {
321 struct xm_displaytarget *xm_dt = CALLOC_STRUCT(xm_displaytarget);
322 unsigned nblocksy, size;
323
324 xm_dt = CALLOC_STRUCT(xm_displaytarget);
325 if(!xm_dt)
326 goto no_xm_dt;
327
328 xm_dt->format = format;
329 xm_dt->width = width;
330 xm_dt->height = height;
331
332 nblocksy = util_format_get_nblocksy(format, height);
333 xm_dt->stride = align(util_format_get_stride(format, width), alignment);
334 size = xm_dt->stride * nblocksy;
335
336 #ifdef USE_XSHM
337 if (!debug_get_bool_option("XLIB_NO_SHM", FALSE))
338 {
339 xm_dt->shminfo.shmid = -1;
340 xm_dt->shminfo.shmaddr = (char *) -1;
341 xm_dt->shm = TRUE;
342
343 xm_dt->data = alloc_shm(xm_dt, size);
344 if(!xm_dt->data)
345 goto no_data;
346 }
347 #endif
348
349 if(!xm_dt->data) {
350 xm_dt->data = align_malloc(size, alignment);
351 if(!xm_dt->data)
352 goto no_data;
353 }
354
355 *stride = xm_dt->stride;
356 return (struct sw_displaytarget *)xm_dt;
357
358 no_data:
359 FREE(xm_dt);
360 no_xm_dt:
361 return NULL;
362 }
363
364
365 static void
366 xm_destroy( struct sw_winsys *ws )
367 {
368 FREE(ws);
369 }
370
371
372 struct sw_winsys *
373 xlib_create_sw_winsys( void )
374 {
375 struct xmesa_sw_winsys *ws;
376
377 ws = CALLOC_STRUCT(xmesa_sw_winsys);
378 if (!ws)
379 return NULL;
380
381 ws->base.destroy = xm_destroy;
382
383 ws->base.is_displaytarget_format_supported = xm_is_displaytarget_format_supported;
384
385 ws->base.displaytarget_create = xm_displaytarget_create;
386 ws->base.displaytarget_map = xm_displaytarget_map;
387 ws->base.displaytarget_unmap = xm_displaytarget_unmap;
388 ws->base.displaytarget_destroy = xm_displaytarget_destroy;
389
390 ws->base.displaytarget_display = xm_displaytarget_display;
391
392 return &ws->base;
393 }
394