1 /**************************************************************************
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
29 * Keith Whitwell <keith@tungstengraphics.com>
30 * Michel Dänzer <michel@tungstengraphics.com>
34 #include "pipe/p_context.h"
35 #include "pipe/p_defines.h"
36 #include "util/u_inlines.h"
38 #include "util/u_format.h"
39 #include "util/u_math.h"
40 #include "util/u_memory.h"
42 #include "cell_context.h"
43 #include "cell_screen.h"
44 #include "cell_state.h"
45 #include "cell_texture.h"
47 #include "state_tracker/sw_winsys.h"
52 cell_texture_layout(struct pipe_screen *screen,
53 struct cell_texture *ct)
55 struct pipe_texture *pt = &ct->base;
57 unsigned width = pt->width0;
58 unsigned height = pt->height0;
59 unsigned depth = pt->depth0;
63 for (level = 0; level <= pt->last_level; level++) {
65 unsigned w_tile, h_tile;
67 assert(level < CELL_MAX_TEXTURE_LEVELS);
69 /* width, height, rounded up to tile size */
70 w_tile = align(width, TILE_SIZE);
71 h_tile = align(height, TILE_SIZE);
73 ct->stride[level] = util_format_get_stride(pt->format, w_tile);
75 ct->level_offset[level] = ct->buffer_size;
77 size = ct->stride[level] * util_format_get_nblocksy(pt->format, h_tile);
78 if (pt->target == PIPE_TEXTURE_CUBE)
83 ct->buffer_size += size;
85 width = u_minify(width, 1);
86 height = u_minify(height, 1);
87 depth = u_minify(depth, 1);
90 ct->data = align_malloc(ct->buffer_size, 16);
92 return ct->data != NULL;
97 * Texture layout for simple color buffers.
100 cell_displaytarget_layout(struct pipe_screen *screen,
101 struct cell_texture * ct)
103 struct sw_winsys *winsys = cell_screen(screen)->winsys;
105 /* Round up the surface size to a multiple of the tile size?
107 ct->dt = winsys->displaytarget_create(winsys,
115 return ct->dt != NULL;
118 static struct pipe_texture *
119 cell_texture_create(struct pipe_screen *screen,
120 const struct pipe_texture *templat)
122 struct cell_texture *ct = CALLOC_STRUCT(cell_texture);
127 pipe_reference_init(&ct->base.reference, 1);
128 ct->base.screen = screen;
130 /* Create both a displaytarget (linear) and regular texture
131 * (twiddled). Convert twiddled->linear at flush_frontbuffer time.
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))
140 if (!cell_texture_layout(screen, ct))
147 struct sw_winsys *winsys = cell_screen(screen)->winsys;
148 winsys->displaytarget_destroy(winsys, ct->dt);
158 cell_texture_destroy(struct pipe_texture *pt)
160 struct cell_screen *screen = cell_screen(pt->screen);
161 struct sw_winsys *winsys = screen->winsys;
162 struct cell_texture *ct = cell_texture(pt);
166 winsys->displaytarget_destroy(winsys, ct->dt);
169 align_free(ct->data);
177 * Convert image from linear layout to tiled layout. 4-byte pixels.
180 twiddle_image_uint(uint w, uint h, uint tile_size, uint *dst,
181 uint src_stride, const uint *src)
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;
187 uint it, jt; /* tile counters */
188 uint i, j; /* intra-tile counters */
190 src_stride /= 4; /* convert from bytes to pixels */
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;
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
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);
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;
214 tdst[i * tile_size + j] = src[srci * src_stride + srcj];
223 * For Cell. Basically, rearrange the pixels/quads from this layout:
236 twiddle_tile(const uint *tileIn, uint *tileOut)
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];
253 * Convert image from tiled layout to linear layout. 4-byte pixels.
256 untwiddle_image_uint(uint w, uint h, uint tile_size, uint *dst,
257 uint dst_stride, const uint *src)
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;
263 uint it, jt; /* tile counters */
264 uint i, j; /* intra-tile counters */
266 dst_stride /= 4; /* convert from bytes to pixels */
268 tile_buf = align_malloc(tile_size * tile_size * 4, 16);
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;
276 twiddle_tile(tsrc, tile_buf);
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
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);
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;
295 dst[dsti * dst_stride + dstj] = tsrc[i * tile_size + j];
301 align_free(tile_buf);
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,
311 struct cell_texture *ct = cell_texture(pt);
312 struct pipe_surface *ps;
314 ps = CALLOC_STRUCT(pipe_surface);
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) */
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];
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];
346 cell_tex_surface_destroy(struct pipe_surface *surf)
348 pipe_texture_reference(&surf->texture, NULL);
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).
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)
365 struct cell_texture *ct = cell_texture(texture);
366 struct cell_transfer *ctrans;
369 assert(level <= texture->last_level);
371 ctrans = CALLOC_STRUCT(cell_transfer);
373 struct pipe_transfer *pt = &ctrans->base;
374 pipe_texture_reference(&pt->texture, texture);
379 pt->stride = ct->stride[level];
385 ctrans->offset = ct->level_offset[level];
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;
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;
406 cell_tex_transfer_destroy(struct pipe_context *ctx, struct pipe_transfer *t)
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.
413 assert (transfer->base.texture);
414 pipe_texture_reference(&transfer->base.texture, NULL);
420 * Return pointer to texture image data in linear layout.
423 cell_transfer_map(struct pipe_context *ctx, struct pipe_transfer *transfer)
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];
434 assert(transfer->texture);
436 if (ct->mapped == NULL) {
437 ct->mapped = ct->data;
441 * Create a buffer of ordinary memory for the linear texture.
442 * This is the memory that the user will read/write.
444 size = util_format_get_stride(pt->format, align(texWidth, TILE_SIZE)) *
445 util_format_get_nblocksy(pt->format, align(texHeight, TILE_SIZE));
447 ctrans->map = align_malloc(size, 16);
449 return NULL; /* out of memory */
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);
455 const uint *src = (uint *) (ct->mapped + ctrans->offset);
456 uint *dst = ctrans->map;
457 untwiddle_image_uint(texWidth, texHeight, TILE_SIZE,
470 * Called when user is done reading/writing texture data.
471 * If new data was written, this is where we convert the linear data
475 cell_transfer_unmap(struct pipe_context *ctx,
476 struct pipe_transfer *transfer)
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];
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.
495 const uint bpp = util_format_get_blocksize(ct->base.format);
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);
506 align_free(ctrans->map);
512 /* This used to be overriden by the co-state tracker, but really needs
513 * to be active with sw_winsys.
515 * Contrasting with llvmpipe and softpipe, this is the only place
516 * where we use the ct->dt display target in any real sense.
518 * Basically just untwiddle our local data into the linear
522 cell_flush_frontbuffer(struct pipe_screen *_screen,
523 struct pipe_surface *surface,
524 void *context_private)
526 struct cell_screen *screen = cell_screen(_screen);
527 struct sw_winsys *winsys = screen->winsys;
528 struct cell_texture *ct = cell_texture(surface->texture);
533 /* Need to untwiddle from our internal representation here:
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]);
541 untwiddle_image_uint(surface->width,
548 winsys->displaytarget_unmap(winsys, ct->dt);
551 winsys->displaytarget_display(winsys, ct->dt, context_private);
556 cell_init_screen_texture_funcs(struct pipe_screen *screen)
558 screen->texture_create = cell_texture_create;
559 screen->texture_destroy = cell_texture_destroy;
561 screen->get_tex_surface = cell_get_tex_surface;
562 screen->tex_surface_destroy = cell_tex_surface_destroy;
564 screen->flush_frontbuffer = cell_flush_frontbuffer;
568 cell_init_texture_transfer_funcs(struct cell_context *cell)
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;