Merge commit 'origin/gallium-0.2' into gallium-xlib-rework
[mesa.git] / src / gallium / winsys / xlib / xlib_cell.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 #include "xlib.h"
36
37 #ifdef GALLIUM_CELL
38
39 #include "xm_api.h"
40
41 #undef ASSERT
42 #undef Elements
43
44 #include "pipe/p_winsys.h"
45 #include "pipe/p_format.h"
46 #include "pipe/p_context.h"
47 #include "pipe/p_inlines.h"
48 #include "util/u_math.h"
49 #include "util/u_memory.h"
50
51 #include "cell/ppu/cell_context.h"
52 #include "cell/ppu/cell_screen.h"
53 #include "cell/ppu/cell_winsys.h"
54
55
56 /**
57 * Subclass of pipe_buffer for Xlib winsys.
58 * Low-level OS/window system memory buffer
59 */
60 struct xm_buffer
61 {
62 struct pipe_buffer base;
63 boolean userBuffer; /** Is this a user-space buffer? */
64 void *data;
65 void *mapped;
66
67 XImage *tempImage;
68 int shm;
69 };
70
71
72 /**
73 * Subclass of pipe_winsys for Xlib winsys
74 */
75 struct xmesa_pipe_winsys
76 {
77 struct pipe_winsys base;
78 };
79
80
81
82 /** Cast wrapper */
83 static INLINE struct xm_buffer *
84 xm_buffer( struct pipe_buffer *buf )
85 {
86 return (struct xm_buffer *)buf;
87 }
88
89
90 /* Most callbacks map direcly onto dri_bufmgr operations:
91 */
92 static void *
93 xm_buffer_map(struct pipe_winsys *pws, struct pipe_buffer *buf,
94 unsigned flags)
95 {
96 struct xm_buffer *xm_buf = xm_buffer(buf);
97 xm_buf->mapped = xm_buf->data;
98 return xm_buf->mapped;
99 }
100
101 static void
102 xm_buffer_unmap(struct pipe_winsys *pws, struct pipe_buffer *buf)
103 {
104 struct xm_buffer *xm_buf = xm_buffer(buf);
105 xm_buf->mapped = NULL;
106 }
107
108 static void
109 xm_buffer_destroy(struct pipe_winsys *pws,
110 struct pipe_buffer *buf)
111 {
112 struct xm_buffer *oldBuf = xm_buffer(buf);
113
114 if (oldBuf->data) {
115 {
116 if (!oldBuf->userBuffer) {
117 align_free(oldBuf->data);
118 }
119 }
120
121 oldBuf->data = NULL;
122 }
123
124 free(oldBuf);
125 }
126
127
128 /**
129 * For Cell. Basically, rearrange the pixels/quads from this layout:
130 * +--+--+--+--+
131 * |p0|p1|p2|p3|....
132 * +--+--+--+--+
133 *
134 * to this layout:
135 * +--+--+
136 * |p0|p1|....
137 * +--+--+
138 * |p2|p3|
139 * +--+--+
140 */
141 static void
142 twiddle_tile(const uint *tileIn, uint *tileOut)
143 {
144 int y, x;
145
146 for (y = 0; y < TILE_SIZE; y+=2) {
147 for (x = 0; x < TILE_SIZE; x+=2) {
148 int k = 4 * (y/2 * TILE_SIZE/2 + x/2);
149 tileOut[y * TILE_SIZE + (x + 0)] = tileIn[k];
150 tileOut[y * TILE_SIZE + (x + 1)] = tileIn[k+1];
151 tileOut[(y + 1) * TILE_SIZE + (x + 0)] = tileIn[k+2];
152 tileOut[(y + 1) * TILE_SIZE + (x + 1)] = tileIn[k+3];
153 }
154 }
155 }
156
157
158
159 /**
160 * Display a surface that's in a tiled configuration. That is, all the
161 * pixels for a TILE_SIZExTILE_SIZE block are contiguous in memory.
162 */
163 static void
164 xlib_cell_display_surface(struct xmesa_buffer *b, struct pipe_surface *surf)
165 {
166 XImage *ximage;
167 struct xm_buffer *xm_buf = xm_buffer(surf->buffer);
168 const uint tilesPerRow = (surf->width + TILE_SIZE - 1) / TILE_SIZE;
169 uint x, y;
170
171 ximage = b->tempImage;
172
173 /* check that the XImage has been previously initialized */
174 assert(ximage->format);
175 assert(ximage->bitmap_unit);
176
177 /* update XImage's fields */
178 ximage->width = TILE_SIZE;
179 ximage->height = TILE_SIZE;
180 ximage->bytes_per_line = TILE_SIZE * 4;
181
182 for (y = 0; y < surf->height; y += TILE_SIZE) {
183 for (x = 0; x < surf->width; x += TILE_SIZE) {
184 uint tmpTile[TILE_SIZE * TILE_SIZE];
185 int tx = x / TILE_SIZE;
186 int ty = y / TILE_SIZE;
187 int offset = ty * tilesPerRow + tx;
188 int w = TILE_SIZE;
189 int h = TILE_SIZE;
190
191 if (y + h > surf->height)
192 h = surf->height - y;
193 if (x + w > surf->width)
194 w = surf->width - x;
195
196 /* offset in pixels */
197 offset *= TILE_SIZE * TILE_SIZE;
198
199 /* twiddle from ximage buffer to temp tile */
200 twiddle_tile((uint *) xm_buf->data + offset, tmpTile);
201 /* display temp tile data */
202 ximage->data = (char *) tmpTile;
203 XPutImage(b->xm_visual->display, b->drawable, b->gc,
204 ximage, 0, 0, x, y, w, h);
205 }
206 }
207 }
208
209
210
211
212
213 static void
214 xm_flush_frontbuffer(struct pipe_winsys *pws,
215 struct pipe_surface *surf,
216 void *context_private)
217 {
218 /*
219 * The front color buffer is actually just another XImage buffer.
220 * This function copies that XImage to the actual X Window.
221 */
222 XMesaContext xmctx = (XMesaContext) context_private;
223 xlib_cell_display_surface(xmctx->xm_buffer, surf);
224 }
225
226
227
228 static const char *
229 xm_get_name(struct pipe_winsys *pws)
230 {
231 return "Xlib/Cell";
232 }
233
234
235 static struct pipe_buffer *
236 xm_buffer_create(struct pipe_winsys *pws,
237 unsigned alignment,
238 unsigned usage,
239 unsigned size)
240 {
241 struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer);
242
243 buffer->base.refcount = 1;
244 buffer->base.alignment = alignment;
245 buffer->base.usage = usage;
246 buffer->base.size = size;
247
248
249 if (buffer->data == NULL) {
250 buffer->shm = 0;
251
252 /* align to 16-byte multiple for Cell */
253 buffer->data = align_malloc(size, max(alignment, 16));
254 }
255
256 return &buffer->base;
257 }
258
259
260 /**
261 * Create buffer which wraps user-space data.
262 */
263 static struct pipe_buffer *
264 xm_user_buffer_create(struct pipe_winsys *pws, void *ptr, unsigned bytes)
265 {
266 struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer);
267 buffer->base.refcount = 1;
268 buffer->base.size = bytes;
269 buffer->userBuffer = TRUE;
270 buffer->data = ptr;
271 buffer->shm = 0;
272
273 return &buffer->base;
274 }
275
276
277
278 /**
279 * Round n up to next multiple.
280 */
281 static INLINE unsigned
282 round_up(unsigned n, unsigned multiple)
283 {
284 return (n + multiple - 1) & ~(multiple - 1);
285 }
286
287 static int
288 xm_surface_alloc_storage(struct pipe_winsys *winsys,
289 struct pipe_surface *surf,
290 unsigned width, unsigned height,
291 enum pipe_format format,
292 unsigned flags,
293 unsigned tex_usage)
294 {
295 const unsigned alignment = 64;
296
297 surf->width = width;
298 surf->height = height;
299 surf->format = format;
300 pf_get_block(format, &surf->block);
301 surf->nblocksx = pf_get_nblocksx(&surf->block, width);
302 surf->nblocksy = pf_get_nblocksy(&surf->block, height);
303 surf->stride = round_up(surf->nblocksx * surf->block.size, alignment);
304 surf->usage = flags;
305
306 assert(!surf->buffer);
307 surf->buffer = winsys->buffer_create(winsys, alignment,
308 PIPE_BUFFER_USAGE_PIXEL,
309 /* XXX a bit of a hack */
310 surf->stride * round_up(surf->nblocksy, TILE_SIZE));
311
312 if(!surf->buffer)
313 return -1;
314
315 return 0;
316 }
317
318
319 /**
320 * Called via winsys->surface_alloc() to create new surfaces.
321 */
322 static struct pipe_surface *
323 xm_surface_alloc(struct pipe_winsys *ws)
324 {
325 struct pipe_surface *surface = CALLOC_STRUCT(pipe_surface);
326
327 assert(ws);
328
329 surface->refcount = 1;
330 surface->winsys = ws;
331
332 return surface;
333 }
334
335
336
337 static void
338 xm_surface_release(struct pipe_winsys *winsys, struct pipe_surface **s)
339 {
340 struct pipe_surface *surf = *s;
341 assert(!surf->texture);
342 surf->refcount--;
343 if (surf->refcount == 0) {
344 if (surf->buffer)
345 winsys_buffer_reference(winsys, &surf->buffer, NULL);
346 free(surf);
347 }
348 *s = NULL;
349 }
350
351
352 /*
353 * Fence functions - basically nothing to do, as we don't create any actual
354 * fence objects.
355 */
356
357 static void
358 xm_fence_reference(struct pipe_winsys *sws, struct pipe_fence_handle **ptr,
359 struct pipe_fence_handle *fence)
360 {
361 }
362
363
364 static int
365 xm_fence_signalled(struct pipe_winsys *sws, struct pipe_fence_handle *fence,
366 unsigned flag)
367 {
368 return 0;
369 }
370
371
372 static int
373 xm_fence_finish(struct pipe_winsys *sws, struct pipe_fence_handle *fence,
374 unsigned flag)
375 {
376 return 0;
377 }
378
379
380
381 static struct pipe_winsys *
382 xlib_create_cell_winsys( void )
383 {
384 static struct xmesa_pipe_winsys *ws = NULL;
385
386 if (!ws) {
387 ws = CALLOC_STRUCT(xmesa_pipe_winsys);
388
389 /* Fill in this struct with callbacks that pipe will need to
390 * communicate with the window system, buffer manager, etc.
391 */
392 ws->base.buffer_create = xm_buffer_create;
393 ws->base.user_buffer_create = xm_user_buffer_create;
394 ws->base.buffer_map = xm_buffer_map;
395 ws->base.buffer_unmap = xm_buffer_unmap;
396 ws->base.buffer_destroy = xm_buffer_destroy;
397
398 ws->base.surface_alloc = xm_surface_alloc;
399 ws->base.surface_alloc_storage = xm_surface_alloc_storage;
400 ws->base.surface_release = xm_surface_release;
401
402 ws->base.fence_reference = xm_fence_reference;
403 ws->base.fence_signalled = xm_fence_signalled;
404 ws->base.fence_finish = xm_fence_finish;
405
406 ws->base.flush_frontbuffer = xm_flush_frontbuffer;
407 ws->base.get_name = xm_get_name;
408 }
409
410 return &ws->base;
411 }
412
413
414 static struct pipe_screen *
415 xlib_create_cell_screen( struct pipe_winsys *pws )
416 {
417 struct pipe_winsys *winsys;
418 struct pipe_screen *screen;
419
420 winsys = xlib_create_cell_winsys();
421 if (winsys == NULL)
422 return NULL;
423
424 screen = cell_create_screen(winsys);
425 if (screen == NULL)
426 goto fail;
427
428 return screen;
429
430 fail:
431 if (winsys)
432 winsys->destroy( winsys );
433
434 return NULL;
435 }
436
437
438 static struct pipe_context *
439 xlib_create_cell_context( struct pipe_screen *screen,
440 void *priv )
441 {
442 struct pipe_context *pipe;
443
444
445 /* This takes a cell_winsys pointer, but probably that should be
446 * created and stored at screen creation, not context creation.
447 *
448 * The actual cell_winsys value isn't used for anything, so just
449 * passing NULL for now.
450 */
451 pipe = cell_create_context( screen, NULL);
452 if (pipe == NULL)
453 goto fail;
454
455 pipe->priv = priv;
456
457 return pipe;
458
459 fail:
460 return NULL;
461 }
462
463 struct xm_driver xlib_cell_driver =
464 {
465 .create_pipe_screen = xlib_create_cell_screen,
466 .create_pipe_context = xlib_create_cell_context,
467 .display_surface = xlib_cell_display_surface,
468 };
469
470 #else
471
472 struct xm_driver xlib_cell_driver =
473 {
474 .create_pipe_screen = NULL,
475 .create_pipe_context = NULL,
476 .display_surface = NULL,
477 };
478
479 #endif