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_context
*sp
,
127 struct softpipe_tile_cache
*tc
,
128 struct pipe_surface
*ps
)
130 if (tc
->surface
&& tc
->surface
->map
)
131 pipe_surface_unmap(tc
->surface
);
133 pipe_surface_reference(&tc
->surface
, ps
);
137 struct pipe_surface
*
138 sp_tile_cache_get_surface(struct softpipe_context
*sp
,
139 struct softpipe_tile_cache
*tc
)
141 if (tc
->surface
&& !tc
->surface
->map
)
142 pipe_surface_map(tc
->surface
);
149 sp_tile_cache_set_texture(struct softpipe_tile_cache
*tc
,
150 struct pipe_texture
*texture
)
154 tc
->texture
= texture
;
156 /* mark as entries as invalid/empty */
157 /* XXX we should try to avoid this when the teximage hasn't changed */
158 for (i
= 0; i
< NUM_ENTRIES
; i
++) {
159 tc
->entries
[i
].x
= -1;
165 sp_flush_tile_cache(struct softpipe_context
*softpipe
,
166 struct softpipe_tile_cache
*tc
)
168 struct pipe_context
*pipe
= &softpipe
->pipe
;
169 struct pipe_surface
*ps
= tc
->surface
;
170 boolean is_depth_stencil
;
173 if (!ps
|| !ps
->buffer
)
176 is_depth_stencil
= (ps
->format
== PIPE_FORMAT_S8_Z24
||
177 ps
->format
== PIPE_FORMAT_Z24_S8
||
178 ps
->format
== PIPE_FORMAT_U_Z16
||
179 ps
->format
== PIPE_FORMAT_U_Z32
||
180 ps
->format
== PIPE_FORMAT_U_S8
);
182 for (pos
= 0; pos
< NUM_ENTRIES
; pos
++) {
183 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
185 if (is_depth_stencil
) {
186 pipe
->put_tile(pipe
, ps
,
187 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
188 tile
->data
.depth32
, 0/*STRIDE*/);
191 pipe
->put_tile_rgba(pipe
, ps
,
192 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
193 (float *) tile
->data
.color
);
196 tile
->x
= tile
->y
= -1; /* mark as empty */
202 printf("flushed tiles in use: %d\n", inuse);
207 struct softpipe_cached_tile
*
208 sp_get_cached_tile(struct softpipe_context
*softpipe
,
209 struct softpipe_tile_cache
*tc
, int x
, int y
)
211 struct pipe_context
*pipe
= &softpipe
->pipe
;
212 struct pipe_surface
*ps
= tc
->surface
;
213 boolean is_depth_stencil
214 = (ps
->format
== PIPE_FORMAT_S8_Z24
||
215 ps
->format
== PIPE_FORMAT_Z24_S8
||
216 ps
->format
== PIPE_FORMAT_U_Z16
||
217 ps
->format
== PIPE_FORMAT_U_Z32
||
218 ps
->format
== PIPE_FORMAT_U_S8
);
220 /* tile pos in framebuffer: */
221 const int tile_x
= x
& ~(TILE_SIZE
- 1);
222 const int tile_y
= y
& ~(TILE_SIZE
- 1);
224 /* cache pos/entry: */
225 const int pos
= CACHE_POS(x
, y
);
226 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
228 if (tile_x
!= tile
->x
||
232 /* put dirty tile back in framebuffer */
233 if (is_depth_stencil
) {
234 pipe
->put_tile(pipe
, ps
,
235 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
236 tile
->data
.depth32
, 0 /*STRIDE*/);
239 pipe
->put_tile_rgba(pipe
, ps
,
240 tile
->x
, tile
->y
, TILE_SIZE
, TILE_SIZE
,
241 (float *) tile
->data
.color
);
245 if (is_clear_flag_set(tc
->clear_flags
, x
, y
)) {
246 /* don't get tile from framebuffer, just clear it */
248 /* XXX these loops could be optimized */
249 switch (ps
->format
) {
250 case PIPE_FORMAT_U_Z16
:
252 ushort clear_val
= (ushort
) (tc
->clear_value
[0] * 0xffff);
253 for (i
= 0; i
< TILE_SIZE
; i
++) {
254 for (j
= 0; j
< TILE_SIZE
; j
++) {
255 tile
->data
.depth16
[i
][j
] = clear_val
;
260 case PIPE_FORMAT_U_Z32
:
262 uint clear_val
= (uint
) (tc
->clear_value
[0] * 0xffffffff);
263 for (i
= 0; i
< TILE_SIZE
; i
++) {
264 for (j
= 0; j
< TILE_SIZE
; j
++) {
265 tile
->data
.depth32
[i
][j
] = clear_val
;
270 case PIPE_FORMAT_S8_Z24
:
272 uint clear_val
= (uint
) (tc
->clear_value
[0] * 0xffffff);
273 clear_val
|= ((uint
) tc
->clear_value
[1]) << 24;
274 for (i
= 0; i
< TILE_SIZE
; i
++) {
275 for (j
= 0; j
< TILE_SIZE
; j
++) {
276 tile
->data
.depth32
[i
][j
] = clear_val
;
281 case PIPE_FORMAT_Z24_S8
:
283 uint clear_val
= ((uint
) (tc
->clear_value
[0] * 0xffffff)) << 8;
284 clear_val
|= ((uint
) tc
->clear_value
[1]) & 0xff;
285 for (i
= 0; i
< TILE_SIZE
; i
++) {
286 for (j
= 0; j
< TILE_SIZE
; j
++) {
287 tile
->data
.depth32
[i
][j
] = clear_val
;
292 case PIPE_FORMAT_U_S8
:
294 ubyte clear_val
= (uint
) tc
->clear_value
[0];
295 for (i
= 0; i
< TILE_SIZE
; i
++) {
296 for (j
= 0; j
< TILE_SIZE
; j
++) {
297 tile
->data
.stencil8
[i
][j
] = clear_val
;
304 for (i
= 0; i
< TILE_SIZE
; i
++) {
305 for (j
= 0; j
< TILE_SIZE
; j
++) {
306 tile
->data
.color
[i
][j
][0] = tc
->clear_value
[0];
307 tile
->data
.color
[i
][j
][1] = tc
->clear_value
[1];
308 tile
->data
.color
[i
][j
][2] = tc
->clear_value
[2];
309 tile
->data
.color
[i
][j
][3] = tc
->clear_value
[3];
313 clear_clear_flag(tc
->clear_flags
, x
, y
);
316 /* get new tile from framebuffer */
317 if (is_depth_stencil
) {
318 pipe
->get_tile(pipe
, ps
,
319 tile_x
, tile_y
, TILE_SIZE
, TILE_SIZE
,
320 tile
->data
.depth32
, 0/*STRIDE*/);
323 pipe
->get_tile_rgba(pipe
, ps
,
324 tile_x
, tile_y
, TILE_SIZE
, TILE_SIZE
,
325 (float *) tile
->data
.color
);
338 * Given the texture face, level, zslice, x and y values, compute
339 * the cache entry position/index where we'd hope to find the
340 * cached texture tile.
341 * This is basically a direct-map cache.
342 * XXX There's probably lots of ways in which we can improve this.
345 tex_cache_pos(int x
, int y
, int z
, int face
, int level
)
347 uint entry
= x
+ y
* 5 + z
* 4 + face
+ level
;
348 return entry
% NUM_ENTRIES
;
353 * Similar to sp_get_cached_tile() but for textures.
354 * Tiles are read-only and indexed with more params.
356 const struct softpipe_cached_tile
*
357 sp_get_cached_tile_tex(struct pipe_context
*pipe
,
358 struct softpipe_tile_cache
*tc
, int x
, int y
, int z
,
361 /* tile pos in framebuffer: */
362 const int tile_x
= x
& ~(TILE_SIZE
- 1);
363 const int tile_y
= y
& ~(TILE_SIZE
- 1);
364 /* cache pos/entry: */
365 const uint pos
= tex_cache_pos(x
/ TILE_SIZE
, y
/ TILE_SIZE
, z
,
367 struct softpipe_cached_tile
*tile
= tc
->entries
+ pos
;
369 if (tile_x
!= tile
->x
||
372 face
!= tile
->face
||
373 level
!= tile
->level
) {
374 /* XXX this call is a bit heavier than we'd like: */
375 struct pipe_surface
*ps
376 = pipe
->get_tex_surface(pipe
, tc
->texture
, face
, level
, z
);
378 if (ps
!= tc
->surface
) {
379 if (tc
->surface
&& tc
->surface
->map
)
380 pipe_surface_unmap(tc
->surface
);
382 pipe_surface_reference(&tc
->surface
, ps
);
384 if (!tc
->surface
->map
)
385 pipe_surface_map(tc
->surface
);
388 pipe
->get_tile_rgba(pipe
, ps
,
389 tile_x
, tile_y
, TILE_SIZE
, TILE_SIZE
,
390 (float *) tile
->data
.color
);
392 pipe_surface_reference(&ps
, NULL
);
406 * When a whole surface is being cleared to a value we can avoid
407 * fetching tiles above.
408 * Save the color and set a 'clearflag' for each tile of the screen.
411 sp_tile_cache_clear(struct softpipe_tile_cache
*tc
, const float value
[4])
413 tc
->clear_value
[0] = value
[0];
414 tc
->clear_value
[1] = value
[1];
415 tc
->clear_value
[2] = value
[2];
416 tc
->clear_value
[3] = value
[3];
418 #if CLEAR_OPTIMIZATION
419 memset(tc
->clear_flags
, 255, sizeof(tc
->clear_flags
));
421 memset(tc
->clear_flags
, 0, sizeof(tc
->clear_flags
));