1 /**************************************************************************
3 * Copyright 2007 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 * Texture tile caching.
35 #include "pipe/p_inlines.h"
36 #include "util/u_memory.h"
37 #include "util/u_tile.h"
38 #include "sp_tile_cache.h"
43 * Return the position in the cache for the tile that contains win pos (x,y).
44 * We currently use a direct mapped cache so this is like a hack key.
45 * At some point we should investige something more sophisticated, like
46 * a LRU replacement policy.
48 #define CACHE_POS(x, y) \
49 (((x) + (y) * 5) % NUM_ENTRIES)
54 * Is the tile at (x,y) in cleared state?
57 is_clear_flag_set(const uint
*bitvec
, union tile_address addr
)
60 pos
= addr
.bits
.y
* (MAX_WIDTH
/ TILE_SIZE
) + addr
.bits
.x
;
61 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
62 bit
= bitvec
[pos
/ 32] & (1 << (pos
& 31));
68 * Mark the tile at (x,y) as not cleared.
71 clear_clear_flag(uint
*bitvec
, union tile_address addr
)
74 pos
= addr
.bits
.y
* (MAX_WIDTH
/ TILE_SIZE
) + addr
.bits
.x
;
75 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
76 bitvec
[pos
/ 32] &= ~(1 << (pos
& 31));
80 struct softpipe_tile_cache
*
81 sp_create_tile_cache( struct pipe_screen
*screen
)
83 struct softpipe_tile_cache
*tc
;
86 tc
= CALLOC_STRUCT( softpipe_tile_cache
);
89 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
90 tc
->entries
[pos
].addr
.bits
.invalid
= 1;
92 tc
->last_tile
= &tc
->entries
[0]; /* any tile */
99 sp_destroy_tile_cache(struct softpipe_tile_cache
*tc
)
101 struct pipe_screen
*screen
;
104 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
105 /*assert(tc->entries[pos].x < 0);*/
108 screen
= tc
->transfer
->texture
->screen
;
109 screen
->tex_transfer_destroy(tc
->transfer
);
112 screen
= tc
->tex_trans
->texture
->screen
;
113 screen
->tex_transfer_destroy(tc
->tex_trans
);
121 * Specify the surface to cache.
124 sp_tile_cache_set_surface(struct softpipe_tile_cache
*tc
,
125 struct pipe_surface
*ps
)
127 assert(!tc
->texture
);
130 struct pipe_screen
*screen
= tc
->transfer
->texture
->screen
;
132 if (ps
== tc
->surface
)
135 if (tc
->transfer_map
) {
136 screen
->transfer_unmap(screen
, tc
->transfer
);
137 tc
->transfer_map
= NULL
;
140 screen
->tex_transfer_destroy(tc
->transfer
);
147 struct pipe_screen
*screen
= ps
->texture
->screen
;
149 tc
->transfer
= screen
->get_tex_transfer(screen
, ps
->texture
, ps
->face
,
150 ps
->level
, ps
->zslice
,
151 PIPE_TRANSFER_READ_WRITE
,
152 0, 0, ps
->width
, ps
->height
);
154 tc
->depth_stencil
= (ps
->format
== PIPE_FORMAT_S8Z24_UNORM
||
155 ps
->format
== PIPE_FORMAT_X8Z24_UNORM
||
156 ps
->format
== PIPE_FORMAT_Z24S8_UNORM
||
157 ps
->format
== PIPE_FORMAT_Z24X8_UNORM
||
158 ps
->format
== PIPE_FORMAT_Z16_UNORM
||
159 ps
->format
== PIPE_FORMAT_Z32_UNORM
||
160 ps
->format
== PIPE_FORMAT_S8_UNORM
);
166 * Return the transfer being cached.
168 struct pipe_surface
*
169 sp_tile_cache_get_surface(struct softpipe_tile_cache
*tc
)
176 sp_tile_cache_map_transfers(struct softpipe_tile_cache
*tc
)
178 if (tc
->transfer
&& !tc
->transfer_map
)
179 tc
->transfer_map
= tc
->screen
->transfer_map(tc
->screen
, tc
->transfer
);
181 if (tc
->tex_trans
&& !tc
->tex_trans_map
)
182 tc
->tex_trans_map
= tc
->screen
->transfer_map(tc
->screen
, tc
->tex_trans
);
187 sp_tile_cache_unmap_transfers(struct softpipe_tile_cache
*tc
)
189 if (tc
->transfer_map
) {
190 tc
->screen
->transfer_unmap(tc
->screen
, tc
->transfer
);
191 tc
->transfer_map
= NULL
;
194 if (tc
->tex_trans_map
) {
195 tc
->screen
->transfer_unmap(tc
->screen
, tc
->tex_trans
);
196 tc
->tex_trans_map
= NULL
;
202 * Invalidate all cached tiles for the cached texture.
203 * Should be called when the texture is modified.
206 sp_tile_cache_validate_texture(struct softpipe_tile_cache
*tc
)
213 for (i
= 0; i
< NUM_ENTRIES
; i
++) {
214 tc
->entries
[i
].addr
.bits
.invalid
= 1;
220 * Specify the texture to cache.
223 sp_tile_cache_set_texture(struct softpipe_tile_cache
*tc
,
224 struct pipe_texture
*texture
)
228 assert(!tc
->transfer
);
230 if (tc
->texture
!= texture
) {
231 pipe_texture_reference(&tc
->texture
, texture
);
234 struct pipe_screen
*screen
= tc
->tex_trans
->texture
->screen
;
236 if (tc
->tex_trans_map
) {
237 screen
->transfer_unmap(screen
, tc
->tex_trans
);
238 tc
->tex_trans_map
= NULL
;
241 screen
->tex_transfer_destroy(tc
->tex_trans
);
242 tc
->tex_trans
= NULL
;
245 /* mark as entries as invalid/empty */
246 /* XXX we should try to avoid this when the teximage hasn't changed */
247 for (i
= 0; i
< NUM_ENTRIES
; i
++) {
248 tc
->entries
[i
].addr
.bits
.invalid
= 1;
251 tc
->tex_face
= -1; /* any invalid value here */
257 * Set pixels in a tile to the given clear color/value, float.
260 clear_tile_rgba(struct softpipe_cached_tile
*tile
,
261 enum pipe_format format
,
262 const float clear_value
[4])
264 if (clear_value
[0] == 0.0 &&
265 clear_value
[1] == 0.0 &&
266 clear_value
[2] == 0.0 &&
267 clear_value
[3] == 0.0) {
268 memset(tile
->data
.color
, 0, sizeof(tile
->data
.color
));
272 for (i
= 0; i
< TILE_SIZE
; i
++) {
273 for (j
= 0; j
< TILE_SIZE
; j
++) {
274 tile
->data
.color
[i
][j
][0] = clear_value
[0];
275 tile
->data
.color
[i
][j
][1] = clear_value
[1];
276 tile
->data
.color
[i
][j
][2] = clear_value
[2];
277 tile
->data
.color
[i
][j
][3] = clear_value
[3];
285 * Set a tile to a solid value/color.
288 clear_tile(struct softpipe_cached_tile
*tile
,
289 enum pipe_format format
,
294 switch (pf_get_size(format
)) {
296 memset(tile
->data
.any
, 0, TILE_SIZE
* TILE_SIZE
);
299 if (clear_value
== 0) {
300 memset(tile
->data
.any
, 0, 2 * TILE_SIZE
* TILE_SIZE
);
303 for (i
= 0; i
< TILE_SIZE
; i
++) {
304 for (j
= 0; j
< TILE_SIZE
; j
++) {
305 tile
->data
.depth16
[i
][j
] = (ushort
) clear_value
;
311 if (clear_value
== 0) {
312 memset(tile
->data
.any
, 0, 4 * TILE_SIZE
* TILE_SIZE
);
315 for (i
= 0; i
< TILE_SIZE
; i
++) {
316 for (j
= 0; j
< TILE_SIZE
; j
++) {
317 tile
->data
.color32
[i
][j
] = clear_value
;
329 * Actually clear the tiles which were flagged as being in a clear state.
332 sp_tile_cache_flush_clear(struct softpipe_tile_cache
*tc
)
334 struct pipe_transfer
*pt
= tc
->transfer
;
335 const uint w
= tc
->transfer
->width
;
336 const uint h
= tc
->transfer
->height
;
340 /* clear the scratch tile to the clear value */
341 clear_tile(&tc
->tile
, pt
->format
, tc
->clear_val
);
343 /* push the tile to all positions marked as clear */
344 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
345 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
346 union tile_address addr
= tile_address(x
, y
, 0, 0, 0);
348 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
349 pipe_put_tile_raw(pt
,
350 x
, y
, TILE_SIZE
, TILE_SIZE
,
351 tc
->tile
.data
.color32
, 0/*STRIDE*/);
354 clear_clear_flag(tc
->clear_flags
, addr
);
361 debug_printf("num cleared: %u\n", numCleared
);
367 * Flush the tile cache: write all dirty tiles back to the transfer.
368 * any tiles "flagged" as cleared will be "really" cleared.
371 sp_flush_tile_cache(struct softpipe_tile_cache
*tc
)
373 struct pipe_transfer
*pt
= tc
->transfer
;
377 /* caching a drawing transfer */
378 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
379 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
380 if (!tile
->addr
.bits
.invalid
) {
381 if (tc
->depth_stencil
) {
382 pipe_put_tile_raw(pt
,
383 tile
->addr
.bits
.x
* TILE_SIZE
,
384 tile
->addr
.bits
.y
* TILE_SIZE
,
385 TILE_SIZE
, TILE_SIZE
,
386 tile
->data
.depth32
, 0/*STRIDE*/);
389 pipe_put_tile_rgba(pt
,
390 tile
->addr
.bits
.x
* TILE_SIZE
,
391 tile
->addr
.bits
.y
* TILE_SIZE
,
392 TILE_SIZE
, TILE_SIZE
,
393 (float *) tile
->data
.color
);
395 tile
->addr
.bits
.invalid
= 1; /* mark as empty */
400 #if TILE_CLEAR_OPTIMIZATION
401 sp_tile_cache_flush_clear(tc
);
404 else if (tc
->texture
) {
405 /* caching a texture, mark all entries as empty */
406 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
407 tc
->entries
[pos
].addr
.bits
.invalid
= 1;
413 debug_printf("flushed tiles in use: %d\n", inuse
);
419 * Get a tile from the cache.
420 * \param x, y position of tile, in pixels
422 struct softpipe_cached_tile
*
423 sp_find_cached_tile(struct softpipe_tile_cache
*tc
,
424 union tile_address addr
)
426 struct pipe_transfer
*pt
= tc
->transfer
;
428 /* cache pos/entry: */
429 const int pos
= CACHE_POS(addr
.bits
.x
,
431 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
433 if (addr
.value
!= tile
->addr
.value
) {
435 if (tile
->addr
.bits
.invalid
== 0) {
436 /* put dirty tile back in framebuffer */
437 if (tc
->depth_stencil
) {
438 pipe_put_tile_raw(pt
,
439 tile
->addr
.bits
.x
* TILE_SIZE
,
440 tile
->addr
.bits
.y
* TILE_SIZE
,
441 TILE_SIZE
, TILE_SIZE
,
442 tile
->data
.depth32
, 0/*STRIDE*/);
445 pipe_put_tile_rgba(pt
,
446 tile
->addr
.bits
.x
* TILE_SIZE
,
447 tile
->addr
.bits
.y
* TILE_SIZE
,
448 TILE_SIZE
, TILE_SIZE
,
449 (float *) tile
->data
.color
);
455 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
456 /* don't get tile from framebuffer, just clear it */
457 if (tc
->depth_stencil
) {
458 clear_tile(tile
, pt
->format
, tc
->clear_val
);
461 clear_tile_rgba(tile
, pt
->format
, tc
->clear_color
);
463 clear_clear_flag(tc
->clear_flags
, addr
);
466 /* get new tile data from transfer */
467 if (tc
->depth_stencil
) {
468 pipe_get_tile_raw(pt
,
469 tile
->addr
.bits
.x
* TILE_SIZE
,
470 tile
->addr
.bits
.y
* TILE_SIZE
,
471 TILE_SIZE
, TILE_SIZE
,
472 tile
->data
.depth32
, 0/*STRIDE*/);
475 pipe_get_tile_rgba(pt
,
476 tile
->addr
.bits
.x
* TILE_SIZE
,
477 tile
->addr
.bits
.y
* TILE_SIZE
,
478 TILE_SIZE
, TILE_SIZE
,
479 (float *) tile
->data
.color
);
484 tc
->last_tile
= tile
;
490 * Given the texture face, level, zslice, x and y values, compute
491 * the cache entry position/index where we'd hope to find the
492 * cached texture tile.
493 * This is basically a direct-map cache.
494 * XXX There's probably lots of ways in which we can improve this.
497 tex_cache_pos( union tile_address addr
)
499 uint entry
= (addr
.bits
.x
+
503 addr
.bits
.level
* 7);
505 return entry
% NUM_ENTRIES
;
509 * Similar to sp_get_cached_tile() but for textures.
510 * Tiles are read-only and indexed with more params.
512 const struct softpipe_cached_tile
*
513 sp_find_cached_tile_tex(struct softpipe_tile_cache
*tc
,
514 union tile_address addr
)
516 struct pipe_screen
*screen
= tc
->screen
;
517 struct softpipe_cached_tile
*tile
;
519 tile
= tc
->entries
+ tex_cache_pos( addr
);
521 if (addr
.value
!= tile
->addr
.value
) {
523 /* cache miss. Most misses are because we've invaldiated the
524 * texture cache previously -- most commonly on binding a new
525 * texture. Currently we effectively flush the cache on texture
529 _debug_printf("miss at %u: x=%d y=%d z=%d face=%d level=%d\n"
530 " tile %u: x=%d y=%d z=%d face=%d level=%d\n",
531 pos
, x
/TILE_SIZE
, y
/TILE_SIZE
, z
, face
, level
,
532 pos
, tile
->addr
.bits
.x
, tile
->addr
.bits
.y
, tile
->z
, tile
->face
, tile
->level
);
535 /* check if we need to get a new transfer */
536 if (!tc
->tex_trans
||
537 tc
->tex_face
!= addr
.bits
.face
||
538 tc
->tex_level
!= addr
.bits
.level
||
539 tc
->tex_z
!= addr
.bits
.z
) {
540 /* get new transfer (view into texture) */
543 if (tc
->tex_trans_map
) {
544 tc
->screen
->transfer_unmap(tc
->screen
, tc
->tex_trans
);
545 tc
->tex_trans_map
= NULL
;
548 screen
->tex_transfer_destroy(tc
->tex_trans
);
549 tc
->tex_trans
= NULL
;
553 screen
->get_tex_transfer(screen
, tc
->texture
,
557 PIPE_TRANSFER_READ
, 0, 0,
558 tc
->texture
->width
[addr
.bits
.level
],
559 tc
->texture
->height
[addr
.bits
.level
]);
561 tc
->tex_trans_map
= screen
->transfer_map(screen
, tc
->tex_trans
);
563 tc
->tex_face
= addr
.bits
.face
;
564 tc
->tex_level
= addr
.bits
.level
;
565 tc
->tex_z
= addr
.bits
.z
;
568 /* get tile from the transfer (view into texture) */
569 pipe_get_tile_rgba(tc
->tex_trans
,
570 addr
.bits
.x
* TILE_SIZE
,
571 addr
.bits
.y
* TILE_SIZE
,
572 TILE_SIZE
, TILE_SIZE
,
573 (float *) tile
->data
.color
);
577 tc
->last_tile
= tile
;
583 * When a whole surface is being cleared to a value we can avoid
584 * fetching tiles above.
585 * Save the color and set a 'clearflag' for each tile of the screen.
588 sp_tile_cache_clear(struct softpipe_tile_cache
*tc
, const float *rgba
,
593 tc
->clear_color
[0] = rgba
[0];
594 tc
->clear_color
[1] = rgba
[1];
595 tc
->clear_color
[2] = rgba
[2];
596 tc
->clear_color
[3] = rgba
[3];
598 tc
->clear_val
= clearValue
;
600 #if TILE_CLEAR_OPTIMIZATION
601 /* set flags to indicate all the tiles are cleared */
602 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
604 /* disable the optimization */
605 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));
608 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
609 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
610 tile
->addr
.bits
.invalid
= 1;