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 * Render target tile caching.
35 #include "util/u_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"
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.
49 #define CACHE_POS(x, y) \
50 (((x) + (y) * 5) % NUM_ENTRIES)
55 * Is the tile at (x,y) in cleared state?
58 is_clear_flag_set(const uint
*bitvec
, union tile_address addr
)
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));
69 * Mark the tile at (x,y) as not cleared.
72 clear_clear_flag(uint
*bitvec
, union tile_address addr
)
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));
81 struct softpipe_tile_cache
*
82 sp_create_tile_cache( struct pipe_context
*pipe
)
84 struct softpipe_tile_cache
*tc
;
86 int maxLevels
, maxTexSize
;
88 /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
89 maxLevels
= pipe
->screen
->get_param(pipe
->screen
, PIPE_CAP_MAX_TEXTURE_2D_LEVELS
);
90 maxTexSize
= 1 << (maxLevels
- 1);
91 assert(MAX_WIDTH
>= maxTexSize
);
93 tc
= CALLOC_STRUCT( softpipe_tile_cache
);
96 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
97 tc
->entries
[pos
].addr
.bits
.invalid
= 1;
99 tc
->last_tile
= &tc
->entries
[0]; /* any tile */
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).
107 /* set flags to indicate all the tiles are cleared */
108 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
116 sp_destroy_tile_cache(struct softpipe_tile_cache
*tc
)
121 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
122 /*assert(tc->entries[pos].x < 0);*/
125 tc
->pipe
->transfer_destroy(tc
->pipe
, tc
->transfer
);
134 * Specify the surface to cache.
137 sp_tile_cache_set_surface(struct softpipe_tile_cache
*tc
,
138 struct pipe_surface
*ps
)
140 struct pipe_context
*pipe
= tc
->pipe
;
143 if (ps
== tc
->surface
)
146 if (tc
->transfer_map
) {
147 pipe
->transfer_unmap(pipe
, tc
->transfer
);
148 tc
->transfer_map
= NULL
;
151 pipe
->transfer_destroy(pipe
, tc
->transfer
);
158 tc
->transfer
= pipe_get_transfer(pipe
, ps
->texture
, ps
->face
,
159 ps
->level
, ps
->zslice
,
160 PIPE_TRANSFER_READ_WRITE
|
161 PIPE_TRANSFER_UNSYNCHRONIZED
,
162 0, 0, ps
->width
, ps
->height
);
164 tc
->depth_stencil
= (ps
->format
== PIPE_FORMAT_Z24_UNORM_S8_USCALED
||
165 ps
->format
== PIPE_FORMAT_Z24X8_UNORM
||
166 ps
->format
== PIPE_FORMAT_S8_USCALED_Z24_UNORM
||
167 ps
->format
== PIPE_FORMAT_X8Z24_UNORM
||
168 ps
->format
== PIPE_FORMAT_Z16_UNORM
||
169 ps
->format
== PIPE_FORMAT_Z32_UNORM
||
170 ps
->format
== PIPE_FORMAT_S8_USCALED
);
176 * Return the transfer being cached.
178 struct pipe_surface
*
179 sp_tile_cache_get_surface(struct softpipe_tile_cache
*tc
)
186 sp_tile_cache_map_transfers(struct softpipe_tile_cache
*tc
)
188 if (tc
->transfer
&& !tc
->transfer_map
)
189 tc
->transfer_map
= tc
->pipe
->transfer_map(tc
->pipe
, tc
->transfer
);
194 sp_tile_cache_unmap_transfers(struct softpipe_tile_cache
*tc
)
196 if (tc
->transfer_map
) {
197 tc
->pipe
->transfer_unmap(tc
->pipe
, tc
->transfer
);
198 tc
->transfer_map
= NULL
;
204 * Set pixels in a tile to the given clear color/value, float.
207 clear_tile_rgba(struct softpipe_cached_tile
*tile
,
208 enum pipe_format format
,
209 const float clear_value
[4])
211 if (clear_value
[0] == 0.0 &&
212 clear_value
[1] == 0.0 &&
213 clear_value
[2] == 0.0 &&
214 clear_value
[3] == 0.0) {
215 memset(tile
->data
.color
, 0, sizeof(tile
->data
.color
));
219 for (i
= 0; i
< TILE_SIZE
; i
++) {
220 for (j
= 0; j
< TILE_SIZE
; j
++) {
221 tile
->data
.color
[i
][j
][0] = clear_value
[0];
222 tile
->data
.color
[i
][j
][1] = clear_value
[1];
223 tile
->data
.color
[i
][j
][2] = clear_value
[2];
224 tile
->data
.color
[i
][j
][3] = clear_value
[3];
232 * Set a tile to a solid value/color.
235 clear_tile(struct softpipe_cached_tile
*tile
,
236 enum pipe_format format
,
241 switch (util_format_get_blocksize(format
)) {
243 memset(tile
->data
.any
, clear_value
, TILE_SIZE
* TILE_SIZE
);
246 if (clear_value
== 0) {
247 memset(tile
->data
.any
, 0, 2 * TILE_SIZE
* TILE_SIZE
);
250 for (i
= 0; i
< TILE_SIZE
; i
++) {
251 for (j
= 0; j
< TILE_SIZE
; j
++) {
252 tile
->data
.depth16
[i
][j
] = (ushort
) clear_value
;
258 if (clear_value
== 0) {
259 memset(tile
->data
.any
, 0, 4 * TILE_SIZE
* TILE_SIZE
);
262 for (i
= 0; i
< TILE_SIZE
; i
++) {
263 for (j
= 0; j
< TILE_SIZE
; j
++) {
264 tile
->data
.color32
[i
][j
] = clear_value
;
276 * Actually clear the tiles which were flagged as being in a clear state.
279 sp_tile_cache_flush_clear(struct softpipe_tile_cache
*tc
)
281 struct pipe_transfer
*pt
= tc
->transfer
;
282 const uint w
= tc
->transfer
->box
.width
;
283 const uint h
= tc
->transfer
->box
.height
;
287 assert(pt
->resource
);
288 /* clear the scratch tile to the clear value */
289 if (tc
->depth_stencil
) {
290 clear_tile(&tc
->tile
, pt
->resource
->format
, tc
->clear_val
);
292 clear_tile_rgba(&tc
->tile
, pt
->resource
->format
, tc
->clear_color
);
295 /* push the tile to all positions marked as clear */
296 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
297 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
298 union tile_address addr
= tile_address(x
, y
);
300 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
301 /* write the scratch tile to the surface */
302 if (tc
->depth_stencil
) {
303 pipe_put_tile_raw(tc
->pipe
,
305 x
, y
, TILE_SIZE
, TILE_SIZE
,
306 tc
->tile
.data
.any
, 0/*STRIDE*/);
309 pipe_put_tile_rgba(tc
->pipe
, pt
,
310 x
, y
, TILE_SIZE
, TILE_SIZE
,
311 (float *) tc
->tile
.data
.color
);
318 /* reset all clear flags to zero */
319 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));
322 debug_printf("num cleared: %u\n", numCleared
);
328 * Flush the tile cache: write all dirty tiles back to the transfer.
329 * any tiles "flagged" as cleared will be "really" cleared.
332 sp_flush_tile_cache(struct softpipe_tile_cache
*tc
)
334 struct pipe_transfer
*pt
= tc
->transfer
;
338 /* caching a drawing transfer */
339 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
340 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
341 if (!tile
->addr
.bits
.invalid
) {
342 if (tc
->depth_stencil
) {
343 pipe_put_tile_raw(tc
->pipe
, pt
,
344 tile
->addr
.bits
.x
* TILE_SIZE
,
345 tile
->addr
.bits
.y
* TILE_SIZE
,
346 TILE_SIZE
, TILE_SIZE
,
347 tile
->data
.depth32
, 0/*STRIDE*/);
350 pipe_put_tile_rgba(tc
->pipe
, pt
,
351 tile
->addr
.bits
.x
* TILE_SIZE
,
352 tile
->addr
.bits
.y
* TILE_SIZE
,
353 TILE_SIZE
, TILE_SIZE
,
354 (float *) tile
->data
.color
);
356 tile
->addr
.bits
.invalid
= 1; /* mark as empty */
361 sp_tile_cache_flush_clear(tc
);
365 debug_printf("flushed tiles in use: %d\n", inuse
);
371 * Get a tile from the cache.
372 * \param x, y position of tile, in pixels
374 struct softpipe_cached_tile
*
375 sp_find_cached_tile(struct softpipe_tile_cache
*tc
,
376 union tile_address addr
)
378 struct pipe_transfer
*pt
= tc
->transfer
;
380 /* cache pos/entry: */
381 const int pos
= CACHE_POS(addr
.bits
.x
,
383 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
385 if (addr
.value
!= tile
->addr
.value
) {
387 assert(pt
->resource
);
388 if (tile
->addr
.bits
.invalid
== 0) {
389 /* put dirty tile back in framebuffer */
390 if (tc
->depth_stencil
) {
391 pipe_put_tile_raw(tc
->pipe
, pt
,
392 tile
->addr
.bits
.x
* TILE_SIZE
,
393 tile
->addr
.bits
.y
* TILE_SIZE
,
394 TILE_SIZE
, TILE_SIZE
,
395 tile
->data
.depth32
, 0/*STRIDE*/);
398 pipe_put_tile_rgba(tc
->pipe
, pt
,
399 tile
->addr
.bits
.x
* TILE_SIZE
,
400 tile
->addr
.bits
.y
* TILE_SIZE
,
401 TILE_SIZE
, TILE_SIZE
,
402 (float *) tile
->data
.color
);
408 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
409 /* don't get tile from framebuffer, just clear it */
410 if (tc
->depth_stencil
) {
411 clear_tile(tile
, pt
->resource
->format
, tc
->clear_val
);
414 clear_tile_rgba(tile
, pt
->resource
->format
, tc
->clear_color
);
416 clear_clear_flag(tc
->clear_flags
, addr
);
419 /* get new tile data from transfer */
420 if (tc
->depth_stencil
) {
421 pipe_get_tile_raw(tc
->pipe
, pt
,
422 tile
->addr
.bits
.x
* TILE_SIZE
,
423 tile
->addr
.bits
.y
* TILE_SIZE
,
424 TILE_SIZE
, TILE_SIZE
,
425 tile
->data
.depth32
, 0/*STRIDE*/);
428 pipe_get_tile_rgba(tc
->pipe
, pt
,
429 tile
->addr
.bits
.x
* TILE_SIZE
,
430 tile
->addr
.bits
.y
* TILE_SIZE
,
431 TILE_SIZE
, TILE_SIZE
,
432 (float *) tile
->data
.color
);
437 tc
->last_tile
= tile
;
446 * When a whole surface is being cleared to a value we can avoid
447 * fetching tiles above.
448 * Save the color and set a 'clearflag' for each tile of the screen.
451 sp_tile_cache_clear(struct softpipe_tile_cache
*tc
, const float *rgba
,
456 tc
->clear_color
[0] = rgba
[0];
457 tc
->clear_color
[1] = rgba
[1];
458 tc
->clear_color
[2] = rgba
[2];
459 tc
->clear_color
[3] = rgba
[3];
461 tc
->clear_val
= clearValue
;
463 /* set flags to indicate all the tiles are cleared */
464 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
466 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
467 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
468 tile
->addr
.bits
.invalid
= 1;