Code reorganization: move files into their places.
[mesa.git] / src / gallium / winsys / xlib / xm_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 #include "glxheader.h"
37 #include "xmesaP.h"
38
39 #include "pipe/p_winsys.h"
40 #include "pipe/p_format.h"
41 #include "pipe/p_context.h"
42 #include "pipe/p_util.h"
43 #include "pipe/p_inlines.h"
44 #include "pipe/softpipe/sp_winsys.h"
45
46 #ifdef GALLIUM_CELL
47 #include "pipe/cell/ppu/cell_context.h"
48 #include "pipe/cell/ppu/cell_winsys.h"
49 #else
50 #define TILE_SIZE 32 /* avoid compilation errors */
51 #endif
52
53 #include "xm_winsys_aub.h"
54
55
56 /**
57 * Low-level OS/window system memory buffer
58 */
59 struct xm_buffer
60 {
61 struct pipe_buffer base;
62 boolean userBuffer; /** Is this a user-space buffer? */
63 void *data;
64 void *mapped;
65 };
66
67
68 struct xmesa_surface
69 {
70 struct pipe_surface surface;
71
72 int tileSize;
73 };
74
75
76 /**
77 * Derived from softpipe_winsys.
78 * We just need one extra field which indicates the pixel format to use for
79 * drawing surfaces so that we're compatible with the XVisual/window format.
80 */
81 struct xmesa_softpipe_winsys
82 {
83 struct softpipe_winsys spws;
84 enum pipe_format pixelformat;
85 };
86
87
88
89 /** Cast wrapper */
90 static INLINE struct xmesa_surface *
91 xmesa_surface(struct pipe_surface *ps)
92 {
93 // assert(0);
94 return (struct xmesa_surface *) ps;
95 }
96
97 /** cast wrapper */
98 static INLINE struct xmesa_softpipe_winsys *
99 xmesa_softpipe_winsys(struct softpipe_winsys *spws)
100 {
101 return (struct xmesa_softpipe_winsys *) spws;
102 }
103
104 /**
105 * Turn the softpipe opaque buffer pointer into a dri_bufmgr opaque
106 * buffer pointer...
107 */
108 static INLINE struct xm_buffer *
109 xm_buffer( struct pipe_buffer *buf )
110 {
111 return (struct xm_buffer *)buf;
112 }
113
114
115
116 /* Most callbacks map direcly onto dri_bufmgr operations:
117 */
118 static void *
119 xm_buffer_map(struct pipe_winsys *pws, struct pipe_buffer *buf,
120 unsigned flags)
121 {
122 struct xm_buffer *xm_buf = xm_buffer(buf);
123 xm_buf->mapped = xm_buf->data;
124 return xm_buf->mapped;
125 }
126
127 static void
128 xm_buffer_unmap(struct pipe_winsys *pws, struct pipe_buffer *buf)
129 {
130 struct xm_buffer *xm_buf = xm_buffer(buf);
131 xm_buf->mapped = NULL;
132 }
133
134 static void
135 xm_buffer_destroy(struct pipe_winsys *pws,
136 struct pipe_buffer *buf)
137 {
138 struct xm_buffer *oldBuf = xm_buffer(buf);
139
140 if (oldBuf->data) {
141 if (!oldBuf->userBuffer)
142 align_free(oldBuf->data);
143 oldBuf->data = NULL;
144 }
145
146 free(oldBuf);
147 }
148
149
150 /**
151 * Display a surface that's in a tiled configuration. That is, all the
152 * pixels for a TILE_SIZExTILE_SIZE block are contiguous in memory.
153 */
154 static void
155 xmesa_display_surface_tiled(XMesaBuffer b, const struct pipe_surface *surf)
156 {
157 XImage *ximage = b->tempImage;
158 struct xm_buffer *xm_buf = xm_buffer(surf->buffer);
159 const uint tilesPerRow = (surf->width + TILE_SIZE - 1) / TILE_SIZE;
160 uint x, y;
161
162 /* check that the XImage has been previously initialized */
163 assert(ximage->format);
164 assert(ximage->bitmap_unit);
165
166 /* update XImage's fields */
167 ximage->width = TILE_SIZE;
168 ximage->height = TILE_SIZE;
169 ximage->bytes_per_line = TILE_SIZE * 4;
170
171 for (y = 0; y < surf->height; y += TILE_SIZE) {
172 for (x = 0; x < surf->width; x += TILE_SIZE) {
173 int dx = x;
174 int dy = y;
175 int tx = x / TILE_SIZE;
176 int ty = y / TILE_SIZE;
177 int offset = ty * tilesPerRow + tx;
178
179 offset *= 4 * TILE_SIZE * TILE_SIZE;
180
181 ximage->data = (char *) xm_buf->data + offset;
182
183 XPutImage(b->xm_visual->display, b->drawable, b->gc,
184 ximage, 0, 0, dx, dy, TILE_SIZE, TILE_SIZE);
185 }
186 }
187 }
188
189
190 /**
191 * Display/copy the image in the surface into the X window specified
192 * by the XMesaBuffer.
193 */
194 void
195 xmesa_display_surface(XMesaBuffer b, const struct pipe_surface *surf)
196 {
197 XImage *ximage = b->tempImage;
198 struct xm_buffer *xm_buf = xm_buffer(surf->buffer);
199 const struct xmesa_surface *xm_surf
200 = xmesa_surface((struct pipe_surface *) surf);
201
202 if (xm_surf->tileSize) {
203 xmesa_display_surface_tiled(b, surf);
204 return;
205 }
206
207 /* check that the XImage has been previously initialized */
208 assert(ximage->format);
209 assert(ximage->bitmap_unit);
210
211 /* update XImage's fields */
212 ximage->width = surf->width;
213 ximage->height = surf->height;
214 ximage->bytes_per_line = surf->pitch * (ximage->bits_per_pixel / 8);
215 ximage->data = xm_buf->data;
216
217 /* display image in Window */
218 XPutImage(b->xm_visual->display, b->drawable, b->gc,
219 ximage, 0, 0, 0, 0, surf->width, surf->height);
220 }
221
222
223 static void
224 xm_flush_frontbuffer(struct pipe_winsys *pws,
225 struct pipe_surface *surf,
226 void *context_private)
227 {
228 /* The Xlib driver's front color surfaces are actually X Windows so
229 * this flush is a no-op.
230 * If we instead did front buffer rendering to a temporary XImage,
231 * this would be the place to copy the Ximage to the on-screen Window.
232 */
233 XMesaContext xmctx = (XMesaContext) context_private;
234 xmesa_display_surface(xmctx->xm_buffer, surf);
235 }
236
237
238
239 static void
240 xm_printf(struct pipe_winsys *pws, const char *fmtString, ...)
241 {
242 va_list args;
243 va_start( args, fmtString );
244 vfprintf(stderr, fmtString, args);
245 va_end( args );
246 }
247
248
249 static const char *
250 xm_get_name(struct pipe_winsys *pws)
251 {
252 return "Xlib";
253 }
254
255
256 static struct pipe_buffer *
257 xm_buffer_create(struct pipe_winsys *pws,
258 unsigned alignment,
259 unsigned usage,
260 unsigned size)
261 {
262 struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer);
263 buffer->base.refcount = 1;
264 buffer->base.alignment = alignment;
265 buffer->base.usage = usage;
266 buffer->base.size = size;
267
268 /* align to 16-byte multiple for Cell */
269 buffer->data = align_malloc(size, max(alignment, 16));
270
271 return &buffer->base;
272 }
273
274
275 /**
276 * Create buffer which wraps user-space data.
277 */
278 static struct pipe_buffer *
279 xm_user_buffer_create(struct pipe_winsys *pws, void *ptr, unsigned bytes)
280 {
281 struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer);
282 buffer->base.refcount = 1;
283 buffer->base.size = bytes;
284 buffer->userBuffer = TRUE;
285 buffer->data = ptr;
286
287 return &buffer->base;
288 }
289
290
291
292 /**
293 * Round n up to next multiple.
294 */
295 static INLINE unsigned
296 round_up(unsigned n, unsigned multiple)
297 {
298 return (n + multiple - 1) & ~(multiple - 1);
299 }
300
301 static int
302 xm_surface_alloc_storage(struct pipe_winsys *winsys,
303 struct pipe_surface *surf,
304 unsigned width, unsigned height,
305 enum pipe_format format,
306 unsigned flags)
307 {
308 const unsigned alignment = 64;
309
310 surf->width = width;
311 surf->height = height;
312 surf->format = format;
313 surf->cpp = pf_get_size(format);
314 surf->pitch = round_up(width, alignment / surf->cpp);
315
316 #ifdef GALLIUM_CELL /* XXX a bit of a hack */
317 height = round_up(height, TILE_SIZE);
318 #endif
319
320 assert(!surf->buffer);
321 surf->buffer = winsys->buffer_create(winsys, alignment,
322 PIPE_BUFFER_USAGE_PIXEL,
323 surf->pitch * surf->cpp * height);
324 if(!surf->buffer)
325 return -1;
326
327 return 0;
328 }
329
330
331 /**
332 * Called via pipe->surface_alloc() to create new surfaces (textures,
333 * renderbuffers, etc.
334 */
335 static struct pipe_surface *
336 xm_surface_alloc(struct pipe_winsys *ws)
337 {
338 struct xmesa_surface *xms = CALLOC_STRUCT(xmesa_surface);
339
340 assert(ws);
341
342 xms->surface.refcount = 1;
343 xms->surface.winsys = ws;
344
345 #ifdef GALLIUM_CELL
346 if (!getenv("GALLIUM_NOCELL")) {
347 xms->tileSize = 32; /** probably temporary */
348 }
349 #endif
350
351 return &xms->surface;
352 }
353
354
355
356 static void
357 xm_surface_release(struct pipe_winsys *winsys, struct pipe_surface **s)
358 {
359 struct pipe_surface *surf = *s;
360 surf->refcount--;
361 if (surf->refcount == 0) {
362 if (surf->buffer)
363 pipe_buffer_reference(winsys, &surf->buffer, NULL);
364 free(surf);
365 }
366 *s = NULL;
367 }
368
369
370
371 /**
372 * Return pointer to a pipe_winsys object.
373 * For Xlib, this is a singleton object.
374 * Nothing special for the Xlib driver so no subclassing or anything.
375 */
376 struct pipe_winsys *
377 xmesa_get_pipe_winsys_aub(void)
378 {
379 static struct pipe_winsys *ws = NULL;
380
381 if (!ws && getenv("XM_AUB")) {
382 ws = xmesa_create_pipe_winsys_aub();
383 }
384 else if (!ws) {
385 ws = CALLOC_STRUCT(pipe_winsys);
386
387 /* Fill in this struct with callbacks that pipe will need to
388 * communicate with the window system, buffer manager, etc.
389 */
390 ws->buffer_create = xm_buffer_create;
391 ws->user_buffer_create = xm_user_buffer_create;
392 ws->buffer_map = xm_buffer_map;
393 ws->buffer_unmap = xm_buffer_unmap;
394 ws->buffer_destroy = xm_buffer_destroy;
395
396 ws->surface_alloc = xm_surface_alloc;
397 ws->surface_alloc_storage = xm_surface_alloc_storage;
398 ws->surface_release = xm_surface_release;
399
400 ws->flush_frontbuffer = xm_flush_frontbuffer;
401 ws->printf = xm_printf;
402 ws->get_name = xm_get_name;
403 }
404
405 return ws;
406 }
407
408
409 /**
410 * Called via softpipe_winsys->is_format_supported().
411 * This function is only called to test formats for front/back color surfaces.
412 * The winsys being queried will have been created at glXCreateContext
413 * time, with a pixel format corresponding to the context's visual.
414 */
415 static boolean
416 xmesa_is_format_supported(struct softpipe_winsys *sws,
417 enum pipe_format format)
418 {
419 struct xmesa_softpipe_winsys *xmws = xmesa_softpipe_winsys(sws);
420 return (format == xmws->pixelformat);
421 }
422
423
424 /**
425 * Return pointer to a softpipe_winsys object.
426 */
427 static struct softpipe_winsys *
428 xmesa_get_softpipe_winsys(uint pixelformat)
429 {
430 struct xmesa_softpipe_winsys *xmws
431 = CALLOC_STRUCT(xmesa_softpipe_winsys);
432 if (!xmws)
433 return NULL;
434
435 xmws->spws.is_format_supported = xmesa_is_format_supported;
436 xmws->pixelformat = pixelformat;
437
438 return &xmws->spws;
439 }
440
441
442 struct pipe_context *
443 xmesa_create_pipe_context(XMesaContext xmesa, uint pixelformat)
444 {
445 struct pipe_winsys *pws = xmesa_get_pipe_winsys_aub();
446 struct pipe_context *pipe;
447
448 #ifdef GALLIUM_CELL
449 if (!getenv("GALLIUM_NOCELL")) {
450 struct cell_winsys *cws = cell_get_winsys(pixelformat);
451 pipe = cell_create_context(pws, cws);
452 if (pipe)
453 pipe->priv = xmesa;
454 return pipe;
455 }
456 else
457 #endif
458 {
459 struct softpipe_winsys *spws = xmesa_get_softpipe_winsys(pixelformat);
460 pipe = softpipe_create( pws, spws );
461 if (pipe)
462 pipe->priv = xmesa;
463
464 return pipe;
465 }
466 }