6d746ebe0ae4f20c630d0cdded7117e907fd9d52
[profile/ivi/mesa.git] / src / gallium / drivers / cell / ppu / cell_texture.c
1 /**************************************************************************
2  * 
3  * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
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 above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  * 
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  * 
26  **************************************************************************/
27  /*
28   * Authors:
29   *   Keith Whitwell <keith@tungstengraphics.com>
30   *   Michel Dänzer <michel@tungstengraphics.com>
31   *   Brian Paul
32   */
33
34 #include "pipe/p_context.h"
35 #include "pipe/p_defines.h"
36 #include "util/u_inlines.h"
37
38 #include "util/u_format.h"
39 #include "util/u_math.h"
40 #include "util/u_memory.h"
41
42 #include "cell_context.h"
43 #include "cell_screen.h"
44 #include "cell_state.h"
45 #include "cell_texture.h"
46
47 #include "state_tracker/sw_winsys.h"
48
49
50
51 static boolean
52 cell_texture_layout(struct pipe_screen *screen, 
53                     struct cell_texture *ct)
54 {
55    struct pipe_texture *pt = &ct->base;
56    unsigned level;
57    unsigned width = pt->width0;
58    unsigned height = pt->height0;
59    unsigned depth = pt->depth0;
60
61    ct->buffer_size = 0;
62
63    for (level = 0; level <= pt->last_level; level++) {
64       unsigned size;
65       unsigned w_tile, h_tile;
66
67       assert(level < CELL_MAX_TEXTURE_LEVELS);
68
69       /* width, height, rounded up to tile size */
70       w_tile = align(width, TILE_SIZE);
71       h_tile = align(height, TILE_SIZE);
72
73       ct->stride[level] = util_format_get_stride(pt->format, w_tile);
74
75       ct->level_offset[level] = ct->buffer_size;
76
77       size = ct->stride[level] * util_format_get_nblocksy(pt->format, h_tile);
78       if (pt->target == PIPE_TEXTURE_CUBE)
79          size *= 6;
80       else
81          size *= depth;
82
83       ct->buffer_size += size;
84
85       width = u_minify(width, 1);
86       height = u_minify(height, 1);
87       depth = u_minify(depth, 1);
88    }
89
90    ct->data = align_malloc(ct->buffer_size, 16);
91  
92    return ct->data != NULL;
93 }
94
95
96 /**
97  * Texture layout for simple color buffers.
98  */
99 static boolean
100 cell_displaytarget_layout(struct pipe_screen *screen,
101                           struct cell_texture * ct)
102 {
103    struct sw_winsys *winsys = cell_screen(screen)->winsys;
104
105    /* Round up the surface size to a multiple of the tile size?
106     */
107    ct->dt = winsys->displaytarget_create(winsys,
108                                           ct->base.tex_usage,
109                                           ct->base.format,
110                                           ct->base.width0, 
111                                           ct->base.height0,
112                                           16,
113                                           &ct->dt_stride );
114
115    return ct->dt != NULL;
116 }
117
118 static struct pipe_texture *
119 cell_texture_create(struct pipe_screen *screen,
120                     const struct pipe_texture *templat)
121 {
122    struct cell_texture *ct = CALLOC_STRUCT(cell_texture);
123    if (!ct)
124       return NULL;
125
126    ct->base = *templat;
127    pipe_reference_init(&ct->base.reference, 1);
128    ct->base.screen = screen;
129
130    /* Create both a displaytarget (linear) and regular texture
131     * (twiddled).  Convert twiddled->linear at flush_frontbuffer time.
132     */
133    if (ct->base.tex_usage & (PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
134                              PIPE_TEXTURE_USAGE_SCANOUT |
135                              PIPE_TEXTURE_USAGE_SHARED)) {
136       if (!cell_displaytarget_layout(screen, ct))
137          goto fail;
138    }
139
140    if (!cell_texture_layout(screen, ct))
141       goto fail;
142
143    return &ct->base;
144
145 fail:
146    if (ct->dt) {
147       struct sw_winsys *winsys = cell_screen(screen)->winsys;
148       winsys->displaytarget_destroy(winsys, ct->dt);
149    }
150
151    FREE(ct);
152
153    return NULL;
154 }
155
156
157 static void
158 cell_texture_destroy(struct pipe_texture *pt)
159 {
160    struct cell_screen *screen = cell_screen(pt->screen);
161    struct sw_winsys *winsys = screen->winsys;
162    struct cell_texture *ct = cell_texture(pt);
163
164    if (ct->dt) {
165       /* display target */
166       winsys->displaytarget_destroy(winsys, ct->dt);
167    }
168
169    align_free(ct->data);
170
171    FREE(ct);
172 }
173
174
175
176 /**
177  * Convert image from linear layout to tiled layout.  4-byte pixels.
178  */
179 static void
180 twiddle_image_uint(uint w, uint h, uint tile_size, uint *dst,
181                    uint src_stride, const uint *src)
182 {
183    const uint tile_size2 = tile_size * tile_size;
184    const uint h_t = (h + tile_size - 1) / tile_size;
185    const uint w_t = (w + tile_size - 1) / tile_size;
186
187    uint it, jt;  /* tile counters */
188    uint i, j;    /* intra-tile counters */
189
190    src_stride /= 4; /* convert from bytes to pixels */
191
192    /* loop over dest tiles */
193    for (it = 0; it < h_t; it++) {
194       for (jt = 0; jt < w_t; jt++) {
195          /* start of dest tile: */
196          uint *tdst = dst + (it * w_t + jt) * tile_size2;
197
198          /* compute size of this tile (may be smaller than tile_size) */
199          /* XXX note: a compiler bug was found here. That's why the code
200           * looks as it does.
201           */
202          uint tile_width = w - jt * tile_size;
203          tile_width = MIN2(tile_width, tile_size);
204          uint tile_height = h - it * tile_size;
205          tile_height = MIN2(tile_height, tile_size);
206
207          /* loop over texels in the tile */
208          for (i = 0; i < tile_height; i++) {
209             for (j = 0; j < tile_width; j++) {
210                const uint srci = it * tile_size + i;
211                const uint srcj = jt * tile_size + j;
212                ASSERT(srci < h);
213                ASSERT(srcj < w);
214                tdst[i * tile_size + j] = src[srci * src_stride + srcj];
215             }
216          }
217       }
218    }
219 }
220
221
222 /**
223  * For Cell.  Basically, rearrange the pixels/quads from this layout:
224  *  +--+--+--+--+
225  *  |p0|p1|p2|p3|....
226  *  +--+--+--+--+
227  *
228  * to this layout:
229  *  +--+--+
230  *  |p0|p1|....
231  *  +--+--+
232  *  |p2|p3|
233  *  +--+--+
234  */
235 static void
236 twiddle_tile(const uint *tileIn, uint *tileOut)
237 {
238    int y, x;
239
240    for (y = 0; y < TILE_SIZE; y+=2) {
241       for (x = 0; x < TILE_SIZE; x+=2) {
242          int k = 4 * (y/2 * TILE_SIZE/2 + x/2);
243          tileOut[y * TILE_SIZE + (x + 0)] = tileIn[k];
244          tileOut[y * TILE_SIZE + (x + 1)] = tileIn[k+1];
245          tileOut[(y + 1) * TILE_SIZE + (x + 0)] = tileIn[k+2];
246          tileOut[(y + 1) * TILE_SIZE + (x + 1)] = tileIn[k+3];
247       }
248    }
249 }
250
251
252 /**
253  * Convert image from tiled layout to linear layout.  4-byte pixels.
254  */
255 static void
256 untwiddle_image_uint(uint w, uint h, uint tile_size, uint *dst,
257                      uint dst_stride, const uint *src)
258 {
259    const uint tile_size2 = tile_size * tile_size;
260    const uint h_t = (h + tile_size - 1) / tile_size;
261    const uint w_t = (w + tile_size - 1) / tile_size;
262    uint *tile_buf;
263    uint it, jt;  /* tile counters */
264    uint i, j;    /* intra-tile counters */
265
266    dst_stride /= 4; /* convert from bytes to pixels */
267
268    tile_buf = align_malloc(tile_size * tile_size * 4, 16);
269    
270    /* loop over src tiles */
271    for (it = 0; it < h_t; it++) {
272       for (jt = 0; jt < w_t; jt++) {
273          /* start of src tile: */
274          const uint *tsrc = src + (it * w_t + jt) * tile_size2;
275          
276          twiddle_tile(tsrc, tile_buf);
277          tsrc = tile_buf;
278
279          /* compute size of this tile (may be smaller than tile_size) */
280          /* XXX note: a compiler bug was found here. That's why the code
281           * looks as it does.
282           */
283          uint tile_width = w - jt * tile_size;
284          tile_width = MIN2(tile_width, tile_size);
285          uint tile_height = h - it * tile_size;
286          tile_height = MIN2(tile_height, tile_size);
287
288          /* loop over texels in the tile */
289          for (i = 0; i < tile_height; i++) {
290             for (j = 0; j < tile_width; j++) {
291                uint dsti = it * tile_size + i;
292                uint dstj = jt * tile_size + j;
293                ASSERT(dsti < h);
294                ASSERT(dstj < w);
295                dst[dsti * dst_stride + dstj] = tsrc[i * tile_size + j];
296             }
297          }
298       }
299    }
300
301    align_free(tile_buf);
302 }
303
304
305 static struct pipe_surface *
306 cell_get_tex_surface(struct pipe_screen *screen,
307                      struct pipe_texture *pt,
308                      unsigned face, unsigned level, unsigned zslice,
309                      unsigned usage)
310 {
311    struct cell_texture *ct = cell_texture(pt);
312    struct pipe_surface *ps;
313
314    ps = CALLOC_STRUCT(pipe_surface);
315    if (ps) {
316       pipe_reference_init(&ps->reference, 1);
317       pipe_texture_reference(&ps->texture, pt);
318       ps->format = pt->format;
319       ps->width = u_minify(pt->width0, level);
320       ps->height = u_minify(pt->height0, level);
321       ps->offset = ct->level_offset[level];
322       /* XXX may need to override usage flags (see sp_texture.c) */
323       ps->usage = usage;
324       ps->face = face;
325       ps->level = level;
326       ps->zslice = zslice;
327
328       if (pt->target == PIPE_TEXTURE_CUBE) {
329          unsigned h_tile = align(ps->height, TILE_SIZE);
330          ps->offset += face * util_format_get_nblocksy(ps->format, h_tile) * ct->stride[level];
331       }
332       else if (pt->target == PIPE_TEXTURE_3D) {
333          unsigned h_tile = align(ps->height, TILE_SIZE);
334          ps->offset += zslice * util_format_get_nblocksy(ps->format, h_tile) * ct->stride[level];
335       }
336       else {
337          assert(face == 0);
338          assert(zslice == 0);
339       }
340    }
341    return ps;
342 }
343
344
345 static void 
346 cell_tex_surface_destroy(struct pipe_surface *surf)
347 {
348    pipe_texture_reference(&surf->texture, NULL);
349    FREE(surf);
350 }
351
352
353 /**
354  * Create new pipe_transfer object.
355  * This is used by the user to put tex data into a texture (and get it
356  * back out for glGetTexImage).
357  */
358 static struct pipe_transfer *
359 cell_get_tex_transfer(struct pipe_context *ctx,
360                       struct pipe_texture *texture,
361                       unsigned face, unsigned level, unsigned zslice,
362                       enum pipe_transfer_usage usage,
363                       unsigned x, unsigned y, unsigned w, unsigned h)
364 {
365    struct cell_texture *ct = cell_texture(texture);
366    struct cell_transfer *ctrans;
367
368    assert(texture);
369    assert(level <= texture->last_level);
370
371    ctrans = CALLOC_STRUCT(cell_transfer);
372    if (ctrans) {
373       struct pipe_transfer *pt = &ctrans->base;
374       pipe_texture_reference(&pt->texture, texture);
375       pt->x = x;
376       pt->y = y;
377       pt->width = w;
378       pt->height = h;
379       pt->stride = ct->stride[level];
380       pt->usage = usage;
381       pt->face = face;
382       pt->level = level;
383       pt->zslice = zslice;
384
385       ctrans->offset = ct->level_offset[level];
386
387       if (texture->target == PIPE_TEXTURE_CUBE) {
388          unsigned h_tile = align(u_minify(texture->height0, level), TILE_SIZE);
389          ctrans->offset += face * util_format_get_nblocksy(texture->format, h_tile) * pt->stride;
390       }
391       else if (texture->target == PIPE_TEXTURE_3D) {
392          unsigned h_tile = align(u_minify(texture->height0, level), TILE_SIZE);
393          ctrans->offset += zslice * util_format_get_nblocksy(texture->format, h_tile) * pt->stride;
394       }
395       else {
396          assert(face == 0);
397          assert(zslice == 0);
398       }
399       return pt;
400    }
401    return NULL;
402 }
403
404
405 static void 
406 cell_tex_transfer_destroy(struct pipe_context *ctx, struct pipe_transfer *t)
407 {
408    struct cell_transfer *transfer = cell_transfer(t);
409    /* Effectively do the texture_update work here - if texture images
410     * needed post-processing to put them into hardware layout, this is
411     * where it would happen.  For cell, nothing to do.
412     */
413    assert (transfer->base.texture);
414    pipe_texture_reference(&transfer->base.texture, NULL);
415    FREE(transfer);
416 }
417
418
419 /**
420  * Return pointer to texture image data in linear layout.
421  */
422 static void *
423 cell_transfer_map(struct pipe_context *ctx, struct pipe_transfer *transfer)
424 {
425    struct cell_transfer *ctrans = cell_transfer(transfer);
426    struct pipe_texture *pt = transfer->texture;
427    struct cell_texture *ct = cell_texture(pt);
428    const uint level = ctrans->base.level;
429    const uint texWidth = u_minify(pt->width0, level);
430    const uint texHeight = u_minify(pt->height0, level);
431    const uint stride = ct->stride[level];
432    unsigned size;
433
434    assert(transfer->texture);
435
436    if (ct->mapped == NULL) {
437       ct->mapped = ct->data;
438    }
439
440    /*
441     * Create a buffer of ordinary memory for the linear texture.
442     * This is the memory that the user will read/write.
443     */
444    size = util_format_get_stride(pt->format, align(texWidth, TILE_SIZE)) *
445           util_format_get_nblocksy(pt->format, align(texHeight, TILE_SIZE));
446
447    ctrans->map = align_malloc(size, 16);
448    if (!ctrans->map)
449       return NULL; /* out of memory */
450
451    if (transfer->usage & PIPE_TRANSFER_READ) {
452       /* need to untwiddle the texture to make a linear version */
453       const uint bpp = util_format_get_blocksize(ct->base.format);
454       if (bpp == 4) {
455          const uint *src = (uint *) (ct->mapped + ctrans->offset);
456          uint *dst = ctrans->map;
457          untwiddle_image_uint(texWidth, texHeight, TILE_SIZE,
458                               dst, stride, src);
459       }
460       else {
461          // xxx fix
462       }
463    }
464
465    return ctrans->map;
466 }
467
468
469 /**
470  * Called when user is done reading/writing texture data.
471  * If new data was written, this is where we convert the linear data
472  * to tiled data.
473  */
474 static void
475 cell_transfer_unmap(struct pipe_context *ctx,
476                     struct pipe_transfer *transfer)
477 {
478    struct cell_transfer *ctrans = cell_transfer(transfer);
479    struct pipe_texture *pt = transfer->texture;
480    struct cell_texture *ct = cell_texture(pt);
481    const uint level = ctrans->base.level;
482    const uint texWidth = u_minify(pt->width0, level);
483    const uint texHeight = u_minify(pt->height0, level);
484    const uint stride = ct->stride[level];
485
486    if (!ct->mapped) {
487       assert(0);
488       return;
489    }
490
491    if (transfer->usage & PIPE_TRANSFER_WRITE) {
492       /* The user wrote new texture data into the mapped buffer.
493        * We need to convert the new linear data into the twiddled/tiled format.
494        */
495       const uint bpp = util_format_get_blocksize(ct->base.format);
496       if (bpp == 4) {
497          const uint *src = ctrans->map;
498          uint *dst = (uint *) (ct->mapped + ctrans->offset);
499          twiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst, stride, src);
500       }
501       else {
502          // xxx fix
503       }
504    }
505
506    align_free(ctrans->map);
507    ctrans->map = NULL;
508 }
509
510
511
512 /* This used to be overriden by the co-state tracker, but really needs
513  * to be active with sw_winsys.
514  *
515  * Contrasting with llvmpipe and softpipe, this is the only place
516  * where we use the ct->dt display target in any real sense.
517  *
518  * Basically just untwiddle our local data into the linear
519  * displaytarget.
520  */
521 static void
522 cell_flush_frontbuffer(struct pipe_screen *_screen,
523                        struct pipe_surface *surface,
524                        void *context_private)
525 {
526    struct cell_screen *screen = cell_screen(_screen);
527    struct sw_winsys *winsys = screen->winsys;
528    struct cell_texture *ct = cell_texture(surface->texture);
529
530    if (!ct->dt)
531       return;
532
533    /* Need to untwiddle from our internal representation here:
534     */
535    {
536       unsigned *map = winsys->displaytarget_map(winsys, ct->dt,
537                                                 (PIPE_BUFFER_USAGE_CPU_READ |
538                                                  PIPE_BUFFER_USAGE_CPU_WRITE));
539       unsigned *src = (unsigned *)(ct->data + ct->level_offset[surface->level]);
540
541       untwiddle_image_uint(surface->width,
542                            surface->height,
543                            TILE_SIZE,
544                            map,
545                            ct->dt_stride,
546                            src);
547
548       winsys->displaytarget_unmap(winsys, ct->dt);
549    }
550
551    winsys->displaytarget_display(winsys, ct->dt, context_private);
552 }
553
554
555 void
556 cell_init_screen_texture_funcs(struct pipe_screen *screen)
557 {
558    screen->texture_create = cell_texture_create;
559    screen->texture_destroy = cell_texture_destroy;
560
561    screen->get_tex_surface = cell_get_tex_surface;
562    screen->tex_surface_destroy = cell_tex_surface_destroy;
563
564    screen->flush_frontbuffer = cell_flush_frontbuffer;
565 }
566
567 void
568 cell_init_texture_transfer_funcs(struct cell_context *cell)
569 {
570    cell->pipe.get_tex_transfer = cell_get_tex_transfer;
571    cell->pipe.tex_transfer_destroy = cell_tex_transfer_destroy;
572    cell->pipe.transfer_map = cell_transfer_map;
573    cell->pipe.transfer_unmap = cell_transfer_unmap;
574 }