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