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"
41 static struct softpipe_cached_tile
*
42 sp_alloc_tile(struct softpipe_tile_cache
*tc
);
46 * Return the position in the cache for the tile that contains win pos (x,y).
47 * We currently use a direct mapped cache so this is like a hack key.
48 * At some point we should investige something more sophisticated, like
49 * a LRU replacement policy.
51 #define CACHE_POS(x, y) \
52 (((x) + (y) * 5) % NUM_ENTRIES)
57 * Is the tile at (x,y) in cleared state?
60 is_clear_flag_set(const uint
*bitvec
, union tile_address addr
)
63 pos
= addr
.bits
.y
* (MAX_WIDTH
/ TILE_SIZE
) + addr
.bits
.x
;
64 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
65 bit
= bitvec
[pos
/ 32] & (1 << (pos
& 31));
71 * Mark the tile at (x,y) as not cleared.
74 clear_clear_flag(uint
*bitvec
, union tile_address addr
)
77 pos
= addr
.bits
.y
* (MAX_WIDTH
/ TILE_SIZE
) + addr
.bits
.x
;
78 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
79 bitvec
[pos
/ 32] &= ~(1 << (pos
& 31));
83 struct softpipe_tile_cache
*
84 sp_create_tile_cache( struct pipe_context
*pipe
)
86 struct softpipe_tile_cache
*tc
;
88 int maxLevels
, maxTexSize
;
90 /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
91 maxLevels
= pipe
->screen
->get_param(pipe
->screen
, PIPE_CAP_MAX_TEXTURE_2D_LEVELS
);
92 maxTexSize
= 1 << (maxLevels
- 1);
93 assert(MAX_WIDTH
>= maxTexSize
);
95 assert(sizeof(union tile_address
) == 4);
97 assert((TILE_SIZE
<< TILE_ADDR_BITS
) >= MAX_WIDTH
);
99 tc
= CALLOC_STRUCT( softpipe_tile_cache
);
102 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
103 tc
->tile_addrs
[pos
].bits
.invalid
= 1;
105 tc
->last_tile_addr
.bits
.invalid
= 1;
107 /* this allocation allows us to guarantee that allocation
108 * failures are never fatal later
110 tc
->tile
= MALLOC_STRUCT( softpipe_cached_tile
);
117 /* XXX this code prevents valgrind warnings about use of uninitialized
118 * memory in programs that don't clear the surface before rendering.
119 * However, it breaks clearing in other situations (such as in
120 * progs/tests/drawbuffers, see bug 24402).
123 /* set flags to indicate all the tiles are cleared */
124 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
132 sp_destroy_tile_cache(struct softpipe_tile_cache
*tc
)
137 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
138 /*assert(tc->entries[pos].x < 0);*/
139 FREE( tc
->entries
[pos
] );
144 tc
->pipe
->transfer_destroy(tc
->pipe
, tc
->transfer
);
153 * Specify the surface to cache.
156 sp_tile_cache_set_surface(struct softpipe_tile_cache
*tc
,
157 struct pipe_surface
*ps
)
159 struct pipe_context
*pipe
= tc
->pipe
;
162 if (ps
== tc
->surface
)
165 if (tc
->transfer_map
) {
166 pipe
->transfer_unmap(pipe
, tc
->transfer
);
167 tc
->transfer_map
= NULL
;
170 pipe
->transfer_destroy(pipe
, tc
->transfer
);
177 tc
->transfer
= pipe_get_transfer(pipe
, ps
->texture
,
178 ps
->u
.tex
.level
, ps
->u
.tex
.first_layer
,
179 PIPE_TRANSFER_READ_WRITE
|
180 PIPE_TRANSFER_UNSYNCHRONIZED
,
181 0, 0, ps
->width
, ps
->height
);
183 tc
->depth_stencil
= util_format_is_depth_or_stencil(ps
->format
);
189 * Return the transfer being cached.
191 struct pipe_surface
*
192 sp_tile_cache_get_surface(struct softpipe_tile_cache
*tc
)
199 sp_tile_cache_map_transfers(struct softpipe_tile_cache
*tc
)
201 if (tc
->transfer
&& !tc
->transfer_map
)
202 tc
->transfer_map
= tc
->pipe
->transfer_map(tc
->pipe
, tc
->transfer
);
207 sp_tile_cache_unmap_transfers(struct softpipe_tile_cache
*tc
)
209 if (tc
->transfer_map
) {
210 tc
->pipe
->transfer_unmap(tc
->pipe
, tc
->transfer
);
211 tc
->transfer_map
= NULL
;
217 * Set pixels in a tile to the given clear color/value, float.
220 clear_tile_rgba(struct softpipe_cached_tile
*tile
,
221 enum pipe_format format
,
222 const union pipe_color_union
*clear_value
)
224 if (clear_value
->f
[0] == 0.0 &&
225 clear_value
->f
[1] == 0.0 &&
226 clear_value
->f
[2] == 0.0 &&
227 clear_value
->f
[3] == 0.0) {
228 memset(tile
->data
.color
, 0, sizeof(tile
->data
.color
));
233 if (util_format_is_pure_uint(format
)) {
234 for (i
= 0; i
< TILE_SIZE
; i
++) {
235 for (j
= 0; j
< TILE_SIZE
; j
++) {
236 tile
->data
.colorui128
[i
][j
][0] = clear_value
->ui
[0];
237 tile
->data
.colorui128
[i
][j
][1] = clear_value
->ui
[1];
238 tile
->data
.colorui128
[i
][j
][2] = clear_value
->ui
[2];
239 tile
->data
.colorui128
[i
][j
][3] = clear_value
->ui
[3];
242 } else if (util_format_is_pure_sint(format
)) {
243 for (i
= 0; i
< TILE_SIZE
; i
++) {
244 for (j
= 0; j
< TILE_SIZE
; j
++) {
245 tile
->data
.colori128
[i
][j
][0] = clear_value
->i
[0];
246 tile
->data
.colori128
[i
][j
][1] = clear_value
->i
[1];
247 tile
->data
.colori128
[i
][j
][2] = clear_value
->i
[2];
248 tile
->data
.colori128
[i
][j
][3] = clear_value
->i
[3];
252 for (i
= 0; i
< TILE_SIZE
; i
++) {
253 for (j
= 0; j
< TILE_SIZE
; j
++) {
254 tile
->data
.color
[i
][j
][0] = clear_value
->f
[0];
255 tile
->data
.color
[i
][j
][1] = clear_value
->f
[1];
256 tile
->data
.color
[i
][j
][2] = clear_value
->f
[2];
257 tile
->data
.color
[i
][j
][3] = clear_value
->f
[3];
266 * Set a tile to a solid value/color.
269 clear_tile(struct softpipe_cached_tile
*tile
,
270 enum pipe_format format
,
271 uint64_t clear_value
)
275 switch (util_format_get_blocksize(format
)) {
277 memset(tile
->data
.any
, clear_value
, TILE_SIZE
* TILE_SIZE
);
280 if (clear_value
== 0) {
281 memset(tile
->data
.any
, 0, 2 * TILE_SIZE
* TILE_SIZE
);
284 for (i
= 0; i
< TILE_SIZE
; i
++) {
285 for (j
= 0; j
< TILE_SIZE
; j
++) {
286 tile
->data
.depth16
[i
][j
] = (ushort
) clear_value
;
292 if (clear_value
== 0) {
293 memset(tile
->data
.any
, 0, 4 * TILE_SIZE
* TILE_SIZE
);
296 for (i
= 0; i
< TILE_SIZE
; i
++) {
297 for (j
= 0; j
< TILE_SIZE
; j
++) {
298 tile
->data
.depth32
[i
][j
] = clear_value
;
304 if (clear_value
== 0) {
305 memset(tile
->data
.any
, 0, 8 * TILE_SIZE
* TILE_SIZE
);
308 for (i
= 0; i
< TILE_SIZE
; i
++) {
309 for (j
= 0; j
< TILE_SIZE
; j
++) {
310 tile
->data
.depth64
[i
][j
] = clear_value
;
322 * Actually clear the tiles which were flagged as being in a clear state.
325 sp_tile_cache_flush_clear(struct softpipe_tile_cache
*tc
)
327 struct pipe_transfer
*pt
= tc
->transfer
;
328 const uint w
= tc
->transfer
->box
.width
;
329 const uint h
= tc
->transfer
->box
.height
;
333 assert(pt
->resource
);
335 tc
->tile
= sp_alloc_tile(tc
);
337 /* clear the scratch tile to the clear value */
338 if (tc
->depth_stencil
) {
339 clear_tile(tc
->tile
, pt
->resource
->format
, tc
->clear_val
);
341 clear_tile_rgba(tc
->tile
, pt
->resource
->format
, &tc
->clear_color
);
344 /* push the tile to all positions marked as clear */
345 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
346 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
347 union tile_address addr
= tile_address(x
, y
);
349 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
350 /* write the scratch tile to the surface */
351 if (tc
->depth_stencil
) {
352 pipe_put_tile_raw(tc
->pipe
,
354 x
, y
, TILE_SIZE
, TILE_SIZE
,
355 tc
->tile
->data
.any
, 0/*STRIDE*/);
358 if (util_format_is_pure_uint(tc
->surface
->format
)) {
359 pipe_put_tile_ui_format(tc
->pipe
, pt
,
360 x
, y
, TILE_SIZE
, TILE_SIZE
,
361 pt
->resource
->format
,
362 (unsigned *) tc
->tile
->data
.colorui128
);
363 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
364 pipe_put_tile_i_format(tc
->pipe
, pt
,
365 x
, y
, TILE_SIZE
, TILE_SIZE
,
366 pt
->resource
->format
,
367 (int *) tc
->tile
->data
.colori128
);
369 pipe_put_tile_rgba(tc
->pipe
, pt
,
370 x
, y
, TILE_SIZE
, TILE_SIZE
,
371 (float *) tc
->tile
->data
.color
);
379 /* reset all clear flags to zero */
380 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));
383 debug_printf("num cleared: %u\n", numCleared
);
388 sp_flush_tile(struct softpipe_tile_cache
* tc
, unsigned pos
)
390 if (!tc
->tile_addrs
[pos
].bits
.invalid
) {
391 if (tc
->depth_stencil
) {
392 pipe_put_tile_raw(tc
->pipe
, tc
->transfer
,
393 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
394 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
395 TILE_SIZE
, TILE_SIZE
,
396 tc
->entries
[pos
]->data
.depth32
, 0/*STRIDE*/);
399 if (util_format_is_pure_uint(tc
->surface
->format
)) {
400 pipe_put_tile_ui_format(tc
->pipe
, tc
->transfer
,
401 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
402 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
403 TILE_SIZE
, TILE_SIZE
,
405 (unsigned *) tc
->entries
[pos
]->data
.colorui128
);
406 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
407 pipe_put_tile_i_format(tc
->pipe
, tc
->transfer
,
408 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
409 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
410 TILE_SIZE
, TILE_SIZE
,
412 (int *) tc
->entries
[pos
]->data
.colori128
);
414 pipe_put_tile_rgba_format(tc
->pipe
, tc
->transfer
,
415 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
416 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
417 TILE_SIZE
, TILE_SIZE
,
419 (float *) tc
->entries
[pos
]->data
.color
);
422 tc
->tile_addrs
[pos
].bits
.invalid
= 1; /* mark as empty */
427 * Flush the tile cache: write all dirty tiles back to the transfer.
428 * any tiles "flagged" as cleared will be "really" cleared.
431 sp_flush_tile_cache(struct softpipe_tile_cache
*tc
)
433 struct pipe_transfer
*pt
= tc
->transfer
;
437 /* caching a drawing transfer */
438 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
439 struct softpipe_cached_tile
*tile
= tc
->entries
[pos
];
442 assert(tc
->tile_addrs
[pos
].bits
.invalid
);
446 sp_flush_tile(tc
, pos
);
450 sp_tile_cache_flush_clear(tc
);
453 tc
->last_tile_addr
.bits
.invalid
= 1;
457 debug_printf("flushed tiles in use: %d\n", inuse
);
461 static struct softpipe_cached_tile
*
462 sp_alloc_tile(struct softpipe_tile_cache
*tc
)
464 struct softpipe_cached_tile
* tile
= MALLOC_STRUCT(softpipe_cached_tile
);
467 /* in this case, steal an existing tile */
471 for (pos
= 0; pos
< NUM_ENTRIES
; ++pos
) {
472 if (!tc
->entries
[pos
])
475 sp_flush_tile(tc
, pos
);
476 tc
->tile
= tc
->entries
[pos
];
477 tc
->entries
[pos
] = NULL
;
481 /* this should never happen */
489 tc
->last_tile_addr
.bits
.invalid
= 1;
495 * Get a tile from the cache.
496 * \param x, y position of tile, in pixels
498 struct softpipe_cached_tile
*
499 sp_find_cached_tile(struct softpipe_tile_cache
*tc
,
500 union tile_address addr
)
502 struct pipe_transfer
*pt
= tc
->transfer
;
503 /* cache pos/entry: */
504 const int pos
= CACHE_POS(addr
.bits
.x
,
506 struct softpipe_cached_tile
*tile
= tc
->entries
[pos
];
509 tile
= sp_alloc_tile(tc
);
510 tc
->entries
[pos
] = tile
;
513 if (addr
.value
!= tc
->tile_addrs
[pos
].value
) {
515 assert(pt
->resource
);
516 if (tc
->tile_addrs
[pos
].bits
.invalid
== 0) {
517 /* put dirty tile back in framebuffer */
518 if (tc
->depth_stencil
) {
519 pipe_put_tile_raw(tc
->pipe
, pt
,
520 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
521 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
522 TILE_SIZE
, TILE_SIZE
,
523 tile
->data
.depth32
, 0/*STRIDE*/);
526 if (util_format_is_pure_uint(tc
->surface
->format
)) {
527 pipe_put_tile_ui_format(tc
->pipe
, pt
,
528 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
529 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
530 TILE_SIZE
, TILE_SIZE
,
532 (unsigned *) tile
->data
.colorui128
);
533 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
534 pipe_put_tile_i_format(tc
->pipe
, pt
,
535 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
536 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
537 TILE_SIZE
, TILE_SIZE
,
539 (int *) tile
->data
.colori128
);
541 pipe_put_tile_rgba_format(tc
->pipe
, pt
,
542 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
543 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
544 TILE_SIZE
, TILE_SIZE
,
546 (float *) tile
->data
.color
);
551 tc
->tile_addrs
[pos
] = addr
;
553 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
554 /* don't get tile from framebuffer, just clear it */
555 if (tc
->depth_stencil
) {
556 clear_tile(tile
, pt
->resource
->format
, tc
->clear_val
);
559 clear_tile_rgba(tile
, pt
->resource
->format
, &tc
->clear_color
);
561 clear_clear_flag(tc
->clear_flags
, addr
);
564 /* get new tile data from transfer */
565 if (tc
->depth_stencil
) {
566 pipe_get_tile_raw(tc
->pipe
, pt
,
567 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
568 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
569 TILE_SIZE
, TILE_SIZE
,
570 tile
->data
.depth32
, 0/*STRIDE*/);
573 if (util_format_is_pure_uint(tc
->surface
->format
)) {
574 pipe_get_tile_ui_format(tc
->pipe
, pt
,
575 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
576 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
577 TILE_SIZE
, TILE_SIZE
,
579 (unsigned *) tile
->data
.colorui128
);
580 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
581 pipe_get_tile_i_format(tc
->pipe
, pt
,
582 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
583 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
584 TILE_SIZE
, TILE_SIZE
,
586 (int *) tile
->data
.colori128
);
588 pipe_get_tile_rgba_format(tc
->pipe
, pt
,
589 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
590 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
591 TILE_SIZE
, TILE_SIZE
,
593 (float *) tile
->data
.color
);
599 tc
->last_tile
= tile
;
600 tc
->last_tile_addr
= addr
;
609 * When a whole surface is being cleared to a value we can avoid
610 * fetching tiles above.
611 * Save the color and set a 'clearflag' for each tile of the screen.
614 sp_tile_cache_clear(struct softpipe_tile_cache
*tc
,
615 const union pipe_color_union
*color
,
620 tc
->clear_color
= *color
;
622 tc
->clear_val
= clearValue
;
624 /* set flags to indicate all the tiles are cleared */
625 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
627 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
628 tc
->tile_addrs
[pos
].bits
.invalid
= 1;
630 tc
->last_tile_addr
.bits
.invalid
= 1;