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