79b1e036be8764685fb32f505ecca63cfbbce62a
[mesa.git] / src / gallium / drivers / 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 * Texture tile caching.
30 *
31 * Author:
32 * Brian Paul
33 */
34
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"
42
43 #define NUM_ENTRIES 50
44
45
46 /** XXX move these */
47 #define MAX_WIDTH 2048
48 #define MAX_HEIGHT 2048
49
50
51 struct softpipe_tile_cache
52 {
53 struct pipe_screen *screen;
54 struct pipe_surface *surface; /**< the surface we're caching */
55 struct pipe_transfer *transfer;
56 void *transfer_map;
57
58 struct pipe_texture *texture; /**< if caching a texture */
59 unsigned timestamp;
60
61 struct softpipe_cached_tile entries[NUM_ENTRIES];
62 uint clear_flags[(MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32];
63 float clear_color[4]; /**< for color bufs */
64 uint clear_val; /**< for z+stencil, or packed color clear value */
65 boolean depth_stencil; /**< Is the surface a depth/stencil format? */
66
67 struct pipe_transfer *tex_trans;
68 void *tex_trans_map;
69 int tex_face, tex_level, tex_z;
70
71 struct softpipe_cached_tile tile; /**< scratch tile for clears */
72 };
73
74
75 /**
76 * Return the position in the cache for the tile that contains win pos (x,y).
77 * We currently use a direct mapped cache so this is like a hack key.
78 * At some point we should investige something more sophisticated, like
79 * a LRU replacement policy.
80 */
81 #define CACHE_POS(x, y) \
82 (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
83
84
85
86 /**
87 * Is the tile at (x,y) in cleared state?
88 */
89 static INLINE uint
90 is_clear_flag_set(const uint *bitvec, int x, int y)
91 {
92 int pos, bit;
93 x /= TILE_SIZE;
94 y /= TILE_SIZE;
95 pos = y * (MAX_WIDTH / TILE_SIZE) + x;
96 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
97 bit = bitvec[pos / 32] & (1 << (pos & 31));
98 return bit;
99 }
100
101
102 /**
103 * Mark the tile at (x,y) as not cleared.
104 */
105 static INLINE void
106 clear_clear_flag(uint *bitvec, int x, int y)
107 {
108 int pos;
109 x /= TILE_SIZE;
110 y /= TILE_SIZE;
111 pos = y * (MAX_WIDTH / TILE_SIZE) + x;
112 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
113 bitvec[pos / 32] &= ~(1 << (pos & 31));
114 }
115
116
117 struct softpipe_tile_cache *
118 sp_create_tile_cache( struct pipe_screen *screen )
119 {
120 struct softpipe_tile_cache *tc;
121 uint pos;
122
123 tc = CALLOC_STRUCT( softpipe_tile_cache );
124 if (tc) {
125 tc->screen = screen;
126 for (pos = 0; pos < NUM_ENTRIES; pos++) {
127 tc->entries[pos].x =
128 tc->entries[pos].y = -1;
129 }
130 }
131 return tc;
132 }
133
134
135 void
136 sp_destroy_tile_cache(struct softpipe_tile_cache *tc)
137 {
138 struct pipe_screen *screen;
139 uint pos;
140
141 for (pos = 0; pos < NUM_ENTRIES; pos++) {
142 /*assert(tc->entries[pos].x < 0);*/
143 }
144 if (tc->transfer) {
145 screen = tc->transfer->texture->screen;
146 screen->tex_transfer_destroy(tc->transfer);
147 }
148 if (tc->tex_trans) {
149 screen = tc->tex_trans->texture->screen;
150 screen->tex_transfer_destroy(tc->tex_trans);
151 }
152
153 FREE( tc );
154 }
155
156
157 /**
158 * Specify the surface to cache.
159 */
160 void
161 sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
162 struct pipe_surface *ps)
163 {
164 assert(!tc->texture);
165
166 if (tc->transfer) {
167 struct pipe_screen *screen = tc->transfer->texture->screen;
168
169 if (ps == tc->surface)
170 return;
171
172 if (tc->transfer_map) {
173 screen->transfer_unmap(screen, tc->transfer);
174 tc->transfer_map = NULL;
175 }
176
177 screen->tex_transfer_destroy(tc->transfer);
178 tc->transfer = NULL;
179 }
180
181 tc->surface = ps;
182
183 if (ps) {
184 struct pipe_screen *screen = ps->texture->screen;
185
186 tc->transfer = screen->get_tex_transfer(screen, ps->texture, ps->face,
187 ps->level, ps->zslice,
188 PIPE_TRANSFER_READ_WRITE,
189 0, 0, ps->width, ps->height);
190
191 tc->depth_stencil = (ps->format == PIPE_FORMAT_S8Z24_UNORM ||
192 ps->format == PIPE_FORMAT_X8Z24_UNORM ||
193 ps->format == PIPE_FORMAT_Z24S8_UNORM ||
194 ps->format == PIPE_FORMAT_Z24X8_UNORM ||
195 ps->format == PIPE_FORMAT_Z16_UNORM ||
196 ps->format == PIPE_FORMAT_Z32_UNORM ||
197 ps->format == PIPE_FORMAT_S8_UNORM);
198 }
199 }
200
201
202 /**
203 * Return the transfer being cached.
204 */
205 struct pipe_surface *
206 sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
207 {
208 return tc->surface;
209 }
210
211
212 void
213 sp_tile_cache_map_transfers(struct softpipe_tile_cache *tc)
214 {
215 if (tc->transfer && !tc->transfer_map)
216 tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
217
218 if (tc->tex_trans && !tc->tex_trans_map)
219 tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
220 }
221
222
223 void
224 sp_tile_cache_unmap_transfers(struct softpipe_tile_cache *tc)
225 {
226 if (tc->transfer_map) {
227 tc->screen->transfer_unmap(tc->screen, tc->transfer);
228 tc->transfer_map = NULL;
229 }
230
231 if (tc->tex_trans_map) {
232 tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
233 tc->tex_trans_map = NULL;
234 }
235 }
236
237 void
238 sp_tile_cache_validate_texture(struct softpipe_tile_cache *tc)
239 {
240 if (tc->texture) {
241 struct softpipe_texture *spt = softpipe_texture(tc->texture);
242 if (spt->timestamp != tc->timestamp) {
243 /* texture was modified, invalidate all cached tiles */
244 uint i;
245 _debug_printf("INV %d %d\n", tc->timestamp, spt->timestamp);
246 for (i = 0; i < NUM_ENTRIES; i++) {
247 tc->entries[i].x = -3;
248 }
249
250 tc->timestamp = spt->timestamp;
251 }
252 }
253 }
254
255 /**
256 * Specify the texture to cache.
257 */
258 void
259 sp_tile_cache_set_texture(struct softpipe_tile_cache *tc,
260 struct pipe_texture *texture)
261 {
262 uint i;
263
264 assert(!tc->transfer);
265
266 if (tc->texture != texture) {
267 pipe_texture_reference(&tc->texture, texture);
268
269 if (tc->tex_trans) {
270 struct pipe_screen *screen = tc->tex_trans->texture->screen;
271
272 if (tc->tex_trans_map) {
273 screen->transfer_unmap(screen, tc->tex_trans);
274 tc->tex_trans_map = NULL;
275 }
276
277 screen->tex_transfer_destroy(tc->tex_trans);
278 tc->tex_trans = NULL;
279 }
280
281 /* mark as entries as invalid/empty */
282 /* XXX we should try to avoid this when the teximage hasn't changed */
283 for (i = 0; i < NUM_ENTRIES; i++) {
284 tc->entries[i].x = -1;
285 }
286
287 tc->tex_face = -1; /* any invalid value here */
288 }
289 }
290
291
292 /**
293 * Set pixels in a tile to the given clear color/value, float.
294 */
295 static void
296 clear_tile_rgba(struct softpipe_cached_tile *tile,
297 enum pipe_format format,
298 const float clear_value[4])
299 {
300 if (clear_value[0] == 0.0 &&
301 clear_value[1] == 0.0 &&
302 clear_value[2] == 0.0 &&
303 clear_value[3] == 0.0) {
304 memset(tile->data.color, 0, sizeof(tile->data.color));
305 }
306 else {
307 uint i, j;
308 for (i = 0; i < TILE_SIZE; i++) {
309 for (j = 0; j < TILE_SIZE; j++) {
310 tile->data.color[i][j][0] = clear_value[0];
311 tile->data.color[i][j][1] = clear_value[1];
312 tile->data.color[i][j][2] = clear_value[2];
313 tile->data.color[i][j][3] = clear_value[3];
314 }
315 }
316 }
317 }
318
319
320 /**
321 * Set a tile to a solid value/color.
322 */
323 static void
324 clear_tile(struct softpipe_cached_tile *tile,
325 enum pipe_format format,
326 uint clear_value)
327 {
328 uint i, j;
329
330 switch (pf_get_size(format)) {
331 case 1:
332 memset(tile->data.any, 0, TILE_SIZE * TILE_SIZE);
333 break;
334 case 2:
335 if (clear_value == 0) {
336 memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE);
337 }
338 else {
339 for (i = 0; i < TILE_SIZE; i++) {
340 for (j = 0; j < TILE_SIZE; j++) {
341 tile->data.depth16[i][j] = (ushort) clear_value;
342 }
343 }
344 }
345 break;
346 case 4:
347 if (clear_value == 0) {
348 memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE);
349 }
350 else {
351 for (i = 0; i < TILE_SIZE; i++) {
352 for (j = 0; j < TILE_SIZE; j++) {
353 tile->data.color32[i][j] = clear_value;
354 }
355 }
356 }
357 break;
358 default:
359 assert(0);
360 }
361 }
362
363
364 /**
365 * Actually clear the tiles which were flagged as being in a clear state.
366 */
367 static void
368 sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc)
369 {
370 struct pipe_transfer *pt = tc->transfer;
371 const uint w = tc->transfer->width;
372 const uint h = tc->transfer->height;
373 uint x, y;
374 uint numCleared = 0;
375
376 /* clear the scratch tile to the clear value */
377 clear_tile(&tc->tile, pt->format, tc->clear_val);
378
379 /* push the tile to all positions marked as clear */
380 for (y = 0; y < h; y += TILE_SIZE) {
381 for (x = 0; x < w; x += TILE_SIZE) {
382 if (is_clear_flag_set(tc->clear_flags, x, y)) {
383 pipe_put_tile_raw(pt,
384 x, y, TILE_SIZE, TILE_SIZE,
385 tc->tile.data.color32, 0/*STRIDE*/);
386
387 /* do this? */
388 clear_clear_flag(tc->clear_flags, x, y);
389
390 numCleared++;
391 }
392 }
393 }
394 #if 0
395 debug_printf("num cleared: %u\n", numCleared);
396 #endif
397 }
398
399
400 /**
401 * Flush the tile cache: write all dirty tiles back to the transfer.
402 * any tiles "flagged" as cleared will be "really" cleared.
403 */
404 void
405 sp_flush_tile_cache(struct softpipe_tile_cache *tc)
406 {
407 struct pipe_transfer *pt = tc->transfer;
408 int inuse = 0, pos;
409
410 if (pt) {
411 /* caching a drawing transfer */
412 for (pos = 0; pos < NUM_ENTRIES; pos++) {
413 struct softpipe_cached_tile *tile = tc->entries + pos;
414 if (tile->x >= 0) {
415 if (tc->depth_stencil) {
416 pipe_put_tile_raw(pt,
417 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
418 tile->data.depth32, 0/*STRIDE*/);
419 }
420 else {
421 pipe_put_tile_rgba(pt,
422 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
423 (float *) tile->data.color);
424 }
425 tile->x = tile->y = -1; /* mark as empty */
426 inuse++;
427 }
428 }
429
430 #if TILE_CLEAR_OPTIMIZATION
431 sp_tile_cache_flush_clear(tc);
432 #endif
433 }
434 else if (tc->texture) {
435 /* caching a texture, mark all entries as empty */
436 for (pos = 0; pos < NUM_ENTRIES; pos++) {
437 tc->entries[pos].x = -1;
438 }
439 tc->tex_face = -1;
440 }
441
442 #if 0
443 debug_printf("flushed tiles in use: %d\n", inuse);
444 #endif
445 }
446
447
448 /**
449 * Get a tile from the cache.
450 * \param x, y position of tile, in pixels
451 */
452 struct softpipe_cached_tile *
453 sp_get_cached_tile(struct softpipe_tile_cache *tc, int x, int y)
454 {
455 struct pipe_transfer *pt = tc->transfer;
456
457 /* tile pos in framebuffer: */
458 const int tile_x = x & ~(TILE_SIZE - 1);
459 const int tile_y = y & ~(TILE_SIZE - 1);
460
461 /* cache pos/entry: */
462 const int pos = CACHE_POS(x, y);
463 struct softpipe_cached_tile *tile = tc->entries + pos;
464
465 if (tile_x != tile->x ||
466 tile_y != tile->y) {
467
468 if (tile->x >= 0) {
469 /* put dirty tile back in framebuffer */
470 if (tc->depth_stencil) {
471 pipe_put_tile_raw(pt,
472 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
473 tile->data.depth32, 0/*STRIDE*/);
474 }
475 else {
476 pipe_put_tile_rgba(pt,
477 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
478 (float *) tile->data.color);
479 }
480 }
481
482 tile->x = tile_x;
483 tile->y = tile_y;
484
485 if (is_clear_flag_set(tc->clear_flags, x, y)) {
486 /* don't get tile from framebuffer, just clear it */
487 if (tc->depth_stencil) {
488 clear_tile(tile, pt->format, tc->clear_val);
489 }
490 else {
491 clear_tile_rgba(tile, pt->format, tc->clear_color);
492 }
493 clear_clear_flag(tc->clear_flags, x, y);
494 }
495 else {
496 /* get new tile data from transfer */
497 if (tc->depth_stencil) {
498 pipe_get_tile_raw(pt,
499 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
500 tile->data.depth32, 0/*STRIDE*/);
501 }
502 else {
503 pipe_get_tile_rgba(pt,
504 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
505 (float *) tile->data.color);
506 }
507 }
508 }
509
510 return tile;
511 }
512
513
514 /**
515 * Given the texture face, level, zslice, x and y values, compute
516 * the cache entry position/index where we'd hope to find the
517 * cached texture tile.
518 * This is basically a direct-map cache.
519 * XXX There's probably lots of ways in which we can improve this.
520 */
521 static INLINE uint
522 tex_cache_pos(int x, int y, int z, int face, int level)
523 {
524 uint entry = x + y * 9 + z * 3 + face + level * 7;
525 return entry % NUM_ENTRIES;
526 }
527
528
529 /**
530 * Similar to sp_get_cached_tile() but for textures.
531 * Tiles are read-only and indexed with more params.
532 */
533 const struct softpipe_cached_tile *
534 sp_get_cached_tile_tex(struct softpipe_tile_cache *tc,
535 int x, int y, int z,
536 int face, int level)
537 {
538 struct pipe_screen *screen = tc->screen;
539 /* tile pos in framebuffer: */
540 const int tile_x = x & ~(TILE_SIZE - 1);
541 const int tile_y = y & ~(TILE_SIZE - 1);
542 /* cache pos/entry: */
543 const uint pos = tex_cache_pos(x / TILE_SIZE, y / TILE_SIZE, z,
544 face, level);
545 struct softpipe_cached_tile *tile = tc->entries + pos;
546
547 if (tile_x != tile->x ||
548 tile_y != tile->y ||
549 z != tile->z ||
550 face != tile->face ||
551 level != tile->level) {
552
553 /* cache miss. Most misses are because we've invaldiated the
554 * texture cache previously -- most commonly on binding a new
555 * texture. Currently we effectively flush the cache on texture
556 * bind.
557 */
558 #if 0
559 _debug_printf("miss at %u: x=%d y=%d z=%d face=%d level=%d\n"
560 " tile %u: x=%d y=%d z=%d face=%d level=%d\n",
561 pos, x/TILE_SIZE, y/TILE_SIZE, z, face, level,
562 pos, tile->x, tile->y, tile->z, tile->face, tile->level);
563 #endif
564
565 /* check if we need to get a new transfer */
566 if (!tc->tex_trans ||
567 tc->tex_face != face ||
568 tc->tex_level != level ||
569 tc->tex_z != z) {
570 /* get new transfer (view into texture) */
571
572 if (tc->tex_trans) {
573 if (tc->tex_trans_map) {
574 tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
575 tc->tex_trans_map = NULL;
576 }
577
578 screen->tex_transfer_destroy(tc->tex_trans);
579 tc->tex_trans = NULL;
580 }
581
582 tc->tex_trans = screen->get_tex_transfer(screen, tc->texture, face, level, z,
583 PIPE_TRANSFER_READ, 0, 0,
584 tc->texture->width[level],
585 tc->texture->height[level]);
586 tc->tex_trans_map = screen->transfer_map(screen, tc->tex_trans);
587
588 tc->tex_face = face;
589 tc->tex_level = level;
590 tc->tex_z = z;
591 }
592
593 /* get tile from the transfer (view into texture) */
594 pipe_get_tile_rgba(tc->tex_trans,
595 tile_x, tile_y, TILE_SIZE, TILE_SIZE,
596 (float *) tile->data.color);
597 tile->x = tile_x;
598 tile->y = tile_y;
599 tile->z = z;
600 tile->face = face;
601 tile->level = level;
602 }
603
604 return tile;
605 }
606
607
608 /**
609 * When a whole surface is being cleared to a value we can avoid
610 * fetching tiles above.
611 * Save the color and set a 'clearflag' for each tile of the screen.
612 */
613 void
614 sp_tile_cache_clear(struct softpipe_tile_cache *tc, const float *rgba,
615 uint clearValue)
616 {
617 uint pos;
618
619 tc->clear_color[0] = rgba[0];
620 tc->clear_color[1] = rgba[1];
621 tc->clear_color[2] = rgba[2];
622 tc->clear_color[3] = rgba[3];
623
624 tc->clear_val = clearValue;
625
626 #if TILE_CLEAR_OPTIMIZATION
627 /* set flags to indicate all the tiles are cleared */
628 memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
629 #else
630 /* disable the optimization */
631 memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
632 #endif
633
634 for (pos = 0; pos < NUM_ENTRIES; pos++) {
635 struct softpipe_cached_tile *tile = tc->entries + pos;
636 tile->x = tile->y = -1;
637 }
638 }