sp_tile_cache.c revision b1ed72ebe2599ec178f51d86fd42f26486b9a19b
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 "pipe/p_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 41 42 43/** 44 * Return the position in the cache for the tile that contains win pos (x,y). 45 * We currently use a direct mapped cache so this is like a hack key. 46 * At some point we should investige something more sophisticated, like 47 * a LRU replacement policy. 48 */ 49#define CACHE_POS(x, y) \ 50 (((x) + (y) * 5) % NUM_ENTRIES) 51 52 53 54/** 55 * Is the tile at (x,y) in cleared state? 56 */ 57static INLINE uint 58is_clear_flag_set(const uint *bitvec, union tile_address addr) 59{ 60 int pos, bit; 61 pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x; 62 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32); 63 bit = bitvec[pos / 32] & (1 << (pos & 31)); 64 return bit; 65} 66 67 68/** 69 * Mark the tile at (x,y) as not cleared. 70 */ 71static INLINE void 72clear_clear_flag(uint *bitvec, union tile_address addr) 73{ 74 int pos; 75 pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x; 76 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32); 77 bitvec[pos / 32] &= ~(1 << (pos & 31)); 78} 79 80 81struct softpipe_tile_cache * 82sp_create_tile_cache( struct pipe_screen *screen ) 83{ 84 struct softpipe_tile_cache *tc; 85 uint pos; 86 int maxLevels, maxTexSize; 87 88 /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */ 89 maxLevels = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); 90 maxTexSize = 1 << (maxLevels - 1); 91 assert(MAX_WIDTH >= maxTexSize); 92 93 tc = CALLOC_STRUCT( softpipe_tile_cache ); 94 if (tc) { 95 tc->screen = screen; 96 for (pos = 0; pos < NUM_ENTRIES; pos++) { 97 tc->entries[pos].addr.bits.invalid = 1; 98 } 99 tc->last_tile = &tc->entries[0]; /* any tile */ 100 101 /* XXX this code prevents valgrind warnings about use of uninitialized 102 * memory in programs that don't clear the surface before rendering. 103 * However, it breaks clearing in other situations (such as in 104 * progs/tests/drawbuffers, see bug 24402). 105 */ 106#if 0 && TILE_CLEAR_OPTIMIZATION 107 /* set flags to indicate all the tiles are cleared */ 108 memset(tc->clear_flags, 255, sizeof(tc->clear_flags)); 109#endif 110 } 111 return tc; 112} 113 114 115void 116sp_destroy_tile_cache(struct softpipe_tile_cache *tc) 117{ 118 struct pipe_screen *screen; 119 uint pos; 120 121 for (pos = 0; pos < NUM_ENTRIES; pos++) { 122 /*assert(tc->entries[pos].x < 0);*/ 123 } 124 if (tc->transfer) { 125 screen = tc->transfer->texture->screen; 126 screen->tex_transfer_destroy(tc->transfer); 127 } 128 129 FREE( tc ); 130} 131 132 133/** 134 * Specify the surface to cache. 135 */ 136void 137sp_tile_cache_set_surface(struct softpipe_tile_cache *tc, 138 struct pipe_surface *ps) 139{ 140 if (tc->transfer) { 141 struct pipe_screen *screen = tc->transfer->texture->screen; 142 143 if (ps == tc->surface) 144 return; 145 146 if (tc->transfer_map) { 147 screen->transfer_unmap(screen, tc->transfer); 148 tc->transfer_map = NULL; 149 } 150 151 screen->tex_transfer_destroy(tc->transfer); 152 tc->transfer = NULL; 153 } 154 155 tc->surface = ps; 156 157 if (ps) { 158 struct pipe_screen *screen = ps->texture->screen; 159 160 tc->transfer = screen->get_tex_transfer(screen, ps->texture, ps->face, 161 ps->level, ps->zslice, 162 PIPE_TRANSFER_READ_WRITE, 163 0, 0, ps->width, ps->height); 164 165 tc->depth_stencil = (ps->format == PIPE_FORMAT_S8Z24_UNORM || 166 ps->format == PIPE_FORMAT_X8Z24_UNORM || 167 ps->format == PIPE_FORMAT_Z24S8_UNORM || 168 ps->format == PIPE_FORMAT_Z24X8_UNORM || 169 ps->format == PIPE_FORMAT_Z16_UNORM || 170 ps->format == PIPE_FORMAT_Z32_UNORM || 171 ps->format == PIPE_FORMAT_S8_UNORM); 172 } 173} 174 175 176/** 177 * Return the transfer being cached. 178 */ 179struct pipe_surface * 180sp_tile_cache_get_surface(struct softpipe_tile_cache *tc) 181{ 182 return tc->surface; 183} 184 185 186void 187sp_tile_cache_map_transfers(struct softpipe_tile_cache *tc) 188{ 189 if (tc->transfer && !tc->transfer_map) 190 tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer); 191} 192 193 194void 195sp_tile_cache_unmap_transfers(struct softpipe_tile_cache *tc) 196{ 197 if (tc->transfer_map) { 198 tc->screen->transfer_unmap(tc->screen, tc->transfer); 199 tc->transfer_map = NULL; 200 } 201} 202 203 204/** 205 * Set pixels in a tile to the given clear color/value, float. 206 */ 207static void 208clear_tile_rgba(struct softpipe_cached_tile *tile, 209 enum pipe_format format, 210 const float clear_value[4]) 211{ 212 if (clear_value[0] == 0.0 && 213 clear_value[1] == 0.0 && 214 clear_value[2] == 0.0 && 215 clear_value[3] == 0.0) { 216 memset(tile->data.color, 0, sizeof(tile->data.color)); 217 } 218 else { 219 uint i, j; 220 for (i = 0; i < TILE_SIZE; i++) { 221 for (j = 0; j < TILE_SIZE; j++) { 222 tile->data.color[i][j][0] = clear_value[0]; 223 tile->data.color[i][j][1] = clear_value[1]; 224 tile->data.color[i][j][2] = clear_value[2]; 225 tile->data.color[i][j][3] = clear_value[3]; 226 } 227 } 228 } 229} 230 231 232/** 233 * Set a tile to a solid value/color. 234 */ 235static void 236clear_tile(struct softpipe_cached_tile *tile, 237 enum pipe_format format, 238 uint clear_value) 239{ 240 uint i, j; 241 242 switch (util_format_get_blocksize(format)) { 243 case 1: 244 memset(tile->data.any, clear_value, TILE_SIZE * TILE_SIZE); 245 break; 246 case 2: 247 if (clear_value == 0) { 248 memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE); 249 } 250 else { 251 for (i = 0; i < TILE_SIZE; i++) { 252 for (j = 0; j < TILE_SIZE; j++) { 253 tile->data.depth16[i][j] = (ushort) clear_value; 254 } 255 } 256 } 257 break; 258 case 4: 259 if (clear_value == 0) { 260 memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE); 261 } 262 else { 263 for (i = 0; i < TILE_SIZE; i++) { 264 for (j = 0; j < TILE_SIZE; j++) { 265 tile->data.color32[i][j] = clear_value; 266 } 267 } 268 } 269 break; 270 default: 271 assert(0); 272 } 273} 274 275 276/** 277 * Actually clear the tiles which were flagged as being in a clear state. 278 */ 279static void 280sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc) 281{ 282 struct pipe_transfer *pt = tc->transfer; 283 const uint w = tc->transfer->width; 284 const uint h = tc->transfer->height; 285 uint x, y; 286 uint numCleared = 0; 287 288 assert(pt->texture); 289 /* clear the scratch tile to the clear value */ 290 clear_tile(&tc->tile, pt->texture->format, tc->clear_val); 291 292 /* push the tile to all positions marked as clear */ 293 for (y = 0; y < h; y += TILE_SIZE) { 294 for (x = 0; x < w; x += TILE_SIZE) { 295 union tile_address addr = tile_address(x, y); 296 297 if (is_clear_flag_set(tc->clear_flags, addr)) { 298 pipe_put_tile_raw(pt, 299 x, y, TILE_SIZE, TILE_SIZE, 300 tc->tile.data.color32, 0/*STRIDE*/); 301 302 /* do this? */ 303 clear_clear_flag(tc->clear_flags, addr); 304 305 numCleared++; 306 } 307 } 308 } 309#if 0 310 debug_printf("num cleared: %u\n", numCleared); 311#endif 312} 313 314 315/** 316 * Flush the tile cache: write all dirty tiles back to the transfer. 317 * any tiles "flagged" as cleared will be "really" cleared. 318 */ 319void 320sp_flush_tile_cache(struct softpipe_tile_cache *tc) 321{ 322 struct pipe_transfer *pt = tc->transfer; 323 int inuse = 0, pos; 324 325 if (pt) { 326 /* caching a drawing transfer */ 327 for (pos = 0; pos < NUM_ENTRIES; pos++) { 328 struct softpipe_cached_tile *tile = tc->entries + pos; 329 if (!tile->addr.bits.invalid) { 330 if (tc->depth_stencil) { 331 pipe_put_tile_raw(pt, 332 tile->addr.bits.x * TILE_SIZE, 333 tile->addr.bits.y * TILE_SIZE, 334 TILE_SIZE, TILE_SIZE, 335 tile->data.depth32, 0/*STRIDE*/); 336 } 337 else { 338 pipe_put_tile_rgba(pt, 339 tile->addr.bits.x * TILE_SIZE, 340 tile->addr.bits.y * TILE_SIZE, 341 TILE_SIZE, TILE_SIZE, 342 (float *) tile->data.color); 343 } 344 tile->addr.bits.invalid = 1; /* mark as empty */ 345 inuse++; 346 } 347 } 348 349#if TILE_CLEAR_OPTIMIZATION 350 sp_tile_cache_flush_clear(tc); 351#endif 352 } 353 354#if 0 355 debug_printf("flushed tiles in use: %d\n", inuse); 356#endif 357} 358 359 360/** 361 * Get a tile from the cache. 362 * \param x, y position of tile, in pixels 363 */ 364struct softpipe_cached_tile * 365sp_find_cached_tile(struct softpipe_tile_cache *tc, 366 union tile_address addr ) 367{ 368 struct pipe_transfer *pt = tc->transfer; 369 370 /* cache pos/entry: */ 371 const int pos = CACHE_POS(addr.bits.x, 372 addr.bits.y); 373 struct softpipe_cached_tile *tile = tc->entries + pos; 374 375 if (addr.value != tile->addr.value) { 376 377 assert(pt->texture); 378 if (tile->addr.bits.invalid == 0) { 379 /* put dirty tile back in framebuffer */ 380 if (tc->depth_stencil) { 381 pipe_put_tile_raw(pt, 382 tile->addr.bits.x * TILE_SIZE, 383 tile->addr.bits.y * TILE_SIZE, 384 TILE_SIZE, TILE_SIZE, 385 tile->data.depth32, 0/*STRIDE*/); 386 } 387 else { 388 pipe_put_tile_rgba(pt, 389 tile->addr.bits.x * TILE_SIZE, 390 tile->addr.bits.y * TILE_SIZE, 391 TILE_SIZE, TILE_SIZE, 392 (float *) tile->data.color); 393 } 394 } 395 396 tile->addr = addr; 397 398 if (is_clear_flag_set(tc->clear_flags, addr)) { 399 /* don't get tile from framebuffer, just clear it */ 400 if (tc->depth_stencil) { 401 clear_tile(tile, pt->texture->format, tc->clear_val); 402 } 403 else { 404 clear_tile_rgba(tile, pt->texture->format, tc->clear_color); 405 } 406 clear_clear_flag(tc->clear_flags, addr); 407 } 408 else { 409 /* get new tile data from transfer */ 410 if (tc->depth_stencil) { 411 pipe_get_tile_raw(pt, 412 tile->addr.bits.x * TILE_SIZE, 413 tile->addr.bits.y * TILE_SIZE, 414 TILE_SIZE, TILE_SIZE, 415 tile->data.depth32, 0/*STRIDE*/); 416 } 417 else { 418 pipe_get_tile_rgba(pt, 419 tile->addr.bits.x * TILE_SIZE, 420 tile->addr.bits.y * TILE_SIZE, 421 TILE_SIZE, TILE_SIZE, 422 (float *) tile->data.color); 423 } 424 } 425 } 426 427 tc->last_tile = tile; 428 return tile; 429} 430 431 432 433 434 435/** 436 * When a whole surface is being cleared to a value we can avoid 437 * fetching tiles above. 438 * Save the color and set a 'clearflag' for each tile of the screen. 439 */ 440void 441sp_tile_cache_clear(struct softpipe_tile_cache *tc, const float *rgba, 442 uint clearValue) 443{ 444 uint pos; 445 446 tc->clear_color[0] = rgba[0]; 447 tc->clear_color[1] = rgba[1]; 448 tc->clear_color[2] = rgba[2]; 449 tc->clear_color[3] = rgba[3]; 450 451 tc->clear_val = clearValue; 452 453#if TILE_CLEAR_OPTIMIZATION 454 /* set flags to indicate all the tiles are cleared */ 455 memset(tc->clear_flags, 255, sizeof(tc->clear_flags)); 456#else 457 /* disable the optimization */ 458 memset(tc->clear_flags, 0, sizeof(tc->clear_flags)); 459#endif 460 461 for (pos = 0; pos < NUM_ENTRIES; pos++) { 462 struct softpipe_cached_tile *tile = tc->entries + pos; 463 tile->addr.bits.invalid = 1; 464 } 465} 466