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_math.h"
38 #include "util/u_tile.h"
39 #include "lp_context.h"
40 #include "lp_surface.h"
41 #include "lp_texture.h"
42 #include "lp_tile_soa.h"
43 #include "lp_tile_cache.h"
48 * Return the position in the cache for the tile that contains win pos (x,y).
49 * We currently use a direct mapped cache so this is like a hack key.
50 * At some point we should investige something more sophisticated, like
51 * a LRU replacement policy.
53 #define CACHE_POS(x, y) \
54 (((x) + (y) * 5) % NUM_ENTRIES)
59 * Is the tile at (x,y) in cleared state?
62 is_clear_flag_set(const uint
*bitvec
, union tile_address addr
)
65 pos
= addr
.bits
.y
* (MAX_WIDTH
/ TILE_SIZE
) + addr
.bits
.x
;
66 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
67 bit
= bitvec
[pos
/ 32] & (1 << (pos
& 31));
73 * Mark the tile at (x,y) as not cleared.
76 clear_clear_flag(uint
*bitvec
, union tile_address addr
)
79 pos
= addr
.bits
.y
* (MAX_WIDTH
/ TILE_SIZE
) + addr
.bits
.x
;
80 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
81 bitvec
[pos
/ 32] &= ~(1 << (pos
& 31));
85 struct llvmpipe_tile_cache
*
86 lp_create_tile_cache( struct pipe_screen
*screen
)
88 struct llvmpipe_tile_cache
*tc
;
91 tc
= align_malloc( sizeof(struct llvmpipe_tile_cache
), 16 );
93 memset(tc
, 0, sizeof *tc
);
95 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
96 tc
->entries
[pos
].addr
.bits
.invalid
= 1;
98 tc
->last_tile
= &tc
->entries
[0]; /* any tile */
105 lp_destroy_tile_cache(struct llvmpipe_tile_cache
*tc
)
107 struct pipe_screen
*screen
;
110 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
111 /*assert(tc->entries[pos].x < 0);*/
114 screen
= tc
->transfer
->texture
->screen
;
115 screen
->tex_transfer_destroy(tc
->transfer
);
118 screen
= tc
->tex_trans
->texture
->screen
;
119 screen
->tex_transfer_destroy(tc
->tex_trans
);
127 * Specify the surface to cache.
130 lp_tile_cache_set_surface(struct llvmpipe_tile_cache
*tc
,
131 struct pipe_surface
*ps
)
133 assert(!tc
->texture
);
136 struct pipe_screen
*screen
= tc
->transfer
->texture
->screen
;
138 if (ps
== tc
->surface
)
141 if (tc
->transfer_map
) {
142 screen
->transfer_unmap(screen
, tc
->transfer
);
143 tc
->transfer_map
= NULL
;
146 screen
->tex_transfer_destroy(tc
->transfer
);
153 struct pipe_screen
*screen
= ps
->texture
->screen
;
155 tc
->transfer
= screen
->get_tex_transfer(screen
, ps
->texture
, ps
->face
,
156 ps
->level
, ps
->zslice
,
157 PIPE_TRANSFER_READ_WRITE
,
158 0, 0, ps
->width
, ps
->height
);
164 * Return the transfer being cached.
166 struct pipe_surface
*
167 lp_tile_cache_get_surface(struct llvmpipe_tile_cache
*tc
)
174 lp_tile_cache_map_transfers(struct llvmpipe_tile_cache
*tc
)
176 if (tc
->transfer
&& !tc
->transfer_map
)
177 tc
->transfer_map
= tc
->screen
->transfer_map(tc
->screen
, tc
->transfer
);
179 if (tc
->tex_trans
&& !tc
->tex_trans_map
)
180 tc
->tex_trans_map
= tc
->screen
->transfer_map(tc
->screen
, tc
->tex_trans
);
185 lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache
*tc
)
187 if (tc
->transfer_map
) {
188 tc
->screen
->transfer_unmap(tc
->screen
, tc
->transfer
);
189 tc
->transfer_map
= NULL
;
192 if (tc
->tex_trans_map
) {
193 tc
->screen
->transfer_unmap(tc
->screen
, tc
->tex_trans
);
194 tc
->tex_trans_map
= NULL
;
200 * Set pixels in a tile to the given clear color/value, float.
203 clear_tile_rgba(struct llvmpipe_cached_tile
*tile
,
204 enum pipe_format format
,
205 const float clear_value
[4])
207 if (clear_value
[0] == 0.0 &&
208 clear_value
[1] == 0.0 &&
209 clear_value
[2] == 0.0 &&
210 clear_value
[3] == 0.0) {
211 memset(tile
->data
.color
, 0, sizeof(tile
->data
.color
));
216 for (i
= 0; i
< 4; ++i
)
217 c
[i
] = float_to_ubyte(clear_value
[i
]);
218 for (y
= 0; y
< TILE_SIZE
; y
++)
219 for (x
= 0; x
< TILE_SIZE
; x
++)
220 for (i
= 0; i
< 4; ++i
)
221 TILE_PIXEL(tile
->data
.color
, x
, y
, i
) = c
[i
];
227 * Set a tile to a solid value/color.
230 clear_tile(struct llvmpipe_cached_tile
*tile
,
231 enum pipe_format format
,
236 if (clear_value
== 0) {
237 memset(tile
->data
.any
, 0, 4 * TILE_SIZE
* TILE_SIZE
);
240 for (i
= 0; i
< TILE_SIZE
; i
++) {
241 for (j
= 0; j
< TILE_SIZE
; j
++) {
242 tile
->data
.color32
[i
][j
] = clear_value
;
250 * Actually clear the tiles which were flagged as being in a clear state.
253 lp_tile_cache_flush_clear(struct llvmpipe_tile_cache
*tc
)
255 struct pipe_transfer
*pt
= tc
->transfer
;
256 const uint w
= tc
->transfer
->width
;
257 const uint h
= tc
->transfer
->height
;
261 /* clear the scratch tile to the clear value */
262 clear_tile(&tc
->tile
, pt
->format
, tc
->clear_val
);
264 /* push the tile to all positions marked as clear */
265 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
266 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
267 union tile_address addr
= tile_address(x
, y
, 0, 0, 0);
269 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
270 pipe_put_tile_raw(pt
,
271 x
, y
, TILE_SIZE
, TILE_SIZE
,
272 tc
->tile
.data
.color32
, 0/*STRIDE*/);
275 clear_clear_flag(tc
->clear_flags
, addr
);
282 debug_printf("num cleared: %u\n", numCleared
);
288 * Flush the tile cache: write all dirty tiles back to the transfer.
289 * any tiles "flagged" as cleared will be "really" cleared.
292 lp_flush_tile_cache(struct llvmpipe_tile_cache
*tc
)
294 struct pipe_transfer
*pt
= tc
->transfer
;
298 /* caching a drawing transfer */
299 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
300 struct llvmpipe_cached_tile
*tile
= tc
->entries
+ pos
;
301 if (!tile
->addr
.bits
.invalid
) {
302 lp_put_tile_rgba_soa(pt
,
303 tile
->addr
.bits
.x
* TILE_SIZE
,
304 tile
->addr
.bits
.y
* TILE_SIZE
,
306 tile
->addr
.bits
.invalid
= 1; /* mark as empty */
311 #if TILE_CLEAR_OPTIMIZATION
312 lp_tile_cache_flush_clear(tc
);
315 else if (tc
->texture
) {
316 /* caching a texture, mark all entries as empty */
317 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
318 tc
->entries
[pos
].addr
.bits
.invalid
= 1;
324 debug_printf("flushed tiles in use: %d\n", inuse
);
330 * Get a tile from the cache.
331 * \param x, y position of tile, in pixels
333 struct llvmpipe_cached_tile
*
334 lp_find_cached_tile(struct llvmpipe_tile_cache
*tc
,
335 union tile_address addr
)
337 struct pipe_transfer
*pt
= tc
->transfer
;
339 /* cache pos/entry: */
340 const int pos
= CACHE_POS(addr
.bits
.x
,
342 struct llvmpipe_cached_tile
*tile
= tc
->entries
+ pos
;
344 if (addr
.value
!= tile
->addr
.value
) {
346 if (tile
->addr
.bits
.invalid
== 0) {
347 /* put dirty tile back in framebuffer */
348 lp_put_tile_rgba_soa(pt
,
349 tile
->addr
.bits
.x
* TILE_SIZE
,
350 tile
->addr
.bits
.y
* TILE_SIZE
,
356 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
357 /* don't get tile from framebuffer, just clear it */
358 clear_tile_rgba(tile
, pt
->format
, tc
->clear_color
);
359 clear_clear_flag(tc
->clear_flags
, addr
);
362 /* get new tile data from transfer */
363 lp_get_tile_rgba_soa(pt
,
364 tile
->addr
.bits
.x
* TILE_SIZE
,
365 tile
->addr
.bits
.y
* TILE_SIZE
,
370 tc
->last_tile
= tile
;
376 * Given the texture face, level, zslice, x and y values, compute
377 * the cache entry position/index where we'd hope to find the
378 * cached texture tile.
379 * This is basically a direct-map cache.
380 * XXX There's probably lots of ways in which we can improve this.
383 tex_cache_pos( union tile_address addr
)
385 uint entry
= (addr
.bits
.x
+
389 addr
.bits
.level
* 7);
391 return entry
% NUM_ENTRIES
;
396 * When a whole surface is being cleared to a value we can avoid
397 * fetching tiles above.
398 * Save the color and set a 'clearflag' for each tile of the screen.
401 lp_tile_cache_clear(struct llvmpipe_tile_cache
*tc
, const float *rgba
,
406 tc
->clear_color
[0] = rgba
[0];
407 tc
->clear_color
[1] = rgba
[1];
408 tc
->clear_color
[2] = rgba
[2];
409 tc
->clear_color
[3] = rgba
[3];
411 tc
->clear_val
= clearValue
;
413 #if TILE_CLEAR_OPTIMIZATION
414 /* set flags to indicate all the tiles are cleared */
415 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
417 /* disable the optimization */
418 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));
421 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
422 struct llvmpipe_cached_tile
*tile
= tc
->entries
+ pos
;
423 tile
->addr
.bits
.invalid
= 1;