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 * Framebuffer/surface tile caching.
35 #include "pipe/p_inlines.h"
36 #include "util/u_memory.h"
37 #include "util/u_tile.h"
38 #include "sp_context.h"
39 #include "sp_surface.h"
40 #include "sp_texture.h"
41 #include "sp_tile_cache.h"
43 #define NUM_ENTRIES 32
47 #define MAX_WIDTH 2048
48 #define MAX_HEIGHT 2048
51 struct softpipe_tile_cache
53 struct pipe_screen
*screen
;
54 struct pipe_surface
*surface
; /**< the surface we're caching */
56 struct pipe_texture
*texture
; /**< if caching a texture */
57 struct softpipe_cached_tile entries
[NUM_ENTRIES
];
58 uint clear_flags
[(MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32];
61 boolean depth_stencil
; /** Is the surface a depth/stencil format? */
63 struct pipe_surface
*tex_surf
;
65 int tex_face
, tex_level
, tex_z
;
67 struct softpipe_cached_tile tile
; /**< scratch tile for clears */
72 * Return the position in the cache for the tile that contains win pos (x,y).
73 * We currently use a direct mapped cache so this is like a hack key.
74 * At some point we should investige something more sophisticated, like
75 * a LRU replacement policy.
77 #define CACHE_POS(x, y) \
78 (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
83 * Is the tile at (x,y) in cleared state?
86 is_clear_flag_set(const uint
*bitvec
, int x
, int y
)
91 pos
= y
* (MAX_WIDTH
/ TILE_SIZE
) + x
;
92 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
93 bit
= bitvec
[pos
/ 32] & (1 << (pos
& 31));
99 * Mark the tile at (x,y) as not cleared.
102 clear_clear_flag(uint
*bitvec
, int x
, int y
)
107 pos
= y
* (MAX_WIDTH
/ TILE_SIZE
) + x
;
108 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
109 bitvec
[pos
/ 32] &= ~(1 << (pos
& 31));
113 struct softpipe_tile_cache
*
114 sp_create_tile_cache( struct pipe_screen
*screen
)
116 struct softpipe_tile_cache
*tc
;
119 tc
= CALLOC_STRUCT( softpipe_tile_cache
);
122 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
124 tc
->entries
[pos
].y
= -1;
132 sp_destroy_tile_cache(struct softpipe_tile_cache
*tc
)
136 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
137 /*assert(tc->entries[pos].x < 0);*/
140 pipe_surface_reference(&tc
->surface
, NULL
);
143 pipe_surface_reference(&tc
->tex_surf
, NULL
);
151 * Specify the surface to cache.
154 sp_tile_cache_set_surface(struct softpipe_tile_cache
*tc
,
155 struct pipe_surface
*ps
)
157 assert(!tc
->texture
);
159 if (tc
->surface_map
) {
160 tc
->screen
->surface_unmap(tc
->screen
, tc
->surface
);
161 tc
->surface_map
= NULL
;
164 pipe_surface_reference(&tc
->surface
, ps
);
167 if (tc
->surface_map
) /* XXX: this is always NULL!? */
168 tc
->surface_map
= tc
->screen
->surface_map(tc
->screen
, tc
->surface
,
169 PIPE_BUFFER_USAGE_CPU_READ
|
170 PIPE_BUFFER_USAGE_CPU_WRITE
);
172 tc
->depth_stencil
= (ps
->format
== PIPE_FORMAT_S8Z24_UNORM
||
173 ps
->format
== PIPE_FORMAT_X8Z24_UNORM
||
174 ps
->format
== PIPE_FORMAT_Z24S8_UNORM
||
175 ps
->format
== PIPE_FORMAT_Z24X8_UNORM
||
176 ps
->format
== PIPE_FORMAT_Z16_UNORM
||
177 ps
->format
== PIPE_FORMAT_Z32_UNORM
||
178 ps
->format
== PIPE_FORMAT_S8_UNORM
);
184 * Return the surface being cached.
186 struct pipe_surface
*
187 sp_tile_cache_get_surface(struct softpipe_tile_cache
*tc
)
194 sp_tile_cache_map_surfaces(struct softpipe_tile_cache
*tc
)
196 if (tc
->surface
&& !tc
->surface_map
)
197 tc
->surface_map
= tc
->screen
->surface_map(tc
->screen
, tc
->surface
,
198 PIPE_BUFFER_USAGE_CPU_WRITE
|
199 PIPE_BUFFER_USAGE_CPU_READ
);
201 if (tc
->tex_surf
&& !tc
->tex_surf_map
)
202 tc
->tex_surf_map
= tc
->screen
->surface_map(tc
->screen
, tc
->tex_surf
,
203 PIPE_BUFFER_USAGE_CPU_READ
);
208 sp_tile_cache_unmap_surfaces(struct softpipe_tile_cache
*tc
)
210 if (tc
->surface_map
) {
211 tc
->screen
->surface_unmap(tc
->screen
, tc
->surface
);
212 tc
->surface_map
= NULL
;
215 if (tc
->tex_surf_map
) {
216 tc
->screen
->surface_unmap(tc
->screen
, tc
->tex_surf
);
217 tc
->tex_surf_map
= NULL
;
223 * Specify the texture to cache.
226 sp_tile_cache_set_texture(struct pipe_context
*pipe
,
227 struct softpipe_tile_cache
*tc
,
228 struct pipe_texture
*texture
)
232 assert(!tc
->surface
);
234 pipe_texture_reference(&tc
->texture
, texture
);
236 if (tc
->tex_surf_map
) {
237 tc
->screen
->surface_unmap(tc
->screen
, tc
->tex_surf
);
238 tc
->tex_surf_map
= NULL
;
240 pipe_surface_reference(&tc
->tex_surf
, NULL
);
242 /* mark as entries as invalid/empty */
243 /* XXX we should try to avoid this when the teximage hasn't changed */
244 for (i
= 0; i
< NUM_ENTRIES
; i
++) {
245 tc
->entries
[i
].x
= -1;
248 tc
->tex_face
= -1; /* any invalid value here */
253 * Set pixels in a tile to the given clear color/value, float.
256 clear_tile_rgba(struct softpipe_cached_tile
*tile
,
257 enum pipe_format format
,
258 const float clear_value
[4])
260 if (clear_value
[0] == 0.0 &&
261 clear_value
[1] == 0.0 &&
262 clear_value
[2] == 0.0 &&
263 clear_value
[3] == 0.0) {
264 memset(tile
->data
.color
, 0, sizeof(tile
->data
.color
));
268 for (i
= 0; i
< TILE_SIZE
; i
++) {
269 for (j
= 0; j
< TILE_SIZE
; j
++) {
270 tile
->data
.color
[i
][j
][0] = clear_value
[0];
271 tile
->data
.color
[i
][j
][1] = clear_value
[1];
272 tile
->data
.color
[i
][j
][2] = clear_value
[2];
273 tile
->data
.color
[i
][j
][3] = clear_value
[3];
281 * Set a tile to a solid value/color.
284 clear_tile(struct softpipe_cached_tile
*tile
,
285 enum pipe_format format
,
290 switch (pf_get_size(format
)) {
292 memset(tile
->data
.any
, 0, TILE_SIZE
* TILE_SIZE
);
295 if (clear_value
== 0) {
296 memset(tile
->data
.any
, 0, 2 * TILE_SIZE
* TILE_SIZE
);
299 for (i
= 0; i
< TILE_SIZE
; i
++) {
300 for (j
= 0; j
< TILE_SIZE
; j
++) {
301 tile
->data
.depth16
[i
][j
] = (ushort
) clear_value
;
307 if (clear_value
== 0) {
308 memset(tile
->data
.any
, 0, 4 * TILE_SIZE
* TILE_SIZE
);
311 for (i
= 0; i
< TILE_SIZE
; i
++) {
312 for (j
= 0; j
< TILE_SIZE
; j
++) {
313 tile
->data
.color32
[i
][j
] = clear_value
;
325 * Actually clear the tiles which were flagged as being in a clear state.
328 sp_tile_cache_flush_clear(struct pipe_context
*pipe
,
329 struct softpipe_tile_cache
*tc
)
331 struct pipe_surface
*ps
= tc
->surface
;
332 const uint w
= tc
->surface
->width
;
333 const uint h
= tc
->surface
->height
;
337 /* clear the scratch tile to the clear value */
338 clear_tile(&tc
->tile
, ps
->format
, tc
->clear_val
);
340 /* push the tile to all positions marked as clear */
341 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
342 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
343 if (is_clear_flag_set(tc
->clear_flags
, x
, y
)) {
344 pipe_put_tile_raw(ps
,
345 x
, y
, TILE_SIZE
, TILE_SIZE
,
346 tc
->tile
.data
.color32
, 0/*STRIDE*/);
349 clear_clear_flag(tc
->clear_flags
, x
, y
);
356 debug_printf("num cleared: %u\n", numCleared
);
362 * Flush the tile cache: write all dirty tiles back to the surface.
363 * any tiles "flagged" as cleared will be "really" cleared.
366 sp_flush_tile_cache(struct softpipe_context
*softpipe
,
367 struct softpipe_tile_cache
*tc
)
369 struct pipe_surface
*ps
= tc
->surface
;
373 /* caching a drawing surface */
374 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
375 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
377 if (tc
->depth_stencil
) {
378 pipe_put_tile_raw(ps
,
379 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
380 tile
->data
.depth32
, 0/*STRIDE*/);
383 pipe_put_tile_rgba(ps
,
384 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
385 (float *) tile
->data
.color
);
387 tile
->x
= tile
->y
= -1; /* mark as empty */
392 #if TILE_CLEAR_OPTIMIZATION
393 sp_tile_cache_flush_clear(&softpipe
->pipe
, tc
);
396 else if (tc
->texture
) {
397 /* caching a texture, mark all entries as empty */
398 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
399 tc
->entries
[pos
].x
= -1;
405 debug_printf("flushed tiles in use: %d\n", inuse
);
411 * Get a tile from the cache.
412 * \param x, y position of tile, in pixels
414 struct softpipe_cached_tile
*
415 sp_get_cached_tile(struct softpipe_context
*softpipe
,
416 struct softpipe_tile_cache
*tc
, int x
, int y
)
418 struct pipe_surface
*ps
= tc
->surface
;
420 /* tile pos in framebuffer: */
421 const int tile_x
= x
& ~(TILE_SIZE
- 1);
422 const int tile_y
= y
& ~(TILE_SIZE
- 1);
424 /* cache pos/entry: */
425 const int pos
= CACHE_POS(x
, y
);
426 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
428 if (tile_x
!= tile
->x
||
432 /* put dirty tile back in framebuffer */
433 if (tc
->depth_stencil
) {
434 pipe_put_tile_raw(ps
,
435 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
436 tile
->data
.depth32
, 0/*STRIDE*/);
439 pipe_put_tile_rgba(ps
,
440 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
441 (float *) tile
->data
.color
);
448 if (is_clear_flag_set(tc
->clear_flags
, x
, y
)) {
449 /* don't get tile from framebuffer, just clear it */
450 if (tc
->depth_stencil
) {
451 clear_tile(tile
, ps
->format
, tc
->clear_val
);
454 clear_tile_rgba(tile
, ps
->format
, tc
->clear_color
);
456 clear_clear_flag(tc
->clear_flags
, x
, y
);
459 /* get new tile data from surface */
460 if (tc
->depth_stencil
) {
461 pipe_get_tile_raw(ps
,
462 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
463 tile
->data
.depth32
, 0/*STRIDE*/);
466 pipe_get_tile_rgba(ps
,
467 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
468 (float *) tile
->data
.color
);
478 * Given the texture face, level, zslice, x and y values, compute
479 * the cache entry position/index where we'd hope to find the
480 * cached texture tile.
481 * This is basically a direct-map cache.
482 * XXX There's probably lots of ways in which we can improve this.
485 tex_cache_pos(int x
, int y
, int z
, int face
, int level
)
487 uint entry
= x
+ y
* 5 + z
* 4 + face
+ level
;
488 return entry
% NUM_ENTRIES
;
493 * Similar to sp_get_cached_tile() but for textures.
494 * Tiles are read-only and indexed with more params.
496 const struct softpipe_cached_tile
*
497 sp_get_cached_tile_tex(struct softpipe_context
*sp
,
498 struct softpipe_tile_cache
*tc
, int x
, int y
, int z
,
501 struct pipe_screen
*screen
= sp
->pipe
.screen
;
502 /* tile pos in framebuffer: */
503 const int tile_x
= x
& ~(TILE_SIZE
- 1);
504 const int tile_y
= y
& ~(TILE_SIZE
- 1);
505 /* cache pos/entry: */
506 const uint pos
= tex_cache_pos(x
/ TILE_SIZE
, y
/ TILE_SIZE
, z
,
508 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
511 struct softpipe_texture
*spt
= softpipe_texture(tc
->texture
);
513 /* texture was modified, force a cache reload */
515 spt
->modified
= FALSE
;
519 if (tile_x
!= tile
->x
||
522 face
!= tile
->face
||
523 level
!= tile
->level
) {
526 /* check if we need to get a new surface */
528 tc
->tex_face
!= face
||
529 tc
->tex_level
!= level
||
531 /* get new surface (view into texture) */
533 if (tc
->tex_surf_map
)
534 tc
->screen
->surface_unmap(tc
->screen
, tc
->tex_surf
);
536 tc
->tex_surf
= screen
->get_tex_surface(screen
, tc
->texture
, face
, level
, z
,
537 PIPE_BUFFER_USAGE_CPU_READ
);
538 tc
->tex_surf_map
= screen
->surface_map(screen
, tc
->tex_surf
,
539 PIPE_BUFFER_USAGE_CPU_READ
);
542 tc
->tex_level
= level
;
546 /* get tile from the surface (view into texture) */
547 pipe_get_tile_rgba(tc
->tex_surf
,
548 tile_x
, tile_y
, TILE_SIZE
, TILE_SIZE
,
549 (float *) tile
->data
.color
);
562 * When a whole surface is being cleared to a value we can avoid
563 * fetching tiles above.
564 * Save the color and set a 'clearflag' for each tile of the screen.
567 sp_tile_cache_clear(struct softpipe_tile_cache
*tc
, uint clearValue
)
572 tc
->clear_val
= clearValue
;
574 switch (tc
->surface
->format
) {
575 case PIPE_FORMAT_R8G8B8A8_UNORM
:
576 r
= (clearValue
>> 24) & 0xff;
577 g
= (clearValue
>> 16) & 0xff;
578 b
= (clearValue
>> 8) & 0xff;
579 a
= (clearValue
) & 0xff;
581 case PIPE_FORMAT_A8R8G8B8_UNORM
:
582 r
= (clearValue
>> 16) & 0xff;
583 g
= (clearValue
>> 8) & 0xff;
584 b
= (clearValue
) & 0xff;
585 a
= (clearValue
>> 24) & 0xff;
587 case PIPE_FORMAT_B8G8R8A8_UNORM
:
588 r
= (clearValue
>> 8) & 0xff;
589 g
= (clearValue
>> 16) & 0xff;
590 b
= (clearValue
>> 24) & 0xff;
591 a
= (clearValue
) & 0xff;
597 tc
->clear_color
[0] = r
/ 255.0f
;
598 tc
->clear_color
[1] = g
/ 255.0f
;
599 tc
->clear_color
[2] = b
/ 255.0f
;
600 tc
->clear_color
[3] = a
/ 255.0f
;
602 #if TILE_CLEAR_OPTIMIZATION
603 /* set flags to indicate all the tiles are cleared */
604 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
606 /* disable the optimization */
607 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));
610 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
611 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
612 tile
->x
= tile
->y
= -1;