gallium: use pipe_texture_reference() in sp_tile_cache_set_texture()
[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(pipe, &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 return;
364
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 #if 0
388 debug_printf("flushed tiles in use: %d\n", inuse);
389 #endif
390 }
391
392
393 /**
394 * Get a tile from the cache.
395 * \param x, y position of tile, in pixels
396 */
397 struct softpipe_cached_tile *
398 sp_get_cached_tile(struct softpipe_context *softpipe,
399 struct softpipe_tile_cache *tc, int x, int y)
400 {
401 struct pipe_context *pipe = &softpipe->pipe;
402 struct pipe_surface *ps = tc->surface;
403
404 /* tile pos in framebuffer: */
405 const int tile_x = x & ~(TILE_SIZE - 1);
406 const int tile_y = y & ~(TILE_SIZE - 1);
407
408 /* cache pos/entry: */
409 const int pos = CACHE_POS(x, y);
410 struct softpipe_cached_tile *tile = tc->entries + pos;
411
412 if (tile_x != tile->x ||
413 tile_y != tile->y) {
414
415 if (tile->x != -1) {
416 /* put dirty tile back in framebuffer */
417 if (tc->depth_stencil) {
418 pipe_put_tile_raw(pipe, ps,
419 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
420 tile->data.depth32, 0/*STRIDE*/);
421 }
422 else {
423 pipe_put_tile_rgba(pipe, ps,
424 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
425 (float *) tile->data.color);
426 }
427 }
428
429 tile->x = tile_x;
430 tile->y = tile_y;
431
432 if (is_clear_flag_set(tc->clear_flags, x, y)) {
433 /* don't get tile from framebuffer, just clear it */
434 if (tc->depth_stencil) {
435 clear_tile(tile, ps->format, tc->clear_val);
436 }
437 else {
438 clear_tile_rgba(tile, ps->format, tc->clear_color);
439 }
440 clear_clear_flag(tc->clear_flags, x, y);
441 }
442 else {
443 /* get new tile data from surface */
444 if (tc->depth_stencil) {
445 pipe_get_tile_raw(pipe, ps,
446 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
447 tile->data.depth32, 0/*STRIDE*/);
448 }
449 else {
450 pipe_get_tile_rgba(pipe, ps,
451 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
452 (float *) tile->data.color);
453 }
454 }
455 }
456
457 return tile;
458 }
459
460
461 /**
462 * Given the texture face, level, zslice, x and y values, compute
463 * the cache entry position/index where we'd hope to find the
464 * cached texture tile.
465 * This is basically a direct-map cache.
466 * XXX There's probably lots of ways in which we can improve this.
467 */
468 static INLINE uint
469 tex_cache_pos(int x, int y, int z, int face, int level)
470 {
471 uint entry = x + y * 5 + z * 4 + face + level;
472 return entry % NUM_ENTRIES;
473 }
474
475
476 /**
477 * Similar to sp_get_cached_tile() but for textures.
478 * Tiles are read-only and indexed with more params.
479 */
480 const struct softpipe_cached_tile *
481 sp_get_cached_tile_tex(struct pipe_context *pipe,
482 struct softpipe_tile_cache *tc, int x, int y, int z,
483 int face, int level)
484 {
485 /* tile pos in framebuffer: */
486 const int tile_x = x & ~(TILE_SIZE - 1);
487 const int tile_y = y & ~(TILE_SIZE - 1);
488 /* cache pos/entry: */
489 const uint pos = tex_cache_pos(x / TILE_SIZE, y / TILE_SIZE, z,
490 face, level);
491 struct softpipe_cached_tile *tile = tc->entries + pos;
492
493 if (tile_x != tile->x ||
494 tile_y != tile->y ||
495 z != tile->z ||
496 face != tile->face ||
497 level != tile->level) {
498 /* cache miss */
499
500 /* check if we need to get a new surface */
501 if (!tc->tex_surf ||
502 tc->tex_face != face ||
503 tc->tex_level != level ||
504 tc->tex_z != z) {
505 /* get new surface (view into texture) */
506
507 if (tc->tex_surf_map)
508 pipe_surface_unmap(tc->tex_surf);
509
510 tc->tex_surf = pipe->get_tex_surface(pipe, tc->texture, face, level, z);
511 tc->tex_surf_map = pipe_surface_map(tc->tex_surf);
512
513 tc->tex_face = face;
514 tc->tex_level = level;
515 tc->tex_z = z;
516 }
517
518 /* get tile from the surface (view into texture) */
519 pipe_get_tile_rgba(pipe, tc->tex_surf,
520 tile_x, tile_y, TILE_SIZE, TILE_SIZE,
521 (float *) tile->data.color);
522 tile->x = tile_x;
523 tile->y = tile_y;
524 tile->z = z;
525 tile->face = face;
526 tile->level = level;
527 }
528
529 return tile;
530 }
531
532
533 /**
534 * When a whole surface is being cleared to a value we can avoid
535 * fetching tiles above.
536 * Save the color and set a 'clearflag' for each tile of the screen.
537 */
538 void
539 sp_tile_cache_clear(struct softpipe_tile_cache *tc, uint clearValue)
540 {
541 uint r, g, b, a;
542 uint pos;
543
544 tc->clear_val = clearValue;
545
546 switch (tc->surface->format) {
547 case PIPE_FORMAT_R8G8B8A8_UNORM:
548 r = (clearValue >> 24) & 0xff;
549 g = (clearValue >> 16) & 0xff;
550 b = (clearValue >> 8) & 0xff;
551 a = (clearValue ) & 0xff;
552 break;
553 case PIPE_FORMAT_A8R8G8B8_UNORM:
554 r = (clearValue >> 16) & 0xff;
555 g = (clearValue >> 8) & 0xff;
556 b = (clearValue ) & 0xff;
557 a = (clearValue >> 24) & 0xff;
558 break;
559 case PIPE_FORMAT_B8G8R8A8_UNORM:
560 r = (clearValue >> 8) & 0xff;
561 g = (clearValue >> 16) & 0xff;
562 b = (clearValue >> 24) & 0xff;
563 a = (clearValue ) & 0xff;
564 break;
565 default:
566 r = g = b = a = 0;
567 }
568
569 tc->clear_color[0] = r / 255.0f;
570 tc->clear_color[1] = g / 255.0f;
571 tc->clear_color[2] = b / 255.0f;
572 tc->clear_color[3] = a / 255.0f;
573
574 #if TILE_CLEAR_OPTIMIZATION
575 /* set flags to indicate all the tiles are cleared */
576 memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
577 #else
578 /* disable the optimization */
579 memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
580 #endif
581
582 for (pos = 0; pos < NUM_ENTRIES; pos++) {
583 struct softpipe_cached_tile *tile = tc->entries + pos;
584 tile->x = tile->y = -1;
585 }
586 }