1/************************************************************************** 2 * 3 * Copyright 2007 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/** 29 * Render target tile caching. 30 * 31 * Author: 32 * Brian Paul 33 */ 34 35#include "util/u_inlines.h" 36#include "util/u_format.h" 37#include "util/u_memory.h" 38#include "util/u_tile.h" 39#include "sp_tile_cache.h" 40 41static struct softpipe_cached_tile * 42sp_alloc_tile(struct softpipe_tile_cache *tc); 43 44 45/** 46 * Return the position in the cache for the tile that contains win pos (x,y). 47 * We currently use a direct mapped cache so this is like a hack key. 48 * At some point we should investige something more sophisticated, like 49 * a LRU replacement policy. 50 */ 51#define CACHE_POS(x, y) \ 52 (((x) + (y) * 5) % NUM_ENTRIES) 53 54 55 56/** 57 * Is the tile at (x,y) in cleared state? 58 */ 59static INLINE uint 60is_clear_flag_set(const uint *bitvec, union tile_address addr) 61{ 62 int pos, bit; 63 pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x; 64 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32); 65 bit = bitvec[pos / 32] & (1 << (pos & 31)); 66 return bit; 67} 68 69 70/** 71 * Mark the tile at (x,y) as not cleared. 72 */ 73static INLINE void 74clear_clear_flag(uint *bitvec, union tile_address addr) 75{ 76 int pos; 77 pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x; 78 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32); 79 bitvec[pos / 32] &= ~(1 << (pos & 31)); 80} 81 82 83struct softpipe_tile_cache * 84sp_create_tile_cache( struct pipe_context *pipe ) 85{ 86 struct softpipe_tile_cache *tc; 87 uint pos; 88 int maxLevels, maxTexSize; 89 90 /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */ 91 maxLevels = pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); 92 maxTexSize = 1 << (maxLevels - 1); 93 assert(MAX_WIDTH >= maxTexSize); 94 95 assert(sizeof(union tile_address) == 4); 96 97 assert((TILE_SIZE << TILE_ADDR_BITS) >= MAX_WIDTH); 98 99 tc = CALLOC_STRUCT( softpipe_tile_cache ); 100 if (tc) { 101 tc->pipe = pipe; 102 for (pos = 0; pos < NUM_ENTRIES; pos++) { 103 tc->tile_addrs[pos].bits.invalid = 1; 104 } 105 tc->last_tile_addr.bits.invalid = 1; 106 107 /* this allocation allows us to guarantee that allocation 108 * failures are never fatal later 109 */ 110 tc->tile = MALLOC_STRUCT( softpipe_cached_tile ); 111 if (!tc->tile) 112 { 113 FREE(tc); 114 return NULL; 115 } 116 117 /* XXX this code prevents valgrind warnings about use of uninitialized 118 * memory in programs that don't clear the surface before rendering. 119 * However, it breaks clearing in other situations (such as in 120 * progs/tests/drawbuffers, see bug 24402). 121 */ 122#if 0 123 /* set flags to indicate all the tiles are cleared */ 124 memset(tc->clear_flags, 255, sizeof(tc->clear_flags)); 125#endif 126 } 127 return tc; 128} 129 130 131void 132sp_destroy_tile_cache(struct softpipe_tile_cache *tc) 133{ 134 if (tc) { 135 uint pos; 136 137 for (pos = 0; pos < NUM_ENTRIES; pos++) { 138 /*assert(tc->entries[pos].x < 0);*/ 139 FREE( tc->entries[pos] ); 140 } 141 FREE( tc->tile ); 142 143 if (tc->transfer) { 144 tc->pipe->transfer_destroy(tc->pipe, tc->transfer); 145 } 146 147 FREE( tc ); 148 } 149} 150 151 152/** 153 * Specify the surface to cache. 154 */ 155void 156sp_tile_cache_set_surface(struct softpipe_tile_cache *tc, 157 struct pipe_surface *ps) 158{ 159 struct pipe_context *pipe = tc->pipe; 160 161 if (tc->transfer) { 162 if (ps == tc->surface) 163 return; 164 165 if (tc->transfer_map) { 166 pipe->transfer_unmap(pipe, tc->transfer); 167 tc->transfer_map = NULL; 168 } 169 170 pipe->transfer_destroy(pipe, tc->transfer); 171 tc->transfer = NULL; 172 } 173 174 tc->surface = ps; 175 176 if (ps) { 177 tc->transfer = pipe_get_transfer(pipe, ps->texture, 178 ps->u.tex.level, ps->u.tex.first_layer, 179 PIPE_TRANSFER_READ_WRITE | 180 PIPE_TRANSFER_UNSYNCHRONIZED, 181 0, 0, ps->width, ps->height); 182 183 tc->depth_stencil = util_format_is_depth_or_stencil(ps->format); 184 } 185} 186 187 188/** 189 * Return the transfer being cached. 190 */ 191struct pipe_surface * 192sp_tile_cache_get_surface(struct softpipe_tile_cache *tc) 193{ 194 return tc->surface; 195} 196 197 198void 199sp_tile_cache_map_transfers(struct softpipe_tile_cache *tc) 200{ 201 if (tc->transfer && !tc->transfer_map) 202 tc->transfer_map = tc->pipe->transfer_map(tc->pipe, tc->transfer); 203} 204 205 206void 207sp_tile_cache_unmap_transfers(struct softpipe_tile_cache *tc) 208{ 209 if (tc->transfer_map) { 210 tc->pipe->transfer_unmap(tc->pipe, tc->transfer); 211 tc->transfer_map = NULL; 212 } 213} 214 215 216/** 217 * Set pixels in a tile to the given clear color/value, float. 218 */ 219static void 220clear_tile_rgba(struct softpipe_cached_tile *tile, 221 enum pipe_format format, 222 const union pipe_color_union *clear_value) 223{ 224 if (clear_value->f[0] == 0.0 && 225 clear_value->f[1] == 0.0 && 226 clear_value->f[2] == 0.0 && 227 clear_value->f[3] == 0.0) { 228 memset(tile->data.color, 0, sizeof(tile->data.color)); 229 } 230 else { 231 uint i, j; 232 233 if (util_format_is_pure_uint(format)) { 234 for (i = 0; i < TILE_SIZE; i++) { 235 for (j = 0; j < TILE_SIZE; j++) { 236 tile->data.colorui128[i][j][0] = clear_value->ui[0]; 237 tile->data.colorui128[i][j][1] = clear_value->ui[1]; 238 tile->data.colorui128[i][j][2] = clear_value->ui[2]; 239 tile->data.colorui128[i][j][3] = clear_value->ui[3]; 240 } 241 } 242 } else if (util_format_is_pure_sint(format)) { 243 for (i = 0; i < TILE_SIZE; i++) { 244 for (j = 0; j < TILE_SIZE; j++) { 245 tile->data.colori128[i][j][0] = clear_value->i[0]; 246 tile->data.colori128[i][j][1] = clear_value->i[1]; 247 tile->data.colori128[i][j][2] = clear_value->i[2]; 248 tile->data.colori128[i][j][3] = clear_value->i[3]; 249 } 250 } 251 } else { 252 for (i = 0; i < TILE_SIZE; i++) { 253 for (j = 0; j < TILE_SIZE; j++) { 254 tile->data.color[i][j][0] = clear_value->f[0]; 255 tile->data.color[i][j][1] = clear_value->f[1]; 256 tile->data.color[i][j][2] = clear_value->f[2]; 257 tile->data.color[i][j][3] = clear_value->f[3]; 258 } 259 } 260 } 261 } 262} 263 264 265/** 266 * Set a tile to a solid value/color. 267 */ 268static void 269clear_tile(struct softpipe_cached_tile *tile, 270 enum pipe_format format, 271 uint64_t clear_value) 272{ 273 uint i, j; 274 275 switch (util_format_get_blocksize(format)) { 276 case 1: 277 memset(tile->data.any, clear_value, TILE_SIZE * TILE_SIZE); 278 break; 279 case 2: 280 if (clear_value == 0) { 281 memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE); 282 } 283 else { 284 for (i = 0; i < TILE_SIZE; i++) { 285 for (j = 0; j < TILE_SIZE; j++) { 286 tile->data.depth16[i][j] = (ushort) clear_value; 287 } 288 } 289 } 290 break; 291 case 4: 292 if (clear_value == 0) { 293 memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE); 294 } 295 else { 296 for (i = 0; i < TILE_SIZE; i++) { 297 for (j = 0; j < TILE_SIZE; j++) { 298 tile->data.depth32[i][j] = clear_value; 299 } 300 } 301 } 302 break; 303 case 8: 304 if (clear_value == 0) { 305 memset(tile->data.any, 0, 8 * TILE_SIZE * TILE_SIZE); 306 } 307 else { 308 for (i = 0; i < TILE_SIZE; i++) { 309 for (j = 0; j < TILE_SIZE; j++) { 310 tile->data.depth64[i][j] = clear_value; 311 } 312 } 313 } 314 break; 315 default: 316 assert(0); 317 } 318} 319 320 321/** 322 * Actually clear the tiles which were flagged as being in a clear state. 323 */ 324static void 325sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc) 326{ 327 struct pipe_transfer *pt = tc->transfer; 328 const uint w = tc->transfer->box.width; 329 const uint h = tc->transfer->box.height; 330 uint x, y; 331 uint numCleared = 0; 332 333 assert(pt->resource); 334 if (!tc->tile) 335 tc->tile = sp_alloc_tile(tc); 336 337 /* clear the scratch tile to the clear value */ 338 if (tc->depth_stencil) { 339 clear_tile(tc->tile, pt->resource->format, tc->clear_val); 340 } else { 341 clear_tile_rgba(tc->tile, pt->resource->format, &tc->clear_color); 342 } 343 344 /* push the tile to all positions marked as clear */ 345 for (y = 0; y < h; y += TILE_SIZE) { 346 for (x = 0; x < w; x += TILE_SIZE) { 347 union tile_address addr = tile_address(x, y); 348 349 if (is_clear_flag_set(tc->clear_flags, addr)) { 350 /* write the scratch tile to the surface */ 351 if (tc->depth_stencil) { 352 pipe_put_tile_raw(tc->pipe, 353 pt, 354 x, y, TILE_SIZE, TILE_SIZE, 355 tc->tile->data.any, 0/*STRIDE*/); 356 } 357 else { 358 if (util_format_is_pure_uint(tc->surface->format)) { 359 pipe_put_tile_ui_format(tc->pipe, pt, 360 x, y, TILE_SIZE, TILE_SIZE, 361 pt->resource->format, 362 (unsigned *) tc->tile->data.colorui128); 363 } else if (util_format_is_pure_sint(tc->surface->format)) { 364 pipe_put_tile_i_format(tc->pipe, pt, 365 x, y, TILE_SIZE, TILE_SIZE, 366 pt->resource->format, 367 (int *) tc->tile->data.colori128); 368 } else { 369 pipe_put_tile_rgba(tc->pipe, pt, 370 x, y, TILE_SIZE, TILE_SIZE, 371 (float *) tc->tile->data.color); 372 } 373 } 374 numCleared++; 375 } 376 } 377 } 378 379 /* reset all clear flags to zero */ 380 memset(tc->clear_flags, 0, sizeof(tc->clear_flags)); 381 382#if 0 383 debug_printf("num cleared: %u\n", numCleared); 384#endif 385} 386 387static void 388sp_flush_tile(struct softpipe_tile_cache* tc, unsigned pos) 389{ 390 if (!tc->tile_addrs[pos].bits.invalid) { 391 if (tc->depth_stencil) { 392 pipe_put_tile_raw(tc->pipe, tc->transfer, 393 tc->tile_addrs[pos].bits.x * TILE_SIZE, 394 tc->tile_addrs[pos].bits.y * TILE_SIZE, 395 TILE_SIZE, TILE_SIZE, 396 tc->entries[pos]->data.depth32, 0/*STRIDE*/); 397 } 398 else { 399 if (util_format_is_pure_uint(tc->surface->format)) { 400 pipe_put_tile_ui_format(tc->pipe, tc->transfer, 401 tc->tile_addrs[pos].bits.x * TILE_SIZE, 402 tc->tile_addrs[pos].bits.y * TILE_SIZE, 403 TILE_SIZE, TILE_SIZE, 404 tc->surface->format, 405 (unsigned *) tc->entries[pos]->data.colorui128); 406 } else if (util_format_is_pure_sint(tc->surface->format)) { 407 pipe_put_tile_i_format(tc->pipe, tc->transfer, 408 tc->tile_addrs[pos].bits.x * TILE_SIZE, 409 tc->tile_addrs[pos].bits.y * TILE_SIZE, 410 TILE_SIZE, TILE_SIZE, 411 tc->surface->format, 412 (int *) tc->entries[pos]->data.colori128); 413 } else { 414 pipe_put_tile_rgba_format(tc->pipe, tc->transfer, 415 tc->tile_addrs[pos].bits.x * TILE_SIZE, 416 tc->tile_addrs[pos].bits.y * TILE_SIZE, 417 TILE_SIZE, TILE_SIZE, 418 tc->surface->format, 419 (float *) tc->entries[pos]->data.color); 420 } 421 } 422 tc->tile_addrs[pos].bits.invalid = 1; /* mark as empty */ 423 } 424} 425 426/** 427 * Flush the tile cache: write all dirty tiles back to the transfer. 428 * any tiles "flagged" as cleared will be "really" cleared. 429 */ 430void 431sp_flush_tile_cache(struct softpipe_tile_cache *tc) 432{ 433 struct pipe_transfer *pt = tc->transfer; 434 int inuse = 0, pos; 435 436 if (pt) { 437 /* caching a drawing transfer */ 438 for (pos = 0; pos < NUM_ENTRIES; pos++) { 439 struct softpipe_cached_tile *tile = tc->entries[pos]; 440 if (!tile) 441 { 442 assert(tc->tile_addrs[pos].bits.invalid); 443 continue; 444 } 445 446 sp_flush_tile(tc, pos); 447 ++inuse; 448 } 449 450 sp_tile_cache_flush_clear(tc); 451 452 453 tc->last_tile_addr.bits.invalid = 1; 454 } 455 456#if 0 457 debug_printf("flushed tiles in use: %d\n", inuse); 458#endif 459} 460 461static struct softpipe_cached_tile * 462sp_alloc_tile(struct softpipe_tile_cache *tc) 463{ 464 struct softpipe_cached_tile * tile = MALLOC_STRUCT(softpipe_cached_tile); 465 if (!tile) 466 { 467 /* in this case, steal an existing tile */ 468 if (!tc->tile) 469 { 470 unsigned pos; 471 for (pos = 0; pos < NUM_ENTRIES; ++pos) { 472 if (!tc->entries[pos]) 473 continue; 474 475 sp_flush_tile(tc, pos); 476 tc->tile = tc->entries[pos]; 477 tc->entries[pos] = NULL; 478 break; 479 } 480 481 /* this should never happen */ 482 if (!tc->tile) 483 abort(); 484 } 485 486 tile = tc->tile; 487 tc->tile = NULL; 488 489 tc->last_tile_addr.bits.invalid = 1; 490 } 491 return tile; 492} 493 494/** 495 * Get a tile from the cache. 496 * \param x, y position of tile, in pixels 497 */ 498struct softpipe_cached_tile * 499sp_find_cached_tile(struct softpipe_tile_cache *tc, 500 union tile_address addr ) 501{ 502 struct pipe_transfer *pt = tc->transfer; 503 /* cache pos/entry: */ 504 const int pos = CACHE_POS(addr.bits.x, 505 addr.bits.y); 506 struct softpipe_cached_tile *tile = tc->entries[pos]; 507 508 if (!tile) { 509 tile = sp_alloc_tile(tc); 510 tc->entries[pos] = tile; 511 } 512 513 if (addr.value != tc->tile_addrs[pos].value) { 514 515 assert(pt->resource); 516 if (tc->tile_addrs[pos].bits.invalid == 0) { 517 /* put dirty tile back in framebuffer */ 518 if (tc->depth_stencil) { 519 pipe_put_tile_raw(tc->pipe, pt, 520 tc->tile_addrs[pos].bits.x * TILE_SIZE, 521 tc->tile_addrs[pos].bits.y * TILE_SIZE, 522 TILE_SIZE, TILE_SIZE, 523 tile->data.depth32, 0/*STRIDE*/); 524 } 525 else { 526 if (util_format_is_pure_uint(tc->surface->format)) { 527 pipe_put_tile_ui_format(tc->pipe, pt, 528 tc->tile_addrs[pos].bits.x * TILE_SIZE, 529 tc->tile_addrs[pos].bits.y * TILE_SIZE, 530 TILE_SIZE, TILE_SIZE, 531 tc->surface->format, 532 (unsigned *) tile->data.colorui128); 533 } else if (util_format_is_pure_sint(tc->surface->format)) { 534 pipe_put_tile_i_format(tc->pipe, pt, 535 tc->tile_addrs[pos].bits.x * TILE_SIZE, 536 tc->tile_addrs[pos].bits.y * TILE_SIZE, 537 TILE_SIZE, TILE_SIZE, 538 tc->surface->format, 539 (int *) tile->data.colori128); 540 } else { 541 pipe_put_tile_rgba_format(tc->pipe, pt, 542 tc->tile_addrs[pos].bits.x * TILE_SIZE, 543 tc->tile_addrs[pos].bits.y * TILE_SIZE, 544 TILE_SIZE, TILE_SIZE, 545 tc->surface->format, 546 (float *) tile->data.color); 547 } 548 } 549 } 550 551 tc->tile_addrs[pos] = addr; 552 553 if (is_clear_flag_set(tc->clear_flags, addr)) { 554 /* don't get tile from framebuffer, just clear it */ 555 if (tc->depth_stencil) { 556 clear_tile(tile, pt->resource->format, tc->clear_val); 557 } 558 else { 559 clear_tile_rgba(tile, pt->resource->format, &tc->clear_color); 560 } 561 clear_clear_flag(tc->clear_flags, addr); 562 } 563 else { 564 /* get new tile data from transfer */ 565 if (tc->depth_stencil) { 566 pipe_get_tile_raw(tc->pipe, pt, 567 tc->tile_addrs[pos].bits.x * TILE_SIZE, 568 tc->tile_addrs[pos].bits.y * TILE_SIZE, 569 TILE_SIZE, TILE_SIZE, 570 tile->data.depth32, 0/*STRIDE*/); 571 } 572 else { 573 if (util_format_is_pure_uint(tc->surface->format)) { 574 pipe_get_tile_ui_format(tc->pipe, pt, 575 tc->tile_addrs[pos].bits.x * TILE_SIZE, 576 tc->tile_addrs[pos].bits.y * TILE_SIZE, 577 TILE_SIZE, TILE_SIZE, 578 tc->surface->format, 579 (unsigned *) tile->data.colorui128); 580 } else if (util_format_is_pure_sint(tc->surface->format)) { 581 pipe_get_tile_i_format(tc->pipe, pt, 582 tc->tile_addrs[pos].bits.x * TILE_SIZE, 583 tc->tile_addrs[pos].bits.y * TILE_SIZE, 584 TILE_SIZE, TILE_SIZE, 585 tc->surface->format, 586 (int *) tile->data.colori128); 587 } else { 588 pipe_get_tile_rgba_format(tc->pipe, pt, 589 tc->tile_addrs[pos].bits.x * TILE_SIZE, 590 tc->tile_addrs[pos].bits.y * TILE_SIZE, 591 TILE_SIZE, TILE_SIZE, 592 tc->surface->format, 593 (float *) tile->data.color); 594 } 595 } 596 } 597 } 598 599 tc->last_tile = tile; 600 tc->last_tile_addr = addr; 601 return tile; 602} 603 604 605 606 607 608/** 609 * When a whole surface is being cleared to a value we can avoid 610 * fetching tiles above. 611 * Save the color and set a 'clearflag' for each tile of the screen. 612 */ 613void 614sp_tile_cache_clear(struct softpipe_tile_cache *tc, 615 const union pipe_color_union *color, 616 uint64_t clearValue) 617{ 618 uint pos; 619 620 tc->clear_color = *color; 621 622 tc->clear_val = clearValue; 623 624 /* set flags to indicate all the tiles are cleared */ 625 memset(tc->clear_flags, 255, sizeof(tc->clear_flags)); 626 627 for (pos = 0; pos < NUM_ENTRIES; pos++) { 628 tc->tile_addrs[pos].bits.invalid = 1; 629 } 630 tc->last_tile_addr.bits.invalid = 1; 631} 632