Merge branch 'gallium-wgl-rework' into gallium-0.2
[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/internal/p_winsys_screen.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 struct pipe_buffer *
288 xm_surface_buffer_create(struct pipe_winsys *winsys,
289 unsigned width, unsigned height,
290 enum pipe_format format,
291 unsigned usage,
292 unsigned *stride)
293 {
294 const unsigned alignment = 64;
295 struct pipe_format_block block;
296 unsigned nblocksx, nblocksy;
297
298 pf_get_block(format, &block);
299 nblocksx = pf_get_nblocksx(&block, width);
300 nblocksy = pf_get_nblocksy(&block, height);
301 *stride = round_up(nblocksx * block.size, alignment);
302
303 return winsys->buffer_create(winsys, alignment,
304 usage,
305 /* XXX a bit of a hack */
306 *stride * round_up(nblocksy, TILE_SIZE));
307 }
308
309
310 /*
311 * Fence functions - basically nothing to do, as we don't create any actual
312 * fence objects.
313 */
314
315 static void
316 xm_fence_reference(struct pipe_winsys *sws, struct pipe_fence_handle **ptr,
317 struct pipe_fence_handle *fence)
318 {
319 }
320
321
322 static int
323 xm_fence_signalled(struct pipe_winsys *sws, struct pipe_fence_handle *fence,
324 unsigned flag)
325 {
326 return 0;
327 }
328
329
330 static int
331 xm_fence_finish(struct pipe_winsys *sws, struct pipe_fence_handle *fence,
332 unsigned flag)
333 {
334 return 0;
335 }
336
337
338
339 static struct pipe_winsys *
340 xlib_create_cell_winsys( void )
341 {
342 static struct xmesa_pipe_winsys *ws = NULL;
343
344 if (!ws) {
345 ws = CALLOC_STRUCT(xmesa_pipe_winsys);
346
347 /* Fill in this struct with callbacks that pipe will need to
348 * communicate with the window system, buffer manager, etc.
349 */
350 ws->base.buffer_create = xm_buffer_create;
351 ws->base.user_buffer_create = xm_user_buffer_create;
352 ws->base.buffer_map = xm_buffer_map;
353 ws->base.buffer_unmap = xm_buffer_unmap;
354 ws->base.buffer_destroy = xm_buffer_destroy;
355
356 ws->base.surface_buffer_create = xm_surface_buffer_create;
357
358 ws->base.fence_reference = xm_fence_reference;
359 ws->base.fence_signalled = xm_fence_signalled;
360 ws->base.fence_finish = xm_fence_finish;
361
362 ws->base.flush_frontbuffer = xm_flush_frontbuffer;
363 ws->base.get_name = xm_get_name;
364 }
365
366 return &ws->base;
367 }
368
369
370 static struct pipe_screen *
371 xlib_create_cell_screen( struct pipe_winsys *pws )
372 {
373 struct pipe_winsys *winsys;
374 struct pipe_screen *screen;
375
376 winsys = xlib_create_cell_winsys();
377 if (winsys == NULL)
378 return NULL;
379
380 screen = cell_create_screen(winsys);
381 if (screen == NULL)
382 goto fail;
383
384 return screen;
385
386 fail:
387 if (winsys)
388 winsys->destroy( winsys );
389
390 return NULL;
391 }
392
393
394 static struct pipe_context *
395 xlib_create_cell_context( struct pipe_screen *screen,
396 void *priv )
397 {
398 struct pipe_context *pipe;
399
400
401 /* This takes a cell_winsys pointer, but probably that should be
402 * created and stored at screen creation, not context creation.
403 *
404 * The actual cell_winsys value isn't used for anything, so just
405 * passing NULL for now.
406 */
407 pipe = cell_create_context( screen, NULL);
408 if (pipe == NULL)
409 goto fail;
410
411 pipe->priv = priv;
412
413 return pipe;
414
415 fail:
416 return NULL;
417 }
418
419 struct xm_driver xlib_cell_driver =
420 {
421 .create_pipe_screen = xlib_create_cell_screen,
422 .create_pipe_context = xlib_create_cell_context,
423 .display_surface = xlib_cell_display_surface,
424 };
425
426 #else
427
428 struct xm_driver xlib_cell_driver =
429 {
430 .create_pipe_screen = NULL,
431 .create_pipe_context = NULL,
432 .display_surface = NULL,
433 };
434
435 #endif