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