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_util.h"
36 #include "pipe/p_inlines.h"
37 #include "sp_context.h"
38 #include "sp_surface.h"
39 #include "sp_tile_cache.h"
41 #define NUM_ENTRIES 30
45 #define MAX_WIDTH 2048
46 #define MAX_HEIGHT 2048
49 struct softpipe_tile_cache
51 struct pipe_surface
*surface
; /**< the surface we're caching */
52 struct pipe_texture
*texture
; /**< if caching a texture */
53 struct softpipe_cached_tile entries
[NUM_ENTRIES
];
54 uint clear_flags
[(MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32];
57 boolean depth_stencil
; /** Is the surface a depth/stencil format? */
59 struct pipe_surface
*tex_surf
;
60 int tex_face
, tex_level
, tex_z
;
65 * Return the position in the cache for the tile that contains win pos (x,y).
66 * We currently use a direct mapped cache so this is like a hack key.
67 * At some point we should investige something more sophisticated, like
68 * a LRU replacement policy.
70 #define CACHE_POS(x, y) \
71 (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
76 * Is the tile at (x,y) in cleared state?
79 is_clear_flag_set(const uint
*bitvec
, int x
, int y
)
84 pos
= y
* (MAX_WIDTH
/ TILE_SIZE
) + x
;
85 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
86 bit
= bitvec
[pos
/ 32] & (1 << (pos
& 31));
92 * Mark the tile at (x,y) as not cleared.
95 clear_clear_flag(uint
*bitvec
, int x
, int y
)
100 pos
= y
* (MAX_WIDTH
/ TILE_SIZE
) + x
;
101 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
102 bitvec
[pos
/ 32] &= ~(1 << (pos
& 31));
106 struct softpipe_tile_cache
*
107 sp_create_tile_cache(void)
109 struct softpipe_tile_cache
*tc
;
112 tc
= CALLOC_STRUCT( softpipe_tile_cache
);
114 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
116 tc
->entries
[pos
].y
= -1;
124 sp_destroy_tile_cache(struct softpipe_tile_cache
*tc
)
127 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
128 assert(tc
->entries
[pos
].x
< 0);
135 * Specify the surface to cache.
138 sp_tile_cache_set_surface(struct softpipe_tile_cache
*tc
,
139 struct pipe_surface
*ps
)
141 assert(!tc
->texture
);
143 if (tc
->surface
&& tc
->surface
->map
) {
144 assert(tc
->surface
!= ps
);
145 pipe_surface_unmap(tc
->surface
);
148 pipe_surface_reference(&tc
->surface
, ps
);
151 pipe_surface_map(ps
);
154 tc
->depth_stencil
= (ps
->format
== PIPE_FORMAT_S8Z24_UNORM
||
155 ps
->format
== PIPE_FORMAT_Z16_UNORM
||
156 ps
->format
== PIPE_FORMAT_Z32_UNORM
||
157 ps
->format
== PIPE_FORMAT_U_S8
);
163 * Return the surface being cached.
165 struct pipe_surface
*
166 sp_tile_cache_get_surface(struct softpipe_tile_cache
*tc
)
173 * Specify the texture to cache.
176 sp_tile_cache_set_texture(struct softpipe_tile_cache
*tc
,
177 struct pipe_texture
*texture
)
181 assert(!tc
->surface
);
183 tc
->texture
= texture
;
185 if (tc
->tex_surf
&& tc
->tex_surf
->map
)
186 pipe_surface_unmap(tc
->tex_surf
);
187 pipe_surface_reference(&tc
->tex_surf
, NULL
);
189 /* mark as entries as invalid/empty */
190 /* XXX we should try to avoid this when the teximage hasn't changed */
191 for (i
= 0; i
< NUM_ENTRIES
; i
++) {
192 tc
->entries
[i
].x
= -1;
195 tc
->tex_face
= -1; /* any invalid value here */
200 * Set pixels in a tile to the given clear color/value, float.
203 clear_tile_rgba(struct softpipe_cached_tile
*tile
,
204 enum pipe_format format
,
205 const float clear_value
[4])
207 if (clear_value
[0] == 0.0 &&
208 clear_value
[1] == 0.0 &&
209 clear_value
[2] == 0.0 &&
210 clear_value
[3] == 0.0) {
211 memset(tile
->data
.color
, 0, sizeof(tile
->data
.color
));
215 for (i
= 0; i
< TILE_SIZE
; i
++) {
216 for (j
= 0; j
< TILE_SIZE
; j
++) {
217 tile
->data
.color
[i
][j
][0] = clear_value
[0];
218 tile
->data
.color
[i
][j
][1] = clear_value
[1];
219 tile
->data
.color
[i
][j
][2] = clear_value
[2];
220 tile
->data
.color
[i
][j
][3] = clear_value
[3];
228 * Set a tile to a solid value/color.
231 clear_tile(struct softpipe_cached_tile
*tile
,
232 enum pipe_format format
,
238 case PIPE_FORMAT_U_S8
:
240 memset(tile
->data
.any
, 0, TILE_SIZE
* TILE_SIZE
);
242 case PIPE_FORMAT_Z16_UNORM
:
244 if (clear_value
== 0) {
245 memset(tile
->data
.any
, 0, 2 * TILE_SIZE
* TILE_SIZE
);
248 for (i
= 0; i
< TILE_SIZE
; i
++) {
249 for (j
= 0; j
< TILE_SIZE
; j
++) {
250 tile
->data
.depth16
[i
][j
] = clear_value
;
257 if (clear_value
== 0) {
258 memset(tile
->data
.any
, 0, 4 * TILE_SIZE
* TILE_SIZE
);
261 for (i
= 0; i
< TILE_SIZE
; i
++) {
262 for (j
= 0; j
< TILE_SIZE
; j
++) {
263 tile
->data
.color32
[i
][j
] = clear_value
;
272 * Actually clear the tiles which were flagged as being in a clear state.
275 sp_tile_cache_flush_clear(struct pipe_context
*pipe
,
276 struct softpipe_tile_cache
*tc
)
278 struct pipe_surface
*ps
= tc
->surface
;
279 const uint w
= tc
->surface
->width
;
280 const uint h
= tc
->surface
->height
;
282 struct softpipe_cached_tile tile
;
285 /* clear one tile to the clear value */
286 clear_tile(&tile
, ps
->format
, tc
->clear_val
);
288 /* push the tile to all positions marked as clear */
289 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
290 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
291 if (is_clear_flag_set(tc
->clear_flags
, x
, y
)) {
292 pipe
->put_tile(pipe
, ps
,
293 x
, y
, TILE_SIZE
, TILE_SIZE
,
294 tile
.data
.color32
, 0/*STRIDE*/);
297 clear_clear_flag(tc
->clear_flags
, x
, y
);
304 printf("num cleared: %u\n", numCleared
);
310 * Flush the tile cache: write all dirty tiles back to the surface.
311 * any tiles "flagged" as cleared will be "really" cleared.
314 sp_flush_tile_cache(struct softpipe_context
*softpipe
,
315 struct softpipe_tile_cache
*tc
)
317 struct pipe_context
*pipe
= &softpipe
->pipe
;
318 struct pipe_surface
*ps
= tc
->surface
;
321 if (!ps
|| !ps
->buffer
)
325 pipe_surface_map(ps
);
327 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
328 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
330 if (tc
->depth_stencil
) {
331 pipe
->put_tile(pipe
, ps
,
332 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
333 tile
->data
.depth32
, 0/*STRIDE*/);
336 pipe
->put_tile_rgba(pipe
, ps
,
337 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
338 (float *) tile
->data
.color
);
340 tile
->x
= tile
->y
= -1; /* mark as empty */
345 #if TILE_CLEAR_OPTIMIZATION
346 sp_tile_cache_flush_clear(&softpipe
->pipe
, tc
);
350 printf("flushed tiles in use: %d\n", inuse
);
356 * Get a tile from the cache.
357 * \param x, y position of tile, in pixels
359 struct softpipe_cached_tile
*
360 sp_get_cached_tile(struct softpipe_context
*softpipe
,
361 struct softpipe_tile_cache
*tc
, int x
, int y
)
363 struct pipe_context
*pipe
= &softpipe
->pipe
;
364 struct pipe_surface
*ps
= tc
->surface
;
366 /* tile pos in framebuffer: */
367 const int tile_x
= x
& ~(TILE_SIZE
- 1);
368 const int tile_y
= y
& ~(TILE_SIZE
- 1);
370 /* cache pos/entry: */
371 const int pos
= CACHE_POS(x
, y
);
372 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
374 if (tile_x
!= tile
->x
||
378 /* put dirty tile back in framebuffer */
379 if (tc
->depth_stencil
) {
380 pipe
->put_tile(pipe
, ps
,
381 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
382 tile
->data
.depth32
, 0/*STRIDE*/);
385 pipe
->put_tile_rgba(pipe
, ps
,
386 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
387 (float *) tile
->data
.color
);
394 if (is_clear_flag_set(tc
->clear_flags
, x
, y
)) {
395 /* don't get tile from framebuffer, just clear it */
396 if (tc
->depth_stencil
) {
397 clear_tile(tile
, ps
->format
, tc
->clear_val
);
400 clear_tile_rgba(tile
, ps
->format
, tc
->clear_color
);
402 clear_clear_flag(tc
->clear_flags
, x
, y
);
405 /* get new tile data from surface */
406 if (tc
->depth_stencil
) {
407 pipe
->get_tile(pipe
, ps
,
408 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
409 tile
->data
.depth32
, 0/*STRIDE*/);
412 pipe
->get_tile_rgba(pipe
, ps
,
413 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
414 (float *) tile
->data
.color
);
424 * Given the texture face, level, zslice, x and y values, compute
425 * the cache entry position/index where we'd hope to find the
426 * cached texture tile.
427 * This is basically a direct-map cache.
428 * XXX There's probably lots of ways in which we can improve this.
431 tex_cache_pos(int x
, int y
, int z
, int face
, int level
)
433 uint entry
= x
+ y
* 5 + z
* 4 + face
+ level
;
434 return entry
% NUM_ENTRIES
;
439 * Similar to sp_get_cached_tile() but for textures.
440 * Tiles are read-only and indexed with more params.
442 const struct softpipe_cached_tile
*
443 sp_get_cached_tile_tex(struct pipe_context
*pipe
,
444 struct softpipe_tile_cache
*tc
, int x
, int y
, int z
,
447 /* tile pos in framebuffer: */
448 const int tile_x
= x
& ~(TILE_SIZE
- 1);
449 const int tile_y
= y
& ~(TILE_SIZE
- 1);
450 /* cache pos/entry: */
451 const uint pos
= tex_cache_pos(x
/ TILE_SIZE
, y
/ TILE_SIZE
, z
,
453 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
455 if (tile_x
!= tile
->x
||
458 face
!= tile
->face
||
459 level
!= tile
->level
) {
462 /* check if we need to get a new surface */
464 tc
->tex_face
!= face
||
465 tc
->tex_level
!= level
||
467 /* get new surface (view into texture) */
468 struct pipe_surface
*ps
;
470 if (tc
->tex_surf
&& tc
->tex_surf
->map
)
471 pipe_surface_unmap(tc
->tex_surf
);
473 ps
= pipe
->get_tex_surface(pipe
, tc
->texture
, face
, level
, z
);
474 pipe_surface_reference(&tc
->tex_surf
, ps
);
476 pipe_surface_map(ps
);
479 tc
->tex_level
= level
;
483 /* get tile from the surface (view into texture) */
484 pipe
->get_tile_rgba(pipe
, tc
->tex_surf
,
485 tile_x
, tile_y
, TILE_SIZE
, TILE_SIZE
,
486 (float *) tile
->data
.color
);
499 * When a whole surface is being cleared to a value we can avoid
500 * fetching tiles above.
501 * Save the color and set a 'clearflag' for each tile of the screen.
504 sp_tile_cache_clear(struct softpipe_tile_cache
*tc
, uint clearValue
)
508 tc
->clear_val
= clearValue
;
510 switch (tc
->surface
->format
) {
511 case PIPE_FORMAT_R8G8B8A8_UNORM
:
512 r
= (clearValue
>> 24) & 0xff;
513 g
= (clearValue
>> 16) & 0xff;
514 b
= (clearValue
>> 8) & 0xff;
515 a
= (clearValue
) & 0xff;
517 case PIPE_FORMAT_A8R8G8B8_UNORM
:
518 r
= (clearValue
>> 16) & 0xff;
519 g
= (clearValue
>> 8) & 0xff;
520 b
= (clearValue
) & 0xff;
521 a
= (clearValue
>> 24) & 0xff;
523 case PIPE_FORMAT_B8G8R8A8_UNORM
:
524 r
= (clearValue
>> 8) & 0xff;
525 g
= (clearValue
>> 16) & 0xff;
526 b
= (clearValue
>> 24) & 0xff;
527 a
= (clearValue
) & 0xff;
533 tc
->clear_color
[0] = r
/ 255.0;
534 tc
->clear_color
[1] = g
/ 255.0;
535 tc
->clear_color
[2] = b
/ 255.0;
536 tc
->clear_color
[3] = a
/ 255.0;
538 #if TILE_CLEAR_OPTIMIZATION
539 /* set flags to indicate all the tiles are cleared */
540 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
542 /* disable the optimization */
543 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));