1dbcc5aadd0b58393d996353df7c1580d9abae03
[mesa.git] / src / mesa / pipe / softpipe / sp_tile_cache.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
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:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
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.
25 *
26 **************************************************************************/
27
28 /**
29 * Framebuffer/surface tile caching.
30 *
31 * Author:
32 * Brian Paul
33 */
34
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"
40
41 #define NUM_ENTRIES 30
42
43
44 /** XXX move these */
45 #define MAX_WIDTH 2048
46 #define MAX_HEIGHT 2048
47
48
49 struct softpipe_tile_cache
50 {
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];
55 float clear_color[4];
56 uint clear_val;
57 boolean depth_stencil; /** Is the surface a depth/stencil format? */
58
59 struct pipe_surface *tex_surf;
60 int tex_face, tex_level, tex_z;
61
62 struct softpipe_cached_tile tile; /**< scratch tile for clears */
63 };
64
65
66 /**
67 * Return the position in the cache for the tile that contains win pos (x,y).
68 * We currently use a direct mapped cache so this is like a hack key.
69 * At some point we should investige something more sophisticated, like
70 * a LRU replacement policy.
71 */
72 #define CACHE_POS(x, y) \
73 (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
74
75
76
77 /**
78 * Is the tile at (x,y) in cleared state?
79 */
80 static INLINE uint
81 is_clear_flag_set(const uint *bitvec, int x, int y)
82 {
83 int pos, bit;
84 x /= TILE_SIZE;
85 y /= TILE_SIZE;
86 pos = y * (MAX_WIDTH / TILE_SIZE) + x;
87 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
88 bit = bitvec[pos / 32] & (1 << (pos & 31));
89 return bit;
90 }
91
92
93 /**
94 * Mark the tile at (x,y) as not cleared.
95 */
96 static INLINE void
97 clear_clear_flag(uint *bitvec, int x, int y)
98 {
99 int pos;
100 x /= TILE_SIZE;
101 y /= TILE_SIZE;
102 pos = y * (MAX_WIDTH / TILE_SIZE) + x;
103 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
104 bitvec[pos / 32] &= ~(1 << (pos & 31));
105 }
106
107
108 struct softpipe_tile_cache *
109 sp_create_tile_cache(void)
110 {
111 struct softpipe_tile_cache *tc;
112 uint pos;
113
114 tc = CALLOC_STRUCT( softpipe_tile_cache );
115 if (tc) {
116 for (pos = 0; pos < NUM_ENTRIES; pos++) {
117 tc->entries[pos].x =
118 tc->entries[pos].y = -1;
119 }
120 }
121 return tc;
122 }
123
124
125 void
126 sp_destroy_tile_cache(struct softpipe_tile_cache *tc)
127 {
128 uint pos;
129
130 for (pos = 0; pos < NUM_ENTRIES; pos++) {
131 //assert(tc->entries[pos].x < 0);
132 }
133 if (tc->surface) {
134 pipe_surface_reference(&tc->surface, NULL);
135 }
136 if (tc->tex_surf) {
137 pipe_surface_reference(&tc->tex_surf, NULL);
138 }
139
140 FREE( tc );
141 }
142
143
144 /**
145 * Specify the surface to cache.
146 */
147 void
148 sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
149 struct pipe_surface *ps)
150 {
151 assert(!tc->texture);
152
153 if (tc->surface && tc->surface->map) {
154 /*assert(tc->surface != ps);*/
155 pipe_surface_unmap(tc->surface);
156 }
157
158 pipe_surface_reference(&tc->surface, ps);
159
160 if (ps) {
161 if (!ps->map)
162 pipe_surface_map(ps);
163
164 tc->depth_stencil = (ps->format == PIPE_FORMAT_S8Z24_UNORM ||
165 ps->format == PIPE_FORMAT_Z16_UNORM ||
166 ps->format == PIPE_FORMAT_Z32_UNORM ||
167 ps->format == PIPE_FORMAT_U_S8);
168 }
169 }
170
171
172 /**
173 * Return the surface being cached.
174 */
175 struct pipe_surface *
176 sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
177 {
178 return tc->surface;
179 }
180
181
182 /**
183 * Specify the texture to cache.
184 */
185 void
186 sp_tile_cache_set_texture(struct softpipe_tile_cache *tc,
187 struct pipe_texture *texture)
188 {
189 uint i;
190
191 assert(!tc->surface);
192
193 tc->texture = texture;
194
195 if (tc->tex_surf && tc->tex_surf->map)
196 pipe_surface_unmap(tc->tex_surf);
197 pipe_surface_reference(&tc->tex_surf, NULL);
198
199 /* mark as entries as invalid/empty */
200 /* XXX we should try to avoid this when the teximage hasn't changed */
201 for (i = 0; i < NUM_ENTRIES; i++) {
202 tc->entries[i].x = -1;
203 }
204
205 tc->tex_face = -1; /* any invalid value here */
206 }
207
208
209 /**
210 * Set pixels in a tile to the given clear color/value, float.
211 */
212 static void
213 clear_tile_rgba(struct softpipe_cached_tile *tile,
214 enum pipe_format format,
215 const float clear_value[4])
216 {
217 if (clear_value[0] == 0.0 &&
218 clear_value[1] == 0.0 &&
219 clear_value[2] == 0.0 &&
220 clear_value[3] == 0.0) {
221 memset(tile->data.color, 0, sizeof(tile->data.color));
222 }
223 else {
224 uint i, j;
225 for (i = 0; i < TILE_SIZE; i++) {
226 for (j = 0; j < TILE_SIZE; j++) {
227 tile->data.color[i][j][0] = clear_value[0];
228 tile->data.color[i][j][1] = clear_value[1];
229 tile->data.color[i][j][2] = clear_value[2];
230 tile->data.color[i][j][3] = clear_value[3];
231 }
232 }
233 }
234 }
235
236
237 /**
238 * Set a tile to a solid value/color.
239 */
240 static void
241 clear_tile(struct softpipe_cached_tile *tile,
242 enum pipe_format format,
243 uint clear_value)
244 {
245 uint i, j;
246
247 switch (pf_get_size(format)) {
248 case 1:
249 memset(tile->data.any, 0, TILE_SIZE * TILE_SIZE);
250 break;
251 case 2:
252 if (clear_value == 0) {
253 memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE);
254 }
255 else {
256 for (i = 0; i < TILE_SIZE; i++) {
257 for (j = 0; j < TILE_SIZE; j++) {
258 tile->data.depth16[i][j] = clear_value;
259 }
260 }
261 }
262 break;
263 case 4:
264 if (clear_value == 0) {
265 memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE);
266 }
267 else {
268 for (i = 0; i < TILE_SIZE; i++) {
269 for (j = 0; j < TILE_SIZE; j++) {
270 tile->data.color32[i][j] = clear_value;
271 }
272 }
273 }
274 break;
275 default:
276 assert(0);
277 }
278 }
279
280
281 /**
282 * Actually clear the tiles which were flagged as being in a clear state.
283 */
284 static void
285 sp_tile_cache_flush_clear(struct pipe_context *pipe,
286 struct softpipe_tile_cache *tc)
287 {
288 struct pipe_surface *ps = tc->surface;
289 const uint w = tc->surface->width;
290 const uint h = tc->surface->height;
291 uint x, y;
292 uint numCleared = 0;
293
294 /* clear the scratch tile to the clear value */
295 clear_tile(&tc->tile, ps->format, tc->clear_val);
296
297 /* push the tile to all positions marked as clear */
298 for (y = 0; y < h; y += TILE_SIZE) {
299 for (x = 0; x < w; x += TILE_SIZE) {
300 if (is_clear_flag_set(tc->clear_flags, x, y)) {
301 pipe->put_tile(pipe, ps,
302 x, y, TILE_SIZE, TILE_SIZE,
303 tc->tile.data.color32, 0/*STRIDE*/);
304
305 /* do this? */
306 clear_clear_flag(tc->clear_flags, x, y);
307
308 numCleared++;
309 }
310 }
311 }
312 #if 0
313 printf("num cleared: %u\n", numCleared);
314 #endif
315 }
316
317
318 /**
319 * Flush the tile cache: write all dirty tiles back to the surface.
320 * any tiles "flagged" as cleared will be "really" cleared.
321 */
322 void
323 sp_flush_tile_cache(struct softpipe_context *softpipe,
324 struct softpipe_tile_cache *tc)
325 {
326 struct pipe_context *pipe = &softpipe->pipe;
327 struct pipe_surface *ps = tc->surface;
328 int inuse = 0, pos;
329
330 if (!ps || !ps->buffer)
331 return;
332
333 if (!ps->map)
334 pipe_surface_map(ps);
335
336 for (pos = 0; pos < NUM_ENTRIES; pos++) {
337 struct softpipe_cached_tile *tile = tc->entries + pos;
338 if (tile->x >= 0) {
339 if (tc->depth_stencil) {
340 pipe->put_tile(pipe, ps,
341 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
342 tile->data.depth32, 0/*STRIDE*/);
343 }
344 else {
345 pipe->put_tile_rgba(pipe, ps,
346 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
347 (float *) tile->data.color);
348 }
349 tile->x = tile->y = -1; /* mark as empty */
350 inuse++;
351 }
352 }
353
354 #if TILE_CLEAR_OPTIMIZATION
355 sp_tile_cache_flush_clear(&softpipe->pipe, tc);
356 #endif
357
358 #if 0
359 printf("flushed tiles in use: %d\n", inuse);
360 #endif
361 }
362
363
364 /**
365 * Get a tile from the cache.
366 * \param x, y position of tile, in pixels
367 */
368 struct softpipe_cached_tile *
369 sp_get_cached_tile(struct softpipe_context *softpipe,
370 struct softpipe_tile_cache *tc, int x, int y)
371 {
372 struct pipe_context *pipe = &softpipe->pipe;
373 struct pipe_surface *ps = tc->surface;
374
375 /* tile pos in framebuffer: */
376 const int tile_x = x & ~(TILE_SIZE - 1);
377 const int tile_y = y & ~(TILE_SIZE - 1);
378
379 /* cache pos/entry: */
380 const int pos = CACHE_POS(x, y);
381 struct softpipe_cached_tile *tile = tc->entries + pos;
382
383 if (tile_x != tile->x ||
384 tile_y != tile->y) {
385
386 if (tile->x != -1) {
387 /* put dirty tile back in framebuffer */
388 if (tc->depth_stencil) {
389 pipe->put_tile(pipe, ps,
390 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
391 tile->data.depth32, 0/*STRIDE*/);
392 }
393 else {
394 pipe->put_tile_rgba(pipe, ps,
395 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
396 (float *) tile->data.color);
397 }
398 }
399
400 tile->x = tile_x;
401 tile->y = tile_y;
402
403 if (is_clear_flag_set(tc->clear_flags, x, y)) {
404 /* don't get tile from framebuffer, just clear it */
405 if (tc->depth_stencil) {
406 clear_tile(tile, ps->format, tc->clear_val);
407 }
408 else {
409 clear_tile_rgba(tile, ps->format, tc->clear_color);
410 }
411 clear_clear_flag(tc->clear_flags, x, y);
412 }
413 else {
414 /* get new tile data from surface */
415 if (tc->depth_stencil) {
416 pipe->get_tile(pipe, ps,
417 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
418 tile->data.depth32, 0/*STRIDE*/);
419 }
420 else {
421 pipe->get_tile_rgba(pipe, ps,
422 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
423 (float *) tile->data.color);
424 }
425 }
426 }
427
428 return tile;
429 }
430
431
432 /**
433 * Given the texture face, level, zslice, x and y values, compute
434 * the cache entry position/index where we'd hope to find the
435 * cached texture tile.
436 * This is basically a direct-map cache.
437 * XXX There's probably lots of ways in which we can improve this.
438 */
439 static INLINE uint
440 tex_cache_pos(int x, int y, int z, int face, int level)
441 {
442 uint entry = x + y * 5 + z * 4 + face + level;
443 return entry % NUM_ENTRIES;
444 }
445
446
447 /**
448 * Similar to sp_get_cached_tile() but for textures.
449 * Tiles are read-only and indexed with more params.
450 */
451 const struct softpipe_cached_tile *
452 sp_get_cached_tile_tex(struct pipe_context *pipe,
453 struct softpipe_tile_cache *tc, int x, int y, int z,
454 int face, int level)
455 {
456 /* tile pos in framebuffer: */
457 const int tile_x = x & ~(TILE_SIZE - 1);
458 const int tile_y = y & ~(TILE_SIZE - 1);
459 /* cache pos/entry: */
460 const uint pos = tex_cache_pos(x / TILE_SIZE, y / TILE_SIZE, z,
461 face, level);
462 struct softpipe_cached_tile *tile = tc->entries + pos;
463
464 if (tile_x != tile->x ||
465 tile_y != tile->y ||
466 z != tile->z ||
467 face != tile->face ||
468 level != tile->level) {
469 /* cache miss */
470
471 /* check if we need to get a new surface */
472 if (!tc->tex_surf ||
473 tc->tex_face != face ||
474 tc->tex_level != level ||
475 tc->tex_z != z) {
476 /* get new surface (view into texture) */
477
478 if (tc->tex_surf && tc->tex_surf->map)
479 pipe_surface_unmap(tc->tex_surf);
480
481 tc->tex_surf = pipe->get_tex_surface(pipe, tc->texture, face, level, z);
482 pipe_surface_map(tc->tex_surf);
483
484 tc->tex_face = face;
485 tc->tex_level = level;
486 tc->tex_z = z;
487 }
488
489 /* get tile from the surface (view into texture) */
490 pipe->get_tile_rgba(pipe, tc->tex_surf,
491 tile_x, tile_y, TILE_SIZE, TILE_SIZE,
492 (float *) tile->data.color);
493 tile->x = tile_x;
494 tile->y = tile_y;
495 tile->z = z;
496 tile->face = face;
497 tile->level = level;
498 }
499
500 return tile;
501 }
502
503
504 /**
505 * When a whole surface is being cleared to a value we can avoid
506 * fetching tiles above.
507 * Save the color and set a 'clearflag' for each tile of the screen.
508 */
509 void
510 sp_tile_cache_clear(struct softpipe_tile_cache *tc, uint clearValue)
511 {
512 uint r, g, b, a;
513
514 tc->clear_val = clearValue;
515
516 switch (tc->surface->format) {
517 case PIPE_FORMAT_R8G8B8A8_UNORM:
518 r = (clearValue >> 24) & 0xff;
519 g = (clearValue >> 16) & 0xff;
520 b = (clearValue >> 8) & 0xff;
521 a = (clearValue ) & 0xff;
522 break;
523 case PIPE_FORMAT_A8R8G8B8_UNORM:
524 r = (clearValue >> 16) & 0xff;
525 g = (clearValue >> 8) & 0xff;
526 b = (clearValue ) & 0xff;
527 a = (clearValue >> 24) & 0xff;
528 break;
529 case PIPE_FORMAT_B8G8R8A8_UNORM:
530 r = (clearValue >> 8) & 0xff;
531 g = (clearValue >> 16) & 0xff;
532 b = (clearValue >> 24) & 0xff;
533 a = (clearValue ) & 0xff;
534 break;
535 default:
536 r = g = b = a = 0;
537 }
538
539 tc->clear_color[0] = r / 255.0;
540 tc->clear_color[1] = g / 255.0;
541 tc->clear_color[2] = b / 255.0;
542 tc->clear_color[3] = a / 255.0;
543
544 #if TILE_CLEAR_OPTIMIZATION
545 /* set flags to indicate all the tiles are cleared */
546 memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
547 #else
548 /* disable the optimization */
549 memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
550 #endif
551 }