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_context.h"
39 #include "sp_surface.h"
40 #include "sp_texture.h"
41 #include "sp_tile_cache.h"
43 #define NUM_ENTRIES 50
47 #define MAX_WIDTH 4096
48 #define MAX_HEIGHT 4096
51 struct softpipe_tile_cache
53 struct pipe_screen
*screen
;
54 struct pipe_surface
*surface
; /**< the surface we're caching */
55 struct pipe_transfer
*transfer
;
57 struct pipe_texture
*texture
; /**< if caching a texture */
58 struct softpipe_cached_tile entries
[NUM_ENTRIES
];
59 uint clear_flags
[(MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32];
60 float clear_color
[4]; /**< for color bufs */
61 uint clear_val
; /**< for z+stencil, or packed color clear value */
62 boolean depth_stencil
; /**< Is the surface a depth/stencil format? */
64 struct pipe_transfer
*tex_trans
;
66 int tex_face
, tex_level
, tex_z
;
68 struct softpipe_cached_tile tile
; /**< scratch tile for clears */
73 * Return the position in the cache for the tile that contains win pos (x,y).
74 * We currently use a direct mapped cache so this is like a hack key.
75 * At some point we should investige something more sophisticated, like
76 * a LRU replacement policy.
78 #define CACHE_POS(x, y) \
79 (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
84 * Is the tile at (x,y) in cleared state?
87 is_clear_flag_set(const uint
*bitvec
, int x
, int y
)
92 pos
= y
* (MAX_WIDTH
/ TILE_SIZE
) + x
;
93 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
94 bit
= bitvec
[pos
/ 32] & (1 << (pos
& 31));
100 * Mark the tile at (x,y) as not cleared.
103 clear_clear_flag(uint
*bitvec
, int x
, int y
)
108 pos
= y
* (MAX_WIDTH
/ TILE_SIZE
) + x
;
109 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
110 bitvec
[pos
/ 32] &= ~(1 << (pos
& 31));
114 struct softpipe_tile_cache
*
115 sp_create_tile_cache( struct pipe_screen
*screen
)
117 struct softpipe_tile_cache
*tc
;
119 int maxLevels
, maxTexSize
;
121 /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
122 maxLevels
= screen
->get_param(screen
, PIPE_CAP_MAX_TEXTURE_2D_LEVELS
);
123 maxTexSize
= 1 << (maxLevels
- 1);
124 assert(MAX_WIDTH
>= maxTexSize
);
126 tc
= CALLOC_STRUCT( softpipe_tile_cache
);
129 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
131 tc
->entries
[pos
].y
= -1;
134 /* XXX this code prevents valgrind warnings about use of uninitialized
135 * memory in programs that don't clear the surface before rendering.
136 * However, it breaks clearing in other situations (such as in
137 * progs/tests/drawbuffers, see bug 24402).
139 #if 0 && TILE_CLEAR_OPTIMIZATION
140 /* set flags to indicate all the tiles are cleared */
141 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
149 sp_destroy_tile_cache(struct softpipe_tile_cache
*tc
)
151 struct pipe_screen
*screen
;
154 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
155 /*assert(tc->entries[pos].x < 0);*/
158 screen
= tc
->transfer
->texture
->screen
;
159 screen
->tex_transfer_destroy(tc
->transfer
);
162 screen
= tc
->tex_trans
->texture
->screen
;
163 screen
->tex_transfer_destroy(tc
->tex_trans
);
171 * Specify the surface to cache.
174 sp_tile_cache_set_surface(struct softpipe_tile_cache
*tc
,
175 struct pipe_surface
*ps
)
177 assert(!tc
->texture
);
180 struct pipe_screen
*screen
= tc
->transfer
->texture
->screen
;
182 if (ps
== tc
->surface
)
185 if (tc
->transfer_map
) {
186 screen
->transfer_unmap(screen
, tc
->transfer
);
187 tc
->transfer_map
= NULL
;
190 screen
->tex_transfer_destroy(tc
->transfer
);
197 struct pipe_screen
*screen
= ps
->texture
->screen
;
199 tc
->transfer
= screen
->get_tex_transfer(screen
, ps
->texture
, ps
->face
,
200 ps
->level
, ps
->zslice
,
201 PIPE_TRANSFER_READ_WRITE
,
202 0, 0, ps
->width
, ps
->height
);
204 tc
->depth_stencil
= (ps
->format
== PIPE_FORMAT_S8Z24_UNORM
||
205 ps
->format
== PIPE_FORMAT_X8Z24_UNORM
||
206 ps
->format
== PIPE_FORMAT_Z24S8_UNORM
||
207 ps
->format
== PIPE_FORMAT_Z24X8_UNORM
||
208 ps
->format
== PIPE_FORMAT_Z16_UNORM
||
209 ps
->format
== PIPE_FORMAT_Z32_UNORM
||
210 ps
->format
== PIPE_FORMAT_S8_UNORM
);
216 * Return the transfer being cached.
218 struct pipe_surface
*
219 sp_tile_cache_get_surface(struct softpipe_tile_cache
*tc
)
226 sp_tile_cache_map_transfers(struct softpipe_tile_cache
*tc
)
228 if (tc
->transfer
&& !tc
->transfer_map
)
229 tc
->transfer_map
= tc
->screen
->transfer_map(tc
->screen
, tc
->transfer
);
231 if (tc
->tex_trans
&& !tc
->tex_trans_map
)
232 tc
->tex_trans_map
= tc
->screen
->transfer_map(tc
->screen
, tc
->tex_trans
);
237 sp_tile_cache_unmap_transfers(struct softpipe_tile_cache
*tc
)
239 if (tc
->transfer_map
) {
240 tc
->screen
->transfer_unmap(tc
->screen
, tc
->transfer
);
241 tc
->transfer_map
= NULL
;
244 if (tc
->tex_trans_map
) {
245 tc
->screen
->transfer_unmap(tc
->screen
, tc
->tex_trans
);
246 tc
->tex_trans_map
= NULL
;
252 * Specify the texture to cache.
255 sp_tile_cache_set_texture(struct pipe_context
*pipe
,
256 struct softpipe_tile_cache
*tc
,
257 struct pipe_texture
*texture
)
261 assert(!tc
->transfer
);
263 pipe_texture_reference(&tc
->texture
, texture
);
266 struct pipe_screen
*screen
= tc
->tex_trans
->texture
->screen
;
268 if (tc
->tex_trans_map
) {
269 screen
->transfer_unmap(screen
, tc
->tex_trans
);
270 tc
->tex_trans_map
= NULL
;
273 screen
->tex_transfer_destroy(tc
->tex_trans
);
274 tc
->tex_trans
= NULL
;
277 /* mark as entries as invalid/empty */
278 /* XXX we should try to avoid this when the teximage hasn't changed */
279 for (i
= 0; i
< NUM_ENTRIES
; i
++) {
280 tc
->entries
[i
].x
= -1;
283 tc
->tex_face
= -1; /* any invalid value here */
288 * Set pixels in a tile to the given clear color/value, float.
291 clear_tile_rgba(struct softpipe_cached_tile
*tile
,
292 enum pipe_format format
,
293 const float clear_value
[4])
295 if (clear_value
[0] == 0.0 &&
296 clear_value
[1] == 0.0 &&
297 clear_value
[2] == 0.0 &&
298 clear_value
[3] == 0.0) {
299 memset(tile
->data
.color
, 0, sizeof(tile
->data
.color
));
303 for (i
= 0; i
< TILE_SIZE
; i
++) {
304 for (j
= 0; j
< TILE_SIZE
; j
++) {
305 tile
->data
.color
[i
][j
][0] = clear_value
[0];
306 tile
->data
.color
[i
][j
][1] = clear_value
[1];
307 tile
->data
.color
[i
][j
][2] = clear_value
[2];
308 tile
->data
.color
[i
][j
][3] = clear_value
[3];
316 * Set a tile to a solid value/color.
319 clear_tile(struct softpipe_cached_tile
*tile
,
320 enum pipe_format format
,
325 switch (pf_get_size(format
)) {
327 memset(tile
->data
.any
, 0, TILE_SIZE
* TILE_SIZE
);
330 if (clear_value
== 0) {
331 memset(tile
->data
.any
, 0, 2 * TILE_SIZE
* TILE_SIZE
);
334 for (i
= 0; i
< TILE_SIZE
; i
++) {
335 for (j
= 0; j
< TILE_SIZE
; j
++) {
336 tile
->data
.depth16
[i
][j
] = (ushort
) clear_value
;
342 if (clear_value
== 0) {
343 memset(tile
->data
.any
, 0, 4 * TILE_SIZE
* TILE_SIZE
);
346 for (i
= 0; i
< TILE_SIZE
; i
++) {
347 for (j
= 0; j
< TILE_SIZE
; j
++) {
348 tile
->data
.color32
[i
][j
] = clear_value
;
360 * Actually clear the tiles which were flagged as being in a clear state.
363 sp_tile_cache_flush_clear(struct pipe_context
*pipe
,
364 struct softpipe_tile_cache
*tc
)
366 struct pipe_transfer
*pt
= tc
->transfer
;
367 const uint w
= tc
->transfer
->width
;
368 const uint h
= tc
->transfer
->height
;
372 /* clear the scratch tile to the clear value */
373 clear_tile(&tc
->tile
, pt
->format
, tc
->clear_val
);
375 /* push the tile to all positions marked as clear */
376 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
377 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
378 if (is_clear_flag_set(tc
->clear_flags
, x
, y
)) {
379 pipe_put_tile_raw(pt
,
380 x
, y
, TILE_SIZE
, TILE_SIZE
,
381 tc
->tile
.data
.color32
, 0/*STRIDE*/);
384 clear_clear_flag(tc
->clear_flags
, x
, y
);
391 debug_printf("num cleared: %u\n", numCleared
);
397 * Flush the tile cache: write all dirty tiles back to the transfer.
398 * any tiles "flagged" as cleared will be "really" cleared.
401 sp_flush_tile_cache(struct softpipe_context
*softpipe
,
402 struct softpipe_tile_cache
*tc
)
404 struct pipe_transfer
*pt
= tc
->transfer
;
408 /* caching a drawing transfer */
409 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
410 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
412 if (tc
->depth_stencil
) {
413 pipe_put_tile_raw(pt
,
414 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
415 tile
->data
.depth32
, 0/*STRIDE*/);
418 pipe_put_tile_rgba(pt
,
419 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
420 (float *) tile
->data
.color
);
422 tile
->x
= tile
->y
= -1; /* mark as empty */
427 #if TILE_CLEAR_OPTIMIZATION
428 sp_tile_cache_flush_clear(&softpipe
->pipe
, tc
);
431 else if (tc
->texture
) {
432 /* caching a texture, mark all entries as empty */
433 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
434 tc
->entries
[pos
].x
= -1;
440 debug_printf("flushed tiles in use: %d\n", inuse
);
446 * Get a tile from the cache.
447 * \param x, y position of tile, in pixels
449 struct softpipe_cached_tile
*
450 sp_get_cached_tile(struct softpipe_context
*softpipe
,
451 struct softpipe_tile_cache
*tc
, int x
, int y
)
453 struct pipe_transfer
*pt
= tc
->transfer
;
455 /* tile pos in framebuffer: */
456 const int tile_x
= x
& ~(TILE_SIZE
- 1);
457 const int tile_y
= y
& ~(TILE_SIZE
- 1);
459 /* cache pos/entry: */
460 const int pos
= CACHE_POS(x
, y
);
461 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
463 if (tile_x
!= tile
->x
||
467 /* put dirty tile back in framebuffer */
468 if (tc
->depth_stencil
) {
469 pipe_put_tile_raw(pt
,
470 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
471 tile
->data
.depth32
, 0/*STRIDE*/);
474 pipe_put_tile_rgba(pt
,
475 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
476 (float *) tile
->data
.color
);
483 if (is_clear_flag_set(tc
->clear_flags
, x
, y
)) {
484 /* don't get tile from framebuffer, just clear it */
485 if (tc
->depth_stencil
) {
486 clear_tile(tile
, pt
->format
, tc
->clear_val
);
489 clear_tile_rgba(tile
, pt
->format
, tc
->clear_color
);
491 clear_clear_flag(tc
->clear_flags
, x
, y
);
494 /* get new tile data from transfer */
495 if (tc
->depth_stencil
) {
496 pipe_get_tile_raw(pt
,
497 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
498 tile
->data
.depth32
, 0/*STRIDE*/);
501 pipe_get_tile_rgba(pt
,
502 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
503 (float *) tile
->data
.color
);
513 * Given the texture face, level, zslice, x and y values, compute
514 * the cache entry position/index where we'd hope to find the
515 * cached texture tile.
516 * This is basically a direct-map cache.
517 * XXX There's probably lots of ways in which we can improve this.
520 tex_cache_pos(int x
, int y
, int z
, int face
, int level
)
522 uint entry
= x
+ y
* 9 + z
* 3 + face
+ level
* 7;
523 return entry
% NUM_ENTRIES
;
528 * Similar to sp_get_cached_tile() but for textures.
529 * Tiles are read-only and indexed with more params.
531 const struct softpipe_cached_tile
*
532 sp_get_cached_tile_tex(struct softpipe_context
*sp
,
533 struct softpipe_tile_cache
*tc
, int x
, int y
, int z
,
536 struct pipe_screen
*screen
= sp
->pipe
.screen
;
537 /* tile pos in framebuffer: */
538 const int tile_x
= x
& ~(TILE_SIZE
- 1);
539 const int tile_y
= y
& ~(TILE_SIZE
- 1);
540 /* cache pos/entry: */
541 const uint pos
= tex_cache_pos(x
/ TILE_SIZE
, y
/ TILE_SIZE
, z
,
543 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
546 struct softpipe_texture
*spt
= softpipe_texture(tc
->texture
);
548 /* texture was modified, invalidate all cached tiles */
550 for (p
= 0; p
< NUM_ENTRIES
; p
++) {
551 tile
= tc
->entries
+ p
;
554 spt
->modified
= FALSE
;
558 if (tile_x
!= tile
->x
||
561 face
!= tile
->face
||
562 level
!= tile
->level
) {
566 printf("miss at %u x=%d y=%d z=%d face=%d level=%d\n", pos
,
567 x
/TILE_SIZE
, y
/TILE_SIZE
, z
, face
, level
);
569 /* check if we need to get a new transfer */
570 if (!tc
->tex_trans
||
571 tc
->tex_face
!= face
||
572 tc
->tex_level
!= level
||
574 /* get new transfer (view into texture) */
577 if (tc
->tex_trans_map
) {
578 tc
->screen
->transfer_unmap(tc
->screen
, tc
->tex_trans
);
579 tc
->tex_trans_map
= NULL
;
582 screen
->tex_transfer_destroy(tc
->tex_trans
);
583 tc
->tex_trans
= NULL
;
586 tc
->tex_trans
= screen
->get_tex_transfer(screen
, tc
->texture
, face
, level
, z
,
587 PIPE_TRANSFER_READ
, 0, 0,
588 tc
->texture
->width
[level
],
589 tc
->texture
->height
[level
]);
590 tc
->tex_trans_map
= screen
->transfer_map(screen
, tc
->tex_trans
);
593 tc
->tex_level
= level
;
597 /* get tile from the transfer (view into texture) */
598 pipe_get_tile_rgba(tc
->tex_trans
,
599 tile_x
, tile_y
, TILE_SIZE
, TILE_SIZE
,
600 (float *) tile
->data
.color
);
613 * When a whole surface is being cleared to a value we can avoid
614 * fetching tiles above.
615 * Save the color and set a 'clearflag' for each tile of the screen.
618 sp_tile_cache_clear(struct softpipe_tile_cache
*tc
, const float *rgba
,
623 tc
->clear_color
[0] = rgba
[0];
624 tc
->clear_color
[1] = rgba
[1];
625 tc
->clear_color
[2] = rgba
[2];
626 tc
->clear_color
[3] = rgba
[3];
628 tc
->clear_val
= clearValue
;
630 #if TILE_CLEAR_OPTIMIZATION
631 /* set flags to indicate all the tiles are cleared */
632 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
634 /* disable the optimization */
635 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));
638 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
639 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
640 tile
->x
= tile
->y
= -1;