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