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