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 "lp_context.h"
39 #include "lp_surface.h"
40 #include "lp_texture.h"
41 #include "lp_tile_soa.h"
42 #include "lp_tile_cache.h"
47 * Return the position in the cache for the tile that contains win pos (x,y).
48 * We currently use a direct mapped cache so this is like a hack key.
49 * At some point we should investige something more sophisticated, like
50 * a LRU replacement policy.
52 #define CACHE_POS(x, y) \
53 (((x) + (y) * 5) % NUM_ENTRIES)
58 * Is the tile at (x,y) in cleared state?
61 is_clear_flag_set(const uint
*bitvec
, union tile_address addr
)
64 pos
= addr
.bits
.y
* (MAX_WIDTH
/ TILE_SIZE
) + addr
.bits
.x
;
65 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
66 bit
= bitvec
[pos
/ 32] & (1 << (pos
& 31));
72 * Mark the tile at (x,y) as not cleared.
75 clear_clear_flag(uint
*bitvec
, union tile_address addr
)
78 pos
= addr
.bits
.y
* (MAX_WIDTH
/ TILE_SIZE
) + addr
.bits
.x
;
79 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
80 bitvec
[pos
/ 32] &= ~(1 << (pos
& 31));
84 struct llvmpipe_tile_cache
*
85 lp_create_tile_cache( struct pipe_screen
*screen
)
87 struct llvmpipe_tile_cache
*tc
;
90 tc
= CALLOC_STRUCT( llvmpipe_tile_cache
);
93 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
94 tc
->entries
[pos
].addr
.bits
.invalid
= 1;
96 tc
->last_tile
= &tc
->entries
[0]; /* any tile */
103 lp_destroy_tile_cache(struct llvmpipe_tile_cache
*tc
)
105 struct pipe_screen
*screen
;
108 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
109 /*assert(tc->entries[pos].x < 0);*/
112 screen
= tc
->transfer
->texture
->screen
;
113 screen
->tex_transfer_destroy(tc
->transfer
);
116 screen
= tc
->tex_trans
->texture
->screen
;
117 screen
->tex_transfer_destroy(tc
->tex_trans
);
125 * Specify the surface to cache.
128 lp_tile_cache_set_surface(struct llvmpipe_tile_cache
*tc
,
129 struct pipe_surface
*ps
)
131 assert(!tc
->texture
);
134 struct pipe_screen
*screen
= tc
->transfer
->texture
->screen
;
136 if (ps
== tc
->surface
)
139 if (tc
->transfer_map
) {
140 screen
->transfer_unmap(screen
, tc
->transfer
);
141 tc
->transfer_map
= NULL
;
144 screen
->tex_transfer_destroy(tc
->transfer
);
151 struct pipe_screen
*screen
= ps
->texture
->screen
;
153 tc
->transfer
= screen
->get_tex_transfer(screen
, ps
->texture
, ps
->face
,
154 ps
->level
, ps
->zslice
,
155 PIPE_TRANSFER_READ_WRITE
,
156 0, 0, ps
->width
, ps
->height
);
158 tc
->depth_stencil
= (ps
->format
== PIPE_FORMAT_S8Z24_UNORM
||
159 ps
->format
== PIPE_FORMAT_X8Z24_UNORM
||
160 ps
->format
== PIPE_FORMAT_Z24S8_UNORM
||
161 ps
->format
== PIPE_FORMAT_Z24X8_UNORM
||
162 ps
->format
== PIPE_FORMAT_Z16_UNORM
||
163 ps
->format
== PIPE_FORMAT_Z32_UNORM
||
164 ps
->format
== PIPE_FORMAT_S8_UNORM
);
170 * Return the transfer being cached.
172 struct pipe_surface
*
173 lp_tile_cache_get_surface(struct llvmpipe_tile_cache
*tc
)
180 lp_tile_cache_map_transfers(struct llvmpipe_tile_cache
*tc
)
182 if (tc
->transfer
&& !tc
->transfer_map
)
183 tc
->transfer_map
= tc
->screen
->transfer_map(tc
->screen
, tc
->transfer
);
185 if (tc
->tex_trans
&& !tc
->tex_trans_map
)
186 tc
->tex_trans_map
= tc
->screen
->transfer_map(tc
->screen
, tc
->tex_trans
);
191 lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache
*tc
)
193 if (tc
->transfer_map
) {
194 tc
->screen
->transfer_unmap(tc
->screen
, tc
->transfer
);
195 tc
->transfer_map
= NULL
;
198 if (tc
->tex_trans_map
) {
199 tc
->screen
->transfer_unmap(tc
->screen
, tc
->tex_trans
);
200 tc
->tex_trans_map
= NULL
;
206 * Set pixels in a tile to the given clear color/value, float.
209 clear_tile_rgba(struct llvmpipe_cached_tile
*tile
,
210 enum pipe_format format
,
211 const float clear_value
[4])
213 if (clear_value
[0] == 0.0 &&
214 clear_value
[1] == 0.0 &&
215 clear_value
[2] == 0.0 &&
216 clear_value
[3] == 0.0) {
217 memset(tile
->data
.color
, 0, sizeof(tile
->data
.color
));
221 for (i
= 0; i
< 4; ++i
)
222 for (y
= 0; y
< TILE_SIZE
; y
++)
223 for (x
= 0; x
< TILE_SIZE
; x
++)
224 tile
->data
.color
[i
][y
][x
] = float_to_ubyte(clear_value
[i
]);
230 * Set a tile to a solid value/color.
233 clear_tile(struct llvmpipe_cached_tile
*tile
,
234 enum pipe_format format
,
239 switch (pf_get_size(format
)) {
241 memset(tile
->data
.any
, 0, TILE_SIZE
* TILE_SIZE
);
244 if (clear_value
== 0) {
245 memset(tile
->data
.any
, 0, 2 * TILE_SIZE
* TILE_SIZE
);
248 for (i
= 0; i
< TILE_SIZE
; i
++) {
249 for (j
= 0; j
< TILE_SIZE
; j
++) {
250 tile
->data
.depth16
[i
][j
] = (ushort
) clear_value
;
256 if (clear_value
== 0) {
257 memset(tile
->data
.any
, 0, 4 * TILE_SIZE
* TILE_SIZE
);
260 for (i
= 0; i
< TILE_SIZE
; i
++) {
261 for (j
= 0; j
< TILE_SIZE
; j
++) {
262 tile
->data
.color32
[i
][j
] = clear_value
;
274 * Actually clear the tiles which were flagged as being in a clear state.
277 lp_tile_cache_flush_clear(struct llvmpipe_tile_cache
*tc
)
279 struct pipe_transfer
*pt
= tc
->transfer
;
280 const uint w
= tc
->transfer
->width
;
281 const uint h
= tc
->transfer
->height
;
285 /* clear the scratch tile to the clear value */
286 clear_tile(&tc
->tile
, pt
->format
, tc
->clear_val
);
288 /* push the tile to all positions marked as clear */
289 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
290 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
291 union tile_address addr
= tile_address(x
, y
, 0, 0, 0);
293 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
294 pipe_put_tile_raw(pt
,
295 x
, y
, TILE_SIZE
, TILE_SIZE
,
296 tc
->tile
.data
.color32
, 0/*STRIDE*/);
299 clear_clear_flag(tc
->clear_flags
, addr
);
306 debug_printf("num cleared: %u\n", numCleared
);
312 * Flush the tile cache: write all dirty tiles back to the transfer.
313 * any tiles "flagged" as cleared will be "really" cleared.
316 lp_flush_tile_cache(struct llvmpipe_tile_cache
*tc
)
318 struct pipe_transfer
*pt
= tc
->transfer
;
322 /* caching a drawing transfer */
323 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
324 struct llvmpipe_cached_tile
*tile
= tc
->entries
+ pos
;
325 if (!tile
->addr
.bits
.invalid
) {
326 if (tc
->depth_stencil
) {
327 pipe_put_tile_raw(pt
,
328 tile
->addr
.bits
.x
* TILE_SIZE
,
329 tile
->addr
.bits
.y
* TILE_SIZE
,
330 TILE_SIZE
, TILE_SIZE
,
331 tile
->data
.depth32
, 0/*STRIDE*/);
334 lp_put_tile_rgba_soa(pt
,
335 tile
->addr
.bits
.x
* TILE_SIZE
,
336 tile
->addr
.bits
.y
* TILE_SIZE
,
339 tile
->addr
.bits
.invalid
= 1; /* mark as empty */
344 #if TILE_CLEAR_OPTIMIZATION
345 lp_tile_cache_flush_clear(tc
);
348 else if (tc
->texture
) {
349 /* caching a texture, mark all entries as empty */
350 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
351 tc
->entries
[pos
].addr
.bits
.invalid
= 1;
357 debug_printf("flushed tiles in use: %d\n", inuse
);
363 * Get a tile from the cache.
364 * \param x, y position of tile, in pixels
366 struct llvmpipe_cached_tile
*
367 lp_find_cached_tile(struct llvmpipe_tile_cache
*tc
,
368 union tile_address addr
)
370 struct pipe_transfer
*pt
= tc
->transfer
;
372 /* cache pos/entry: */
373 const int pos
= CACHE_POS(addr
.bits
.x
,
375 struct llvmpipe_cached_tile
*tile
= tc
->entries
+ pos
;
377 if (addr
.value
!= tile
->addr
.value
) {
379 if (tile
->addr
.bits
.invalid
== 0) {
380 /* put dirty tile back in framebuffer */
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 lp_put_tile_rgba_soa(pt
,
390 tile
->addr
.bits
.x
* TILE_SIZE
,
391 tile
->addr
.bits
.y
* TILE_SIZE
,
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
->format
, tc
->clear_val
);
404 clear_tile_rgba(tile
, pt
->format
, tc
->clear_color
);
406 clear_clear_flag(tc
->clear_flags
, addr
);
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*/);
418 lp_get_tile_rgba_soa(pt
,
419 tile
->addr
.bits
.x
* TILE_SIZE
,
420 tile
->addr
.bits
.y
* TILE_SIZE
,
426 tc
->last_tile
= tile
;
432 * Given the texture face, level, zslice, x and y values, compute
433 * the cache entry position/index where we'd hope to find the
434 * cached texture tile.
435 * This is basically a direct-map cache.
436 * XXX There's probably lots of ways in which we can improve this.
439 tex_cache_pos( union tile_address addr
)
441 uint entry
= (addr
.bits
.x
+
445 addr
.bits
.level
* 7);
447 return entry
% NUM_ENTRIES
;
452 * When a whole surface is being cleared to a value we can avoid
453 * fetching tiles above.
454 * Save the color and set a 'clearflag' for each tile of the screen.
457 lp_tile_cache_clear(struct llvmpipe_tile_cache
*tc
, const float *rgba
,
462 tc
->clear_color
[0] = rgba
[0];
463 tc
->clear_color
[1] = rgba
[1];
464 tc
->clear_color
[2] = rgba
[2];
465 tc
->clear_color
[3] = rgba
[3];
467 tc
->clear_val
= clearValue
;
469 #if TILE_CLEAR_OPTIMIZATION
470 /* set flags to indicate all the tiles are cleared */
471 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
473 /* disable the optimization */
474 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));
477 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
478 struct llvmpipe_cached_tile
*tile
= tc
->entries
+ pos
;
479 tile
->addr
.bits
.invalid
= 1;