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 CLEAR_OPTIMIZATION 0
43 #define NUM_ENTRIES 20
47 #define MAX_WIDTH 2048
48 #define MAX_HEIGHT 2048
51 struct softpipe_tile_cache
53 struct pipe_surface
*surface
; /**< the surface we're caching */
54 struct pipe_texture
*texture
; /**< if caching a texture */
55 struct softpipe_cached_tile entries
[NUM_ENTRIES
];
56 uint clear_flags
[(MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32];
62 * Return the position in the cache for the tile that contains win pos (x,y).
63 * We currently use a direct mapped cache so this is like a hack key.
64 * At some point we should investige something more sophisticated, like
65 * a LRU replacement policy.
67 #define CACHE_POS(x, y) \
68 (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
73 is_clear_flag_set(const uint
*bitvec
, int x
, int y
)
78 pos
= y
* (MAX_WIDTH
/ TILE_SIZE
) + x
;
79 assert(pos
/ 32 < (MAX_WIDTH
/ TILE_SIZE
) * (MAX_HEIGHT
/ TILE_SIZE
) / 32);
80 bit
= bitvec
[pos
/ 32] & (1 << (pos
& 31));
86 clear_clear_flag(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 bitvec
[pos
/ 32] &= ~(1 << (pos
& 31));
97 struct softpipe_tile_cache
*
98 sp_create_tile_cache(void)
100 struct softpipe_tile_cache
*tc
;
103 tc
= CALLOC_STRUCT( softpipe_tile_cache
);
105 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
107 tc
->entries
[pos
].y
= -1;
115 sp_destroy_tile_cache(struct softpipe_tile_cache
*tc
)
118 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
119 assert(tc
->entries
[pos
].x
< 0);
126 sp_tile_cache_set_surface(struct softpipe_tile_cache
*tc
,
127 struct pipe_surface
*ps
)
129 pipe_surface_reference(&tc
->surface
, ps
);
133 struct pipe_surface
*
134 sp_tile_cache_get_surface(struct softpipe_tile_cache
*tc
)
141 sp_tile_cache_set_texture(struct softpipe_tile_cache
*tc
,
142 struct pipe_texture
*texture
)
146 tc
->texture
= texture
;
148 /* mark as entries as invalid/empty */
149 /* XXX we should try to avoid this when the teximage hasn't changed */
150 for (i
= 0; i
< NUM_ENTRIES
; i
++) {
151 tc
->entries
[i
].x
= -1;
157 sp_flush_tile_cache(struct softpipe_context
*softpipe
,
158 struct softpipe_tile_cache
*tc
)
160 struct pipe_context
*pipe
= &softpipe
->pipe
;
161 struct pipe_surface
*ps
= tc
->surface
;
162 boolean is_depth_stencil
;
165 if (!ps
|| !ps
->region
|| !ps
->region
->map
)
168 is_depth_stencil
= (ps
->format
== PIPE_FORMAT_S8_Z24
||
169 ps
->format
== PIPE_FORMAT_Z24_S8
||
170 ps
->format
== PIPE_FORMAT_U_Z16
||
171 ps
->format
== PIPE_FORMAT_U_Z32
||
172 ps
->format
== PIPE_FORMAT_U_S8
);
174 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
175 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
177 if (is_depth_stencil
) {
178 pipe
->put_tile(pipe
, ps
,
179 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
180 tile
->data
.depth32
, 0/*STRIDE*/);
183 pipe
->put_tile_rgba(pipe
, ps
,
184 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
185 (float *) tile
->data
.color
);
188 tile
->x
= tile
->y
= -1; /* mark as empty */
194 printf("flushed tiles in use: %d\n", inuse);
199 struct softpipe_cached_tile
*
200 sp_get_cached_tile(struct softpipe_context
*softpipe
,
201 struct softpipe_tile_cache
*tc
, int x
, int y
)
203 struct pipe_context
*pipe
= &softpipe
->pipe
;
204 struct pipe_surface
*ps
= tc
->surface
;
205 boolean is_depth_stencil
206 = (ps
->format
== PIPE_FORMAT_S8_Z24
||
207 ps
->format
== PIPE_FORMAT_Z24_S8
||
208 ps
->format
== PIPE_FORMAT_U_Z16
||
209 ps
->format
== PIPE_FORMAT_U_Z32
||
210 ps
->format
== PIPE_FORMAT_U_S8
);
212 /* tile pos in framebuffer: */
213 const int tile_x
= x
& ~(TILE_SIZE
- 1);
214 const int tile_y
= y
& ~(TILE_SIZE
- 1);
216 /* cache pos/entry: */
217 const int pos
= CACHE_POS(x
, y
);
218 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
220 if (tile_x
!= tile
->x
||
224 /* put dirty tile back in framebuffer */
225 if (is_depth_stencil
) {
226 pipe
->put_tile(pipe
, ps
,
227 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
228 tile
->data
.depth32
, 0 /*STRIDE*/);
231 pipe
->put_tile_rgba(pipe
, ps
,
232 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
233 (float *) tile
->data
.color
);
237 if (is_clear_flag_set(tc
->clear_flags
, x
, y
)) {
238 /* don't get tile from framebuffer, just clear it */
240 /* XXX these loops could be optimized */
241 switch (ps
->format
) {
242 case PIPE_FORMAT_U_Z16
:
244 ushort clear_val
= (ushort
) (tc
->clear_value
[0] * 0xffff);
245 for (i
= 0; i
< TILE_SIZE
; i
++) {
246 for (j
= 0; j
< TILE_SIZE
; j
++) {
247 tile
->data
.depth16
[i
][j
] = clear_val
;
252 case PIPE_FORMAT_U_Z32
:
254 uint clear_val
= (uint
) (tc
->clear_value
[0] * 0xffffffff);
255 for (i
= 0; i
< TILE_SIZE
; i
++) {
256 for (j
= 0; j
< TILE_SIZE
; j
++) {
257 tile
->data
.depth32
[i
][j
] = clear_val
;
262 case PIPE_FORMAT_S8_Z24
:
264 uint clear_val
= (uint
) (tc
->clear_value
[0] * 0xffffff);
265 clear_val
|= ((uint
) tc
->clear_value
[1]) << 24;
266 for (i
= 0; i
< TILE_SIZE
; i
++) {
267 for (j
= 0; j
< TILE_SIZE
; j
++) {
268 tile
->data
.depth32
[i
][j
] = clear_val
;
273 case PIPE_FORMAT_Z24_S8
:
275 uint clear_val
= ((uint
) (tc
->clear_value
[0] * 0xffffff)) << 8;
276 clear_val
|= ((uint
) tc
->clear_value
[1]) & 0xff;
277 for (i
= 0; i
< TILE_SIZE
; i
++) {
278 for (j
= 0; j
< TILE_SIZE
; j
++) {
279 tile
->data
.depth32
[i
][j
] = clear_val
;
284 case PIPE_FORMAT_U_S8
:
286 ubyte clear_val
= (uint
) tc
->clear_value
[0];
287 for (i
= 0; i
< TILE_SIZE
; i
++) {
288 for (j
= 0; j
< TILE_SIZE
; j
++) {
289 tile
->data
.stencil8
[i
][j
] = clear_val
;
296 for (i
= 0; i
< TILE_SIZE
; i
++) {
297 for (j
= 0; j
< TILE_SIZE
; j
++) {
298 tile
->data
.color
[i
][j
][0] = tc
->clear_value
[0];
299 tile
->data
.color
[i
][j
][1] = tc
->clear_value
[1];
300 tile
->data
.color
[i
][j
][2] = tc
->clear_value
[2];
301 tile
->data
.color
[i
][j
][3] = tc
->clear_value
[3];
305 clear_clear_flag(tc
->clear_flags
, x
, y
);
308 /* get new tile from framebuffer */
309 if (is_depth_stencil
) {
310 pipe
->get_tile(pipe
, ps
,
311 tile_x
, tile_y
, TILE_SIZE
, TILE_SIZE
,
312 tile
->data
.depth32
, 0/*STRIDE*/);
315 pipe
->get_tile_rgba(pipe
, ps
,
316 tile_x
, tile_y
, TILE_SIZE
, TILE_SIZE
,
317 (float *) tile
->data
.color
);
330 * Given the texture face, level, zslice, x and y values, compute
331 * the cache entry position/index where we'd hope to find the
332 * cached texture tile.
333 * This is basically a direct-map cache.
334 * XXX There's probably lots of ways in which we can improve this.
337 tex_cache_pos(int x
, int y
, int z
, int face
, int level
)
339 uint entry
= x
+ y
* 5 + z
* 4 + face
+ level
;
340 return entry
% NUM_ENTRIES
;
345 * Similar to sp_get_cached_tile() but for textures.
346 * Tiles are read-only and indexed with more params.
348 const struct softpipe_cached_tile
*
349 sp_get_cached_tile_tex(struct pipe_context
*pipe
,
350 struct softpipe_tile_cache
*tc
, int x
, int y
, int z
,
353 /* tile pos in framebuffer: */
354 const int tile_x
= x
& ~(TILE_SIZE
- 1);
355 const int tile_y
= y
& ~(TILE_SIZE
- 1);
356 /* cache pos/entry: */
357 const uint pos
= tex_cache_pos(x
/ TILE_SIZE
, y
/ TILE_SIZE
, z
,
359 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
361 if (tile_x
!= tile
->x
||
364 face
!= tile
->face
||
365 level
!= tile
->level
) {
366 /* XXX this call is a bit heavier than we'd like: */
367 struct pipe_surface
*ps
368 = pipe
->get_tex_surface(pipe
, tc
->texture
, face
, level
, z
);
370 pipe
->get_tile_rgba(pipe
, ps
,
371 tile_x
, tile_y
, TILE_SIZE
, TILE_SIZE
,
372 (float *) tile
->data
.color
);
374 pipe_surface_reference(&ps
, NULL
);
388 * When a whole surface is being cleared to a value we can avoid
389 * fetching tiles above.
390 * Save the color and set a 'clearflag' for each tile of the screen.
393 sp_tile_cache_clear(struct softpipe_tile_cache
*tc
, const float value
[4])
395 tc
->clear_value
[0] = value
[0];
396 tc
->clear_value
[1] = value
[1];
397 tc
->clear_value
[2] = value
[2];
398 tc
->clear_value
[3] = value
[3];
400 #if CLEAR_OPTIMIZATION
401 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
403 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));