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"
37
#include "util/u_transfer.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_resource_layout(struct pipe_screen *screen,
53
struct cell_resource *ct)
55
struct pipe_resource *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_resource * 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_resource *
119
cell_resource_create(struct pipe_screen *screen,
120
const struct pipe_resource *templat)
122
struct cell_resource *ct = CALLOC_STRUCT(cell_resource);
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.bind & (PIPE_BIND_DISPLAY_TARGET |
136
if (!cell_displaytarget_layout(screen, ct))
140
if (!cell_resource_layout(screen, ct))
147
struct sw_winsys *winsys = cell_screen(screen)->winsys;
148
winsys->displaytarget_destroy(winsys, ct->dt);
158
cell_resource_destroy(struct pipe_screen *scrn, struct pipe_resource *pt)
160
struct cell_screen *screen = cell_screen(scrn);
161
struct sw_winsys *winsys = screen->winsys;
162
struct cell_resource *ct = cell_resource(pt);
166
winsys->displaytarget_destroy(winsys, ct->dt);
168
else if (!ct->userBuffer) {
169
align_free(ct->data);
178
* Convert image from linear layout to tiled layout. 4-byte pixels.
181
twiddle_image_uint(uint w, uint h, uint tile_size, uint *dst,
182
uint src_stride, const uint *src)
184
const uint tile_size2 = tile_size * tile_size;
185
const uint h_t = (h + tile_size - 1) / tile_size;
186
const uint w_t = (w + tile_size - 1) / tile_size;
188
uint it, jt; /* tile counters */
189
uint i, j; /* intra-tile counters */
191
src_stride /= 4; /* convert from bytes to pixels */
193
/* loop over dest tiles */
194
for (it = 0; it < h_t; it++) {
195
for (jt = 0; jt < w_t; jt++) {
196
/* start of dest tile: */
197
uint *tdst = dst + (it * w_t + jt) * tile_size2;
199
/* compute size of this tile (may be smaller than tile_size) */
200
/* XXX note: a compiler bug was found here. That's why the code
203
uint tile_width = w - jt * tile_size;
204
tile_width = MIN2(tile_width, tile_size);
205
uint tile_height = h - it * tile_size;
206
tile_height = MIN2(tile_height, tile_size);
208
/* loop over texels in the tile */
209
for (i = 0; i < tile_height; i++) {
210
for (j = 0; j < tile_width; j++) {
211
const uint srci = it * tile_size + i;
212
const uint srcj = jt * tile_size + j;
215
tdst[i * tile_size + j] = src[srci * src_stride + srcj];
224
* For Cell. Basically, rearrange the pixels/quads from this layout:
237
twiddle_tile(const uint *tileIn, uint *tileOut)
241
for (y = 0; y < TILE_SIZE; y+=2) {
242
for (x = 0; x < TILE_SIZE; x+=2) {
243
int k = 4 * (y/2 * TILE_SIZE/2 + x/2);
244
tileOut[y * TILE_SIZE + (x + 0)] = tileIn[k];
245
tileOut[y * TILE_SIZE + (x + 1)] = tileIn[k+1];
246
tileOut[(y + 1) * TILE_SIZE + (x + 0)] = tileIn[k+2];
247
tileOut[(y + 1) * TILE_SIZE + (x + 1)] = tileIn[k+3];
254
* Convert image from tiled layout to linear layout. 4-byte pixels.
257
untwiddle_image_uint(uint w, uint h, uint tile_size, uint *dst,
258
uint dst_stride, const uint *src)
260
const uint tile_size2 = tile_size * tile_size;
261
const uint h_t = (h + tile_size - 1) / tile_size;
262
const uint w_t = (w + tile_size - 1) / tile_size;
264
uint it, jt; /* tile counters */
265
uint i, j; /* intra-tile counters */
267
dst_stride /= 4; /* convert from bytes to pixels */
269
tile_buf = align_malloc(tile_size * tile_size * 4, 16);
271
/* loop over src tiles */
272
for (it = 0; it < h_t; it++) {
273
for (jt = 0; jt < w_t; jt++) {
274
/* start of src tile: */
275
const uint *tsrc = src + (it * w_t + jt) * tile_size2;
277
twiddle_tile(tsrc, tile_buf);
280
/* compute size of this tile (may be smaller than tile_size) */
281
/* XXX note: a compiler bug was found here. That's why the code
284
uint tile_width = w - jt * tile_size;
285
tile_width = MIN2(tile_width, tile_size);
286
uint tile_height = h - it * tile_size;
287
tile_height = MIN2(tile_height, tile_size);
289
/* loop over texels in the tile */
290
for (i = 0; i < tile_height; i++) {
291
for (j = 0; j < tile_width; j++) {
292
uint dsti = it * tile_size + i;
293
uint dstj = jt * tile_size + j;
296
dst[dsti * dst_stride + dstj] = tsrc[i * tile_size + j];
302
align_free(tile_buf);
306
static struct pipe_surface *
307
cell_create_surface(struct pipe_context *ctx,
308
struct pipe_resource *pt,
309
const struct pipe_surface *surf_tmpl)
311
struct cell_resource *ct = cell_resource(pt);
312
struct pipe_surface *ps;
314
assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
315
ps = CALLOC_STRUCT(pipe_surface);
317
pipe_reference_init(&ps->reference, 1);
318
pipe_resource_reference(&ps->texture, pt);
319
ps->format = surf_tmpl->format;
321
ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
322
ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
323
/* XXX may need to override usage flags (see sp_texture.c) */
324
ps->usage = surf_tmpl->usage;
325
ps->u.tex.level = surf_tmpl->u.tex.level;
326
ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
327
ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
334
cell_surface_destroy(struct pipe_context *ctx, struct pipe_surface *surf)
336
pipe_resource_reference(&surf->texture, NULL);
342
* Create new pipe_transfer object.
343
* This is used by the user to put tex data into a texture (and get it
344
* back out for glGetTexImage).
346
static struct pipe_transfer *
347
cell_get_transfer(struct pipe_context *ctx,
348
struct pipe_resource *resource,
351
const struct pipe_box *box)
353
struct cell_resource *ct = cell_resource(resource);
354
struct cell_transfer *ctrans;
355
enum pipe_format format = resource->format;
358
assert(level <= resource->last_level);
360
/* make sure the requested region is in the image bounds */
361
assert(box->x + box->width <= u_minify(resource->width0, level));
362
assert(box->y + box->height <= u_minify(resource->height0, level));
363
assert(box->z + box->depth <= (u_minify(resource->depth0, level) + resource->array_size - 1));
365
ctrans = CALLOC_STRUCT(cell_transfer);
367
struct pipe_transfer *pt = &ctrans->base;
368
pipe_resource_reference(&pt->resource, resource);
372
pt->stride = ct->stride[level];
374
ctrans->offset = ct->level_offset[level];
376
if (resource->target == PIPE_TEXTURE_CUBE || resource->target == PIPE_TEXTURE_3D) {
377
unsigned h_tile = align(u_minify(resource->height0, level), TILE_SIZE);
378
ctrans->offset += box->z * util_format_get_nblocksy(format, h_tile) * pt->stride;
391
cell_transfer_destroy(struct pipe_context *ctx, struct pipe_transfer *t)
393
struct cell_transfer *transfer = cell_transfer(t);
394
/* Effectively do the texture_update work here - if texture images
395
* needed post-processing to put them into hardware layout, this is
396
* where it would happen. For cell, nothing to do.
398
assert (transfer->base.resource);
399
pipe_resource_reference(&transfer->base.resource, NULL);
405
* Return pointer to texture image data in linear layout.
408
cell_transfer_map(struct pipe_context *ctx, struct pipe_transfer *transfer)
410
struct cell_transfer *ctrans = cell_transfer(transfer);
411
struct pipe_resource *pt = transfer->resource;
412
struct cell_resource *ct = cell_resource(pt);
414
assert(transfer->resource);
416
if (ct->mapped == NULL) {
417
ct->mapped = ct->data;
421
/* Better test would be resource->is_linear
423
if (transfer->resource->target != PIPE_BUFFER) {
424
const uint level = ctrans->base.level;
425
const uint texWidth = u_minify(pt->width0, level);
426
const uint texHeight = u_minify(pt->height0, level);
431
* Create a buffer of ordinary memory for the linear texture.
432
* This is the memory that the user will read/write.
434
size = (util_format_get_stride(pt->format, align(texWidth, TILE_SIZE)) *
435
util_format_get_nblocksy(pt->format, align(texHeight, TILE_SIZE)));
437
ctrans->map = align_malloc(size, 16);
439
return NULL; /* out of memory */
441
if (transfer->usage & PIPE_TRANSFER_READ) {
442
/* Textures always stored twiddled, need to untwiddle the
443
* texture to make a linear version.
445
const uint bpp = util_format_get_blocksize(ct->base.format);
447
const uint *src = (uint *) (ct->mapped + ctrans->offset);
448
uint *dst = ctrans->map;
449
untwiddle_image_uint(texWidth, texHeight, TILE_SIZE,
450
dst, transfer->stride, src);
458
unsigned stride = transfer->stride;
459
enum pipe_format format = pt->format;
460
unsigned blocksize = util_format_get_blocksize(format);
462
ctrans->map = (ct->mapped +
464
ctrans->base.box.y / util_format_get_blockheight(format) * stride +
465
ctrans->base.box.x / util_format_get_blockwidth(format) * blocksize);
474
* Called when user is done reading/writing texture data.
475
* If new data was written, this is where we convert the linear data
479
cell_transfer_unmap(struct pipe_context *ctx,
480
struct pipe_transfer *transfer)
482
struct cell_transfer *ctrans = cell_transfer(transfer);
483
struct pipe_resource *pt = transfer->resource;
484
struct cell_resource *ct = cell_resource(pt);
485
const uint level = ctrans->base.level;
486
const uint texWidth = u_minify(pt->width0, level);
487
const uint texHeight = u_minify(pt->height0, level);
488
const uint stride = ct->stride[level];
495
if (pt->target != PIPE_BUFFER) {
496
if (transfer->usage & PIPE_TRANSFER_WRITE) {
497
/* The user wrote new texture data into the mapped buffer.
498
* We need to convert the new linear data into the twiddled/tiled format.
500
const uint bpp = util_format_get_blocksize(ct->base.format);
502
const uint *src = ctrans->map;
503
uint *dst = (uint *) (ct->mapped + ctrans->offset);
504
twiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst, stride, src);
511
align_free(ctrans->map);
522
/* This used to be overriden by the co-state tracker, but really needs
523
* to be active with sw_winsys.
525
* Contrasting with llvmpipe and softpipe, this is the only place
526
* where we use the ct->dt display target in any real sense.
528
* Basically just untwiddle our local data into the linear
532
cell_flush_frontbuffer(struct pipe_screen *_screen,
533
struct pipe_resource *resource,
534
unsigned level, unsigned layer,
535
void *context_private)
537
struct cell_screen *screen = cell_screen(_screen);
538
struct sw_winsys *winsys = screen->winsys;
539
struct cell_resource *ct = cell_resource(resource);
544
/* Need to untwiddle from our internal representation here:
547
unsigned *map = winsys->displaytarget_map(winsys, ct->dt,
548
(PIPE_TRANSFER_READ |
549
PIPE_TRANSFER_WRITE));
550
unsigned *src = (unsigned *)(ct->data + ct->level_offset[level]);
552
untwiddle_image_uint(u_minify(resource->width0, level),
553
u_minify(resource->height0, level),
559
winsys->displaytarget_unmap(winsys, ct->dt);
562
winsys->displaytarget_display(winsys, ct->dt, context_private);
568
* Create buffer which wraps user-space data.
570
static struct pipe_resource *
571
cell_user_buffer_create(struct pipe_screen *screen,
576
struct cell_resource *buffer;
578
buffer = CALLOC_STRUCT(cell_resource);
582
pipe_reference_init(&buffer->base.reference, 1);
583
buffer->base.screen = screen;
584
buffer->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
585
buffer->base.bind = PIPE_BIND_TRANSFER_READ | bind_flags;
586
buffer->base.usage = PIPE_USAGE_IMMUTABLE;
587
buffer->base.flags = 0;
588
buffer->base.width0 = bytes;
589
buffer->base.height0 = 1;
590
buffer->base.depth0 = 1;
591
buffer->base.array_size = 1;
592
buffer->userBuffer = TRUE;
595
return &buffer->base;
599
static struct pipe_resource *
600
cell_resource_from_handle(struct pipe_screen *screen,
601
const struct pipe_resource *templat,
602
struct winsys_handle *handle)
610
cell_resource_get_handle(struct pipe_screen *scree,
611
struct pipe_resource *tex,
612
struct winsys_handle *handle)
620
cell_init_screen_texture_funcs(struct pipe_screen *screen)
622
screen->resource_create = cell_resource_create;
623
screen->resource_destroy = cell_resource_destroy;
624
screen->resource_from_handle = cell_resource_from_handle;
625
screen->resource_get_handle = cell_resource_get_handle;
626
screen->user_buffer_create = cell_user_buffer_create;
628
screen->flush_frontbuffer = cell_flush_frontbuffer;
632
cell_init_texture_transfer_funcs(struct cell_context *cell)
634
cell->pipe.get_transfer = cell_get_transfer;
635
cell->pipe.transfer_destroy = cell_transfer_destroy;
636
cell->pipe.transfer_map = cell_transfer_map;
637
cell->pipe.transfer_unmap = cell_transfer_unmap;
639
cell->pipe.transfer_flush_region = u_default_transfer_flush_region;
640
cell->pipe.transfer_inline_write = u_default_transfer_inline_write;
642
cell->pipe.create_surface = cell_create_surface;
643
cell->pipe.surface_destroy = cell_surface_destroy;