1 /**************************************************************************
3 * Copyright 2007 VMware, Inc.
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 VMWARE 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, l) \
52 (((x) + (y) * 5 + (l) * 10) % NUM_ENTRIES)
55 static inline int addr_to_clear_pos(union tile_address addr
)
58 pos
= addr
.bits
.layer
* (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
);
59 pos
+= addr
.bits
.y
* (MAX_WIDTH
/ TILE_SIZE
);
64 * Is the tile at (x,y) in cleared state?
67 is_clear_flag_set(const uint
*bitvec
, union tile_address addr
, unsigned max
)
70 pos
= addr_to_clear_pos(addr
);
71 assert(pos
/ 32 < max
);
72 bit
= bitvec
[pos
/ 32] & (1 << (pos
& 31));
78 * Mark the tile at (x,y) as not cleared.
81 clear_clear_flag(uint
*bitvec
, union tile_address addr
, unsigned max
)
84 pos
= addr_to_clear_pos(addr
);
85 assert(pos
/ 32 < max
);
86 bitvec
[pos
/ 32] &= ~(1 << (pos
& 31));
90 struct softpipe_tile_cache
*
91 sp_create_tile_cache( struct pipe_context
*pipe
)
93 struct softpipe_tile_cache
*tc
;
95 MAYBE_UNUSED
int maxTexSize
;
98 /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
99 maxLevels
= pipe
->screen
->get_param(pipe
->screen
, PIPE_CAP_MAX_TEXTURE_2D_LEVELS
);
100 maxTexSize
= 1 << (maxLevels
- 1);
101 assert(MAX_WIDTH
>= maxTexSize
);
103 STATIC_ASSERT(sizeof(union tile_address
) == 4);
105 STATIC_ASSERT((TILE_SIZE
<< TILE_ADDR_BITS
) >= MAX_WIDTH
);
107 tc
= CALLOC_STRUCT( softpipe_tile_cache
);
110 for (pos
= 0; pos
< Elements(tc
->tile_addrs
); pos
++) {
111 tc
->tile_addrs
[pos
].bits
.invalid
= 1;
113 tc
->last_tile_addr
.bits
.invalid
= 1;
115 /* this allocation allows us to guarantee that allocation
116 * failures are never fatal later
118 tc
->tile
= MALLOC_STRUCT( softpipe_cached_tile
);
125 /* XXX this code prevents valgrind warnings about use of uninitialized
126 * memory in programs that don't clear the surface before rendering.
127 * However, it breaks clearing in other situations (such as in
128 * progs/tests/drawbuffers, see bug 24402).
131 /* set flags to indicate all the tiles are cleared */
132 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
140 sp_destroy_tile_cache(struct softpipe_tile_cache
*tc
)
145 for (pos
= 0; pos
< Elements(tc
->entries
); pos
++) {
146 /*assert(tc->entries[pos].x < 0);*/
147 FREE( tc
->entries
[pos
] );
153 for (i
= 0; i
< tc
->num_maps
; i
++)
154 if (tc
->transfer
[i
]) {
155 tc
->pipe
->transfer_unmap(tc
->pipe
, tc
->transfer
[i
]);
158 FREE(tc
->transfer_map
);
159 FREE(tc
->clear_flags
);
168 * Specify the surface to cache.
171 sp_tile_cache_set_surface(struct softpipe_tile_cache
*tc
,
172 struct pipe_surface
*ps
)
174 struct pipe_context
*pipe
= tc
->pipe
;
178 if (ps
== tc
->surface
)
181 for (i
= 0; i
< tc
->num_maps
; i
++) {
182 pipe
->transfer_unmap(pipe
, tc
->transfer
[i
]);
183 tc
->transfer
[i
] = NULL
;
184 tc
->transfer_map
[i
] = NULL
;
187 FREE(tc
->transfer_map
);
190 FREE(tc
->clear_flags
);
191 tc
->clear_flags_size
= 0;
197 tc
->num_maps
= ps
->u
.tex
.last_layer
- ps
->u
.tex
.first_layer
+ 1;
198 tc
->transfer
= CALLOC(tc
->num_maps
, sizeof(struct pipe_transfer
*));
199 tc
->transfer_map
= CALLOC(tc
->num_maps
, sizeof(void *));
201 tc
->clear_flags_size
= (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) * tc
->num_maps
/ 32 * sizeof(uint
);
202 tc
->clear_flags
= CALLOC(1, tc
->clear_flags_size
);
204 if (ps
->texture
->target
!= PIPE_BUFFER
) {
205 for (i
= 0; i
< tc
->num_maps
; i
++) {
206 tc
->transfer_map
[i
] = pipe_transfer_map(pipe
, ps
->texture
,
207 ps
->u
.tex
.level
, ps
->u
.tex
.first_layer
+ i
,
208 PIPE_TRANSFER_READ_WRITE
|
209 PIPE_TRANSFER_UNSYNCHRONIZED
,
210 0, 0, ps
->width
, ps
->height
,
215 /* can't render to buffers */
219 tc
->depth_stencil
= util_format_is_depth_or_stencil(ps
->format
);
225 * Return the transfer being cached.
227 struct pipe_surface
*
228 sp_tile_cache_get_surface(struct softpipe_tile_cache
*tc
)
235 * Set pixels in a tile to the given clear color/value, float.
238 clear_tile_rgba(struct softpipe_cached_tile
*tile
,
239 enum pipe_format format
,
240 const union pipe_color_union
*clear_value
)
242 if (clear_value
->f
[0] == 0.0 &&
243 clear_value
->f
[1] == 0.0 &&
244 clear_value
->f
[2] == 0.0 &&
245 clear_value
->f
[3] == 0.0) {
246 memset(tile
->data
.color
, 0, sizeof(tile
->data
.color
));
251 if (util_format_is_pure_uint(format
)) {
252 for (i
= 0; i
< TILE_SIZE
; i
++) {
253 for (j
= 0; j
< TILE_SIZE
; j
++) {
254 tile
->data
.colorui128
[i
][j
][0] = clear_value
->ui
[0];
255 tile
->data
.colorui128
[i
][j
][1] = clear_value
->ui
[1];
256 tile
->data
.colorui128
[i
][j
][2] = clear_value
->ui
[2];
257 tile
->data
.colorui128
[i
][j
][3] = clear_value
->ui
[3];
260 } else if (util_format_is_pure_sint(format
)) {
261 for (i
= 0; i
< TILE_SIZE
; i
++) {
262 for (j
= 0; j
< TILE_SIZE
; j
++) {
263 tile
->data
.colori128
[i
][j
][0] = clear_value
->i
[0];
264 tile
->data
.colori128
[i
][j
][1] = clear_value
->i
[1];
265 tile
->data
.colori128
[i
][j
][2] = clear_value
->i
[2];
266 tile
->data
.colori128
[i
][j
][3] = clear_value
->i
[3];
270 for (i
= 0; i
< TILE_SIZE
; i
++) {
271 for (j
= 0; j
< TILE_SIZE
; j
++) {
272 tile
->data
.color
[i
][j
][0] = clear_value
->f
[0];
273 tile
->data
.color
[i
][j
][1] = clear_value
->f
[1];
274 tile
->data
.color
[i
][j
][2] = clear_value
->f
[2];
275 tile
->data
.color
[i
][j
][3] = clear_value
->f
[3];
284 * Set a tile to a solid value/color.
287 clear_tile(struct softpipe_cached_tile
*tile
,
288 enum pipe_format format
,
289 uint64_t clear_value
)
293 switch (util_format_get_blocksize(format
)) {
295 memset(tile
->data
.any
, (int) clear_value
, TILE_SIZE
* TILE_SIZE
);
298 if (clear_value
== 0) {
299 memset(tile
->data
.any
, 0, 2 * TILE_SIZE
* TILE_SIZE
);
302 for (i
= 0; i
< TILE_SIZE
; i
++) {
303 for (j
= 0; j
< TILE_SIZE
; j
++) {
304 tile
->data
.depth16
[i
][j
] = (ushort
) clear_value
;
310 if (clear_value
== 0) {
311 memset(tile
->data
.any
, 0, 4 * TILE_SIZE
* TILE_SIZE
);
314 for (i
= 0; i
< TILE_SIZE
; i
++) {
315 for (j
= 0; j
< TILE_SIZE
; j
++) {
316 tile
->data
.depth32
[i
][j
] = (uint
) clear_value
;
322 if (clear_value
== 0) {
323 memset(tile
->data
.any
, 0, 8 * TILE_SIZE
* TILE_SIZE
);
326 for (i
= 0; i
< TILE_SIZE
; i
++) {
327 for (j
= 0; j
< TILE_SIZE
; j
++) {
328 tile
->data
.depth64
[i
][j
] = clear_value
;
340 * Actually clear the tiles which were flagged as being in a clear state.
343 sp_tile_cache_flush_clear(struct softpipe_tile_cache
*tc
, int layer
)
345 struct pipe_transfer
*pt
= tc
->transfer
[layer
];
346 const uint w
= tc
->transfer
[layer
]->box
.width
;
347 const uint h
= tc
->transfer
[layer
]->box
.height
;
351 assert(pt
->resource
);
353 /* clear the scratch tile to the clear value */
354 if (tc
->depth_stencil
) {
355 clear_tile(tc
->tile
, pt
->resource
->format
, tc
->clear_val
);
357 clear_tile_rgba(tc
->tile
, pt
->resource
->format
, &tc
->clear_color
);
360 /* push the tile to all positions marked as clear */
361 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
362 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
363 union tile_address addr
= tile_address(x
, y
, layer
);
365 if (is_clear_flag_set(tc
->clear_flags
, addr
, tc
->clear_flags_size
)) {
366 /* write the scratch tile to the surface */
367 if (tc
->depth_stencil
) {
368 pipe_put_tile_raw(pt
, tc
->transfer_map
[layer
],
369 x
, y
, TILE_SIZE
, TILE_SIZE
,
370 tc
->tile
->data
.any
, 0/*STRIDE*/);
373 if (util_format_is_pure_uint(tc
->surface
->format
)) {
374 pipe_put_tile_ui_format(pt
, tc
->transfer_map
[layer
],
375 x
, y
, TILE_SIZE
, TILE_SIZE
,
376 pt
->resource
->format
,
377 (unsigned *) tc
->tile
->data
.colorui128
);
378 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
379 pipe_put_tile_i_format(pt
, tc
->transfer_map
[layer
],
380 x
, y
, TILE_SIZE
, TILE_SIZE
,
381 pt
->resource
->format
,
382 (int *) tc
->tile
->data
.colori128
);
384 pipe_put_tile_rgba(pt
, tc
->transfer_map
[layer
],
385 x
, y
, TILE_SIZE
, TILE_SIZE
,
386 (float *) tc
->tile
->data
.color
);
396 debug_printf("num cleared: %u\n", numCleared
);
401 sp_flush_tile(struct softpipe_tile_cache
* tc
, unsigned pos
)
403 int layer
= tc
->tile_addrs
[pos
].bits
.layer
;
404 if (!tc
->tile_addrs
[pos
].bits
.invalid
) {
405 if (tc
->depth_stencil
) {
406 pipe_put_tile_raw(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
407 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
408 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
409 TILE_SIZE
, TILE_SIZE
,
410 tc
->entries
[pos
]->data
.depth32
, 0/*STRIDE*/);
413 if (util_format_is_pure_uint(tc
->surface
->format
)) {
414 pipe_put_tile_ui_format(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
415 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
416 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
417 TILE_SIZE
, TILE_SIZE
,
419 (unsigned *) tc
->entries
[pos
]->data
.colorui128
);
420 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
421 pipe_put_tile_i_format(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
422 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
423 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
424 TILE_SIZE
, TILE_SIZE
,
426 (int *) tc
->entries
[pos
]->data
.colori128
);
428 pipe_put_tile_rgba_format(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
429 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
430 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
431 TILE_SIZE
, TILE_SIZE
,
433 (float *) tc
->entries
[pos
]->data
.color
);
436 tc
->tile_addrs
[pos
].bits
.invalid
= 1; /* mark as empty */
441 * Flush the tile cache: write all dirty tiles back to the transfer.
442 * any tiles "flagged" as cleared will be "really" cleared.
445 sp_flush_tile_cache(struct softpipe_tile_cache
*tc
)
450 /* caching a drawing transfer */
451 for (pos
= 0; pos
< Elements(tc
->entries
); pos
++) {
452 struct softpipe_cached_tile
*tile
= tc
->entries
[pos
];
455 assert(tc
->tile_addrs
[pos
].bits
.invalid
);
458 sp_flush_tile(tc
, pos
);
463 tc
->tile
= sp_alloc_tile(tc
);
465 for (i
= 0; i
< tc
->num_maps
; i
++)
466 sp_tile_cache_flush_clear(tc
, i
);
467 /* reset all clear flags to zero */
468 memset(tc
->clear_flags
, 0, tc
->clear_flags_size
);
470 tc
->last_tile_addr
.bits
.invalid
= 1;
474 debug_printf("flushed tiles in use: %d\n", inuse
);
478 static struct softpipe_cached_tile
*
479 sp_alloc_tile(struct softpipe_tile_cache
*tc
)
481 struct softpipe_cached_tile
* tile
= MALLOC_STRUCT(softpipe_cached_tile
);
484 /* in this case, steal an existing tile */
488 for (pos
= 0; pos
< Elements(tc
->entries
); ++pos
) {
489 if (!tc
->entries
[pos
])
492 sp_flush_tile(tc
, pos
);
493 tc
->tile
= tc
->entries
[pos
];
494 tc
->entries
[pos
] = NULL
;
498 /* this should never happen */
506 tc
->last_tile_addr
.bits
.invalid
= 1;
512 * Get a tile from the cache.
513 * \param x, y position of tile, in pixels
515 struct softpipe_cached_tile
*
516 sp_find_cached_tile(struct softpipe_tile_cache
*tc
,
517 union tile_address addr
)
519 struct pipe_transfer
*pt
;
520 /* cache pos/entry: */
521 const int pos
= CACHE_POS(addr
.bits
.x
,
522 addr
.bits
.y
, addr
.bits
.layer
);
523 struct softpipe_cached_tile
*tile
= tc
->entries
[pos
];
526 tile
= sp_alloc_tile(tc
);
527 tc
->entries
[pos
] = tile
;
530 if (addr
.value
!= tc
->tile_addrs
[pos
].value
) {
532 layer
= tc
->tile_addrs
[pos
].bits
.layer
;
533 if (tc
->tile_addrs
[pos
].bits
.invalid
== 0) {
534 /* put dirty tile back in framebuffer */
535 if (tc
->depth_stencil
) {
536 pipe_put_tile_raw(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
537 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
538 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
539 TILE_SIZE
, TILE_SIZE
,
540 tile
->data
.depth32
, 0/*STRIDE*/);
543 if (util_format_is_pure_uint(tc
->surface
->format
)) {
544 pipe_put_tile_ui_format(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
545 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
546 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
547 TILE_SIZE
, TILE_SIZE
,
549 (unsigned *) tile
->data
.colorui128
);
550 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
551 pipe_put_tile_i_format(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
552 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
553 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
554 TILE_SIZE
, TILE_SIZE
,
556 (int *) tile
->data
.colori128
);
558 pipe_put_tile_rgba_format(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
559 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
560 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
561 TILE_SIZE
, TILE_SIZE
,
563 (float *) tile
->data
.color
);
568 tc
->tile_addrs
[pos
] = addr
;
570 layer
= tc
->tile_addrs
[pos
].bits
.layer
;
571 pt
= tc
->transfer
[layer
];
572 assert(pt
->resource
);
574 if (is_clear_flag_set(tc
->clear_flags
, addr
, tc
->clear_flags_size
)) {
575 /* don't get tile from framebuffer, just clear it */
576 if (tc
->depth_stencil
) {
577 clear_tile(tile
, pt
->resource
->format
, tc
->clear_val
);
580 clear_tile_rgba(tile
, pt
->resource
->format
, &tc
->clear_color
);
582 clear_clear_flag(tc
->clear_flags
, addr
, tc
->clear_flags_size
);
585 /* get new tile data from transfer */
586 if (tc
->depth_stencil
) {
587 pipe_get_tile_raw(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
588 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
589 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
590 TILE_SIZE
, TILE_SIZE
,
591 tile
->data
.depth32
, 0/*STRIDE*/);
594 if (util_format_is_pure_uint(tc
->surface
->format
)) {
595 pipe_get_tile_ui_format(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
596 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
597 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
598 TILE_SIZE
, TILE_SIZE
,
600 (unsigned *) tile
->data
.colorui128
);
601 } else if (util_format_is_pure_sint(tc
->surface
->format
)) {
602 pipe_get_tile_i_format(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
603 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
604 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
605 TILE_SIZE
, TILE_SIZE
,
607 (int *) tile
->data
.colori128
);
609 pipe_get_tile_rgba_format(tc
->transfer
[layer
], tc
->transfer_map
[layer
],
610 tc
->tile_addrs
[pos
].bits
.x
* TILE_SIZE
,
611 tc
->tile_addrs
[pos
].bits
.y
* TILE_SIZE
,
612 TILE_SIZE
, TILE_SIZE
,
614 (float *) tile
->data
.color
);
620 tc
->last_tile
= tile
;
621 tc
->last_tile_addr
= addr
;
630 * When a whole surface is being cleared to a value we can avoid
631 * fetching tiles above.
632 * Save the color and set a 'clearflag' for each tile of the screen.
635 sp_tile_cache_clear(struct softpipe_tile_cache
*tc
,
636 const union pipe_color_union
*color
,
641 tc
->clear_color
= *color
;
643 tc
->clear_val
= clearValue
;
645 /* set flags to indicate all the tiles are cleared */
646 memset(tc
->clear_flags
, 255, tc
->clear_flags_size
);
648 for (pos
= 0; pos
< Elements(tc
->tile_addrs
); pos
++) {
649 tc
->tile_addrs
[pos
].bits
.invalid
= 1;
651 tc
->last_tile_addr
.bits
.invalid
= 1;