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
< Elements(tc
->tile_addrs
); 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
< Elements(tc
->entries
); pos
++) {
138 /*assert(tc->entries[pos].x < 0);*/
139 FREE( tc
->entries
[pos
] );
144 tc
->pipe
->transfer_unmap(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
;
161 if (tc
->transfer_map
) {
162 if (ps
== tc
->surface
)
165 pipe
->transfer_unmap(pipe
, tc
->transfer
);
167 tc
->transfer_map
= NULL
;
173 if (ps
->texture
->target
!= PIPE_BUFFER
) {
174 tc
->transfer_map
= pipe_transfer_map(pipe
, ps
->texture
,
175 ps
->u
.tex
.level
, ps
->u
.tex
.first_layer
,
176 PIPE_TRANSFER_READ_WRITE
|
177 PIPE_TRANSFER_UNSYNCHRONIZED
,
178 0, 0, ps
->width
, ps
->height
,
182 /* can't render to buffers */
186 tc
->depth_stencil
= util_format_is_depth_or_stencil(ps
->format
);
192 * Return the transfer being cached.
194 struct pipe_surface
*
195 sp_tile_cache_get_surface(struct softpipe_tile_cache
*tc
)
202 * Set pixels in a tile to the given clear color/value, float.
205 clear_tile_rgba(struct softpipe_cached_tile
*tile
,
206 enum pipe_format format
,
207 const union pipe_color_union
*clear_value
)
209 if (clear_value
->f
[0] == 0.0 &&
210 clear_value
->f
[1] == 0.0 &&
211 clear_value
->f
[2] == 0.0 &&
212 clear_value
->f
[3] == 0.0) {
213 memset(tile
->data
.color
, 0, sizeof(tile
->data
.color
));
218 if (util_format_is_pure_uint(format
)) {
219 for (i
= 0; i
< TILE_SIZE
; i
++) {
220 for (j
= 0; j
< TILE_SIZE
; j
++) {
221 tile
->data
.colorui128
[i
][j
][0] = clear_value
->ui
[0];
222 tile
->data
.colorui128
[i
][j
][1] = clear_value
->ui
[1];
223 tile
->data
.colorui128
[i
][j
][2] = clear_value
->ui
[2];
224 tile
->data
.colorui128
[i
][j
][3] = clear_value
->ui
[3];
227 } else if (util_format_is_pure_sint(format
)) {
228 for (i
= 0; i
< TILE_SIZE
; i
++) {
229 for (j
= 0; j
< TILE_SIZE
; j
++) {
230 tile
->data
.colori128
[i
][j
][0] = clear_value
->i
[0];
231 tile
->data
.colori128
[i
][j
][1] = clear_value
->i
[1];
232 tile
->data
.colori128
[i
][j
][2] = clear_value
->i
[2];
233 tile
->data
.colori128
[i
][j
][3] = clear_value
->i
[3];
237 for (i
= 0; i
< TILE_SIZE
; i
++) {
238 for (j
= 0; j
< TILE_SIZE
; j
++) {
239 tile
->data
.color
[i
][j
][0] = clear_value
->f
[0];
240 tile
->data
.color
[i
][j
][1] = clear_value
->f
[1];
241 tile
->data
.color
[i
][j
][2] = clear_value
->f
[2];
242 tile
->data
.color
[i
][j
][3] = clear_value
->f
[3];
251 * Set a tile to a solid value/color.
254 clear_tile(struct softpipe_cached_tile
*tile
,
255 enum pipe_format format
,
256 uint64_t clear_value
)
260 switch (util_format_get_blocksize(format
)) {
262 memset(tile
->data
.any
, (int) clear_value
, TILE_SIZE
* TILE_SIZE
);
265 if (clear_value
== 0) {
266 memset(tile
->data
.any
, 0, 2 * TILE_SIZE
* TILE_SIZE
);
269 for (i
= 0; i
< TILE_SIZE
; i
++) {
270 for (j
= 0; j
< TILE_SIZE
; j
++) {
271 tile
->data
.depth16
[i
][j
] = (ushort
) clear_value
;
277 if (clear_value
== 0) {
278 memset(tile
->data
.any
, 0, 4 * TILE_SIZE
* TILE_SIZE
);
281 for (i
= 0; i
< TILE_SIZE
; i
++) {
282 for (j
= 0; j
< TILE_SIZE
; j
++) {
283 tile
->data
.depth32
[i
][j
] = (uint
) clear_value
;
289 if (clear_value
== 0) {
290 memset(tile
->data
.any
, 0, 8 * TILE_SIZE
* TILE_SIZE
);
293 for (i
= 0; i
< TILE_SIZE
; i
++) {
294 for (j
= 0; j
< TILE_SIZE
; j
++) {
295 tile
->data
.depth64
[i
][j
] = clear_value
;
307 * Actually clear the tiles which were flagged as being in a clear state.
310 sp_tile_cache_flush_clear(struct softpipe_tile_cache
*tc
)
312 struct pipe_transfer
*pt
= tc
->transfer
;
313 const uint w
= tc
->transfer
->box
.width
;
314 const uint h
= tc
->transfer
->box
.height
;
318 assert(pt
->resource
);
320 tc
->tile
= sp_alloc_tile(tc
);
322 /* clear the scratch tile to the clear value */
323 if (tc
->depth_stencil
) {
324 clear_tile(tc
->tile
, pt
->resource
->format
, tc
->clear_val
);
326 clear_tile_rgba(tc
->tile
, pt
->resource
->format
, &tc
->clear_color
);
329 /* push the tile to all positions marked as clear */
330 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
331 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
332 union tile_address addr
= tile_address(x
, y
);
334 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
335 /* write the scratch tile to the surface */
336 if (tc
->depth_stencil
) {
337 pipe_put_tile_raw(pt
, tc
->transfer_map
,
338 x
, y
, TILE_SIZE
, TILE_SIZE
,
339 tc
->tile
->data
.any
, 0/*STRIDE*/);
342 if (util_format_is_pure_uint(tc
->surface
->format
)) {
343 pipe_put_tile_ui_format(pt
, tc
->transfer_map
,
344 x
, y
, TILE_SIZE
, TILE_SIZE
,
345 pt
->resource
->format
,
346 (unsigned *) tc
->tile
->data
.colorui128
);
347 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
348 pipe_put_tile_i_format(pt
, tc
->transfer_map
,
349 x
, y
, TILE_SIZE
, TILE_SIZE
,
350 pt
->resource
->format
,
351 (int *) tc
->tile
->data
.colori128
);
353 pipe_put_tile_rgba(pt
, tc
->transfer_map
,
354 x
, y
, TILE_SIZE
, TILE_SIZE
,
355 (float *) tc
->tile
->data
.color
);
363 /* reset all clear flags to zero */
364 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));
367 debug_printf("num cleared: %u\n", numCleared
);
372 sp_flush_tile(struct softpipe_tile_cache
* tc
, unsigned pos
)
374 if (!tc
->tile_addrs
[pos
].bits
.invalid
) {
375 if (tc
->depth_stencil
) {
376 pipe_put_tile_raw(tc
->transfer
, tc
->transfer_map
,
377 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
378 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
379 TILE_SIZE
, TILE_SIZE
,
380 tc
->entries
[pos
]->data
.depth32
, 0/*STRIDE*/);
383 if (util_format_is_pure_uint(tc
->surface
->format
)) {
384 pipe_put_tile_ui_format(tc
->transfer
, tc
->transfer_map
,
385 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
386 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
387 TILE_SIZE
, TILE_SIZE
,
389 (unsigned *) tc
->entries
[pos
]->data
.colorui128
);
390 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
391 pipe_put_tile_i_format(tc
->transfer
, tc
->transfer_map
,
392 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
393 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
394 TILE_SIZE
, TILE_SIZE
,
396 (int *) tc
->entries
[pos
]->data
.colori128
);
398 pipe_put_tile_rgba_format(tc
->transfer
, tc
->transfer_map
,
399 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
400 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
401 TILE_SIZE
, TILE_SIZE
,
403 (float *) tc
->entries
[pos
]->data
.color
);
406 tc
->tile_addrs
[pos
].bits
.invalid
= 1; /* mark as empty */
411 * Flush the tile cache: write all dirty tiles back to the transfer.
412 * any tiles "flagged" as cleared will be "really" cleared.
415 sp_flush_tile_cache(struct softpipe_tile_cache
*tc
)
417 struct pipe_transfer
*pt
= tc
->transfer
;
421 /* caching a drawing transfer */
422 for (pos
= 0; pos
< Elements(tc
->entries
); pos
++) {
423 struct softpipe_cached_tile
*tile
= tc
->entries
[pos
];
426 assert(tc
->tile_addrs
[pos
].bits
.invalid
);
430 sp_flush_tile(tc
, pos
);
434 sp_tile_cache_flush_clear(tc
);
437 tc
->last_tile_addr
.bits
.invalid
= 1;
441 debug_printf("flushed tiles in use: %d\n", inuse
);
445 static struct softpipe_cached_tile
*
446 sp_alloc_tile(struct softpipe_tile_cache
*tc
)
448 struct softpipe_cached_tile
* tile
= MALLOC_STRUCT(softpipe_cached_tile
);
451 /* in this case, steal an existing tile */
455 for (pos
= 0; pos
< Elements(tc
->entries
); ++pos
) {
456 if (!tc
->entries
[pos
])
459 sp_flush_tile(tc
, pos
);
460 tc
->tile
= tc
->entries
[pos
];
461 tc
->entries
[pos
] = NULL
;
465 /* this should never happen */
473 tc
->last_tile_addr
.bits
.invalid
= 1;
479 * Get a tile from the cache.
480 * \param x, y position of tile, in pixels
482 struct softpipe_cached_tile
*
483 sp_find_cached_tile(struct softpipe_tile_cache
*tc
,
484 union tile_address addr
)
486 struct pipe_transfer
*pt
= tc
->transfer
;
487 /* cache pos/entry: */
488 const int pos
= CACHE_POS(addr
.bits
.x
,
490 struct softpipe_cached_tile
*tile
= tc
->entries
[pos
];
493 tile
= sp_alloc_tile(tc
);
494 tc
->entries
[pos
] = tile
;
497 if (addr
.value
!= tc
->tile_addrs
[pos
].value
) {
499 assert(pt
->resource
);
500 if (tc
->tile_addrs
[pos
].bits
.invalid
== 0) {
501 /* put dirty tile back in framebuffer */
502 if (tc
->depth_stencil
) {
503 pipe_put_tile_raw(pt
, tc
->transfer_map
,
504 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
505 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
506 TILE_SIZE
, TILE_SIZE
,
507 tile
->data
.depth32
, 0/*STRIDE*/);
510 if (util_format_is_pure_uint(tc
->surface
->format
)) {
511 pipe_put_tile_ui_format(pt
, tc
->transfer_map
,
512 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
513 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
514 TILE_SIZE
, TILE_SIZE
,
516 (unsigned *) tile
->data
.colorui128
);
517 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
518 pipe_put_tile_i_format(pt
, tc
->transfer_map
,
519 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
520 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
521 TILE_SIZE
, TILE_SIZE
,
523 (int *) tile
->data
.colori128
);
525 pipe_put_tile_rgba_format(pt
, tc
->transfer_map
,
526 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
527 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
528 TILE_SIZE
, TILE_SIZE
,
530 (float *) tile
->data
.color
);
535 tc
->tile_addrs
[pos
] = addr
;
537 if (is_clear_flag_set(tc
->clear_flags
, addr
)) {
538 /* don't get tile from framebuffer, just clear it */
539 if (tc
->depth_stencil
) {
540 clear_tile(tile
, pt
->resource
->format
, tc
->clear_val
);
543 clear_tile_rgba(tile
, pt
->resource
->format
, &tc
->clear_color
);
545 clear_clear_flag(tc
->clear_flags
, addr
);
548 /* get new tile data from transfer */
549 if (tc
->depth_stencil
) {
550 pipe_get_tile_raw(pt
, tc
->transfer_map
,
551 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
552 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
553 TILE_SIZE
, TILE_SIZE
,
554 tile
->data
.depth32
, 0/*STRIDE*/);
557 if (util_format_is_pure_uint(tc
->surface
->format
)) {
558 pipe_get_tile_ui_format(pt
, tc
->transfer_map
,
559 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
560 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
561 TILE_SIZE
, TILE_SIZE
,
563 (unsigned *) tile
->data
.colorui128
);
564 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
565 pipe_get_tile_i_format(pt
, tc
->transfer_map
,
566 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
567 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
568 TILE_SIZE
, TILE_SIZE
,
570 (int *) tile
->data
.colori128
);
572 pipe_get_tile_rgba_format(pt
, tc
->transfer_map
,
573 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
574 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
575 TILE_SIZE
, TILE_SIZE
,
577 (float *) tile
->data
.color
);
583 tc
->last_tile
= tile
;
584 tc
->last_tile_addr
= addr
;
593 * When a whole surface is being cleared to a value we can avoid
594 * fetching tiles above.
595 * Save the color and set a 'clearflag' for each tile of the screen.
598 sp_tile_cache_clear(struct softpipe_tile_cache
*tc
,
599 const union pipe_color_union
*color
,
604 tc
->clear_color
= *color
;
606 tc
->clear_val
= clearValue
;
608 /* set flags to indicate all the tiles are cleared */
609 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
611 for (pos
= 0; pos
< Elements(tc
->tile_addrs
); pos
++) {
612 tc
->tile_addrs
[pos
].bits
.invalid
= 1;
614 tc
->last_tile_addr
.bits
.invalid
= 1;