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