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