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