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