Squashed commit of the following:
[profile/ivi/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  * Render target tile caching.
30  *
31  * Author:
32  *    Brian Paul
33  */
34
35 #include "util/u_inlines.h"
36 #include "util/u_format.h"
37 #include "util/u_memory.h"
38 #include "util/u_tile.h"
39 #include "sp_tile_cache.h"
40
41
42
43 /**
44  * Return the position in the cache for the tile that contains win pos (x,y).
45  * We currently use a direct mapped cache so this is like a hack key.
46  * At some point we should investige something more sophisticated, like
47  * a LRU replacement policy.
48  */
49 #define CACHE_POS(x, y) \
50    (((x) + (y) * 5) % NUM_ENTRIES)
51
52
53
54 /**
55  * Is the tile at (x,y) in cleared state?
56  */
57 static INLINE uint
58 is_clear_flag_set(const uint *bitvec, union tile_address addr)
59 {
60    int pos, bit;
61    pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x;
62    assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
63    bit = bitvec[pos / 32] & (1 << (pos & 31));
64    return bit;
65 }
66    
67
68 /**
69  * Mark the tile at (x,y) as not cleared.
70  */
71 static INLINE void
72 clear_clear_flag(uint *bitvec, union tile_address addr)
73 {
74    int pos;
75    pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x;
76    assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
77    bitvec[pos / 32] &= ~(1 << (pos & 31));
78 }
79    
80
81 struct softpipe_tile_cache *
82 sp_create_tile_cache( struct pipe_context *pipe )
83 {
84    struct softpipe_tile_cache *tc;
85    uint pos;
86    int maxLevels, maxTexSize;
87
88    /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
89    maxLevels = pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
90    maxTexSize = 1 << (maxLevels - 1);
91    assert(MAX_WIDTH >= maxTexSize);
92
93    tc = CALLOC_STRUCT( softpipe_tile_cache );
94    if (tc) {
95       tc->pipe = pipe;
96       for (pos = 0; pos < NUM_ENTRIES; pos++) {
97          tc->entries[pos].addr.bits.invalid = 1;
98       }
99       tc->last_tile = &tc->entries[0]; /* any tile */
100
101       /* XXX this code prevents valgrind warnings about use of uninitialized
102        * memory in programs that don't clear the surface before rendering.
103        * However, it breaks clearing in other situations (such as in
104        * progs/tests/drawbuffers, see bug 24402).
105        */
106 #if 0 && TILE_CLEAR_OPTIMIZATION
107       /* set flags to indicate all the tiles are cleared */
108       memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
109 #endif
110    }
111    return tc;
112 }
113
114
115 void
116 sp_destroy_tile_cache(struct softpipe_tile_cache *tc)
117 {
118    uint pos;
119
120    for (pos = 0; pos < NUM_ENTRIES; pos++) {
121       /*assert(tc->entries[pos].x < 0);*/
122    }
123    if (tc->transfer) {
124       tc->pipe->transfer_destroy(tc->pipe, tc->transfer);
125    }
126
127    FREE( tc );
128 }
129
130
131 /**
132  * Specify the surface to cache.
133  */
134 void
135 sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
136                           struct pipe_surface *ps)
137 {
138    struct pipe_context *pipe = tc->pipe;
139
140    if (tc->transfer) {
141       if (ps == tc->surface)
142          return;
143
144       if (tc->transfer_map) {
145          pipe->transfer_unmap(pipe, tc->transfer);
146          tc->transfer_map = NULL;
147       }
148
149       pipe->transfer_destroy(pipe, tc->transfer);
150       tc->transfer = NULL;
151    }
152
153    tc->surface = ps;
154
155    if (ps) {
156       tc->transfer = pipe_get_transfer(pipe, ps->texture, ps->face,
157                                            ps->level, ps->zslice,
158                                            PIPE_TRANSFER_READ_WRITE,
159                                            0, 0, ps->width, ps->height);
160
161       tc->depth_stencil = (ps->format == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||
162                            ps->format == PIPE_FORMAT_Z24X8_UNORM ||
163                            ps->format == PIPE_FORMAT_S8_USCALED_Z24_UNORM ||
164                            ps->format == PIPE_FORMAT_X8Z24_UNORM ||
165                            ps->format == PIPE_FORMAT_Z16_UNORM ||
166                            ps->format == PIPE_FORMAT_Z32_UNORM ||
167                            ps->format == PIPE_FORMAT_S8_USCALED);
168    }
169 }
170
171
172 /**
173  * Return the transfer being cached.
174  */
175 struct pipe_surface *
176 sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
177 {
178    return tc->surface;
179 }
180
181
182 void
183 sp_tile_cache_map_transfers(struct softpipe_tile_cache *tc)
184 {
185    if (tc->transfer && !tc->transfer_map)
186       tc->transfer_map = tc->pipe->transfer_map(tc->pipe, tc->transfer);
187 }
188
189
190 void
191 sp_tile_cache_unmap_transfers(struct softpipe_tile_cache *tc)
192 {
193    if (tc->transfer_map) {
194       tc->pipe->transfer_unmap(tc->pipe, tc->transfer);
195       tc->transfer_map = NULL;
196    }
197 }
198
199
200 /**
201  * Set pixels in a tile to the given clear color/value, float.
202  */
203 static void
204 clear_tile_rgba(struct softpipe_cached_tile *tile,
205                 enum pipe_format format,
206                 const float clear_value[4])
207 {
208    if (clear_value[0] == 0.0 &&
209        clear_value[1] == 0.0 &&
210        clear_value[2] == 0.0 &&
211        clear_value[3] == 0.0) {
212       memset(tile->data.color, 0, sizeof(tile->data.color));
213    }
214    else {
215       uint i, j;
216       for (i = 0; i < TILE_SIZE; i++) {
217          for (j = 0; j < TILE_SIZE; j++) {
218             tile->data.color[i][j][0] = clear_value[0];
219             tile->data.color[i][j][1] = clear_value[1];
220             tile->data.color[i][j][2] = clear_value[2];
221             tile->data.color[i][j][3] = clear_value[3];
222          }
223       }
224    }
225 }
226
227
228 /**
229  * Set a tile to a solid value/color.
230  */
231 static void
232 clear_tile(struct softpipe_cached_tile *tile,
233            enum pipe_format format,
234            uint clear_value)
235 {
236    uint i, j;
237
238    switch (util_format_get_blocksize(format)) {
239    case 1:
240       memset(tile->data.any, clear_value, TILE_SIZE * TILE_SIZE);
241       break;
242    case 2:
243       if (clear_value == 0) {
244          memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE);
245       }
246       else {
247          for (i = 0; i < TILE_SIZE; i++) {
248             for (j = 0; j < TILE_SIZE; j++) {
249                tile->data.depth16[i][j] = (ushort) clear_value;
250             }
251          }
252       }
253       break;
254    case 4:
255       if (clear_value == 0) {
256          memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE);
257       }
258       else {
259          for (i = 0; i < TILE_SIZE; i++) {
260             for (j = 0; j < TILE_SIZE; j++) {
261                tile->data.color32[i][j] = clear_value;
262             }
263          }
264       }
265       break;
266    default:
267       assert(0);
268    }
269 }
270
271
272 /**
273  * Actually clear the tiles which were flagged as being in a clear state.
274  */
275 static void
276 sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc)
277 {
278    struct pipe_transfer *pt = tc->transfer;
279    const uint w = tc->transfer->box.width;
280    const uint h = tc->transfer->box.height;
281    uint x, y;
282    uint numCleared = 0;
283
284    assert(pt->resource);
285    /* clear the scratch tile to the clear value */
286    clear_tile(&tc->tile, pt->resource->format, tc->clear_val);
287
288    /* push the tile to all positions marked as clear */
289    for (y = 0; y < h; y += TILE_SIZE) {
290       for (x = 0; x < w; x += TILE_SIZE) {
291          union tile_address addr = tile_address(x, y);
292
293          if (is_clear_flag_set(tc->clear_flags, addr)) {
294             pipe_put_tile_raw(tc->pipe,
295                               pt,
296                               x, y, TILE_SIZE, TILE_SIZE,
297                               tc->tile.data.color32, 0/*STRIDE*/);
298
299             numCleared++;
300          }
301       }
302    }
303
304    /* reset all clear flags to zero */
305    memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
306
307 #if 0
308    debug_printf("num cleared: %u\n", numCleared);
309 #endif
310 }
311
312
313 /**
314  * Flush the tile cache: write all dirty tiles back to the transfer.
315  * any tiles "flagged" as cleared will be "really" cleared.
316  */
317 void
318 sp_flush_tile_cache(struct softpipe_tile_cache *tc)
319 {
320    struct pipe_transfer *pt = tc->transfer;
321    int inuse = 0, pos;
322
323    if (pt) {
324       /* caching a drawing transfer */
325       for (pos = 0; pos < NUM_ENTRIES; pos++) {
326          struct softpipe_cached_tile *tile = tc->entries + pos;
327          if (!tile->addr.bits.invalid) {
328             if (tc->depth_stencil) {
329                pipe_put_tile_raw(tc->pipe, pt,
330                                  tile->addr.bits.x * TILE_SIZE, 
331                                  tile->addr.bits.y * TILE_SIZE, 
332                                  TILE_SIZE, TILE_SIZE,
333                                  tile->data.depth32, 0/*STRIDE*/);
334             }
335             else {
336                pipe_put_tile_rgba(tc->pipe, pt,
337                                   tile->addr.bits.x * TILE_SIZE, 
338                                   tile->addr.bits.y * TILE_SIZE, 
339                                   TILE_SIZE, TILE_SIZE,
340                                   (float *) tile->data.color);
341             }
342             tile->addr.bits.invalid = 1;  /* mark as empty */
343             inuse++;
344          }
345       }
346
347 #if TILE_CLEAR_OPTIMIZATION
348       sp_tile_cache_flush_clear(tc);
349 #endif
350    }
351
352 #if 0
353    debug_printf("flushed tiles in use: %d\n", inuse);
354 #endif
355 }
356
357
358 /**
359  * Get a tile from the cache.
360  * \param x, y  position of tile, in pixels
361  */
362 struct softpipe_cached_tile *
363 sp_find_cached_tile(struct softpipe_tile_cache *tc, 
364                     union tile_address addr )
365 {
366    struct pipe_transfer *pt = tc->transfer;
367    
368    /* cache pos/entry: */
369    const int pos = CACHE_POS(addr.bits.x,
370                              addr.bits.y);
371    struct softpipe_cached_tile *tile = tc->entries + pos;
372
373    if (addr.value != tile->addr.value) {
374
375       assert(pt->resource);
376       if (tile->addr.bits.invalid == 0) {
377          /* put dirty tile back in framebuffer */
378          if (tc->depth_stencil) {
379             pipe_put_tile_raw(tc->pipe, pt,
380                               tile->addr.bits.x * TILE_SIZE,
381                               tile->addr.bits.y * TILE_SIZE,
382                               TILE_SIZE, TILE_SIZE,
383                               tile->data.depth32, 0/*STRIDE*/);
384          }
385          else {
386             pipe_put_tile_rgba(tc->pipe, pt,
387                                tile->addr.bits.x * TILE_SIZE,
388                                tile->addr.bits.y * TILE_SIZE,
389                                TILE_SIZE, TILE_SIZE,
390                                (float *) tile->data.color);
391          }
392       }
393
394       tile->addr = addr;
395
396       if (is_clear_flag_set(tc->clear_flags, addr)) {
397          /* don't get tile from framebuffer, just clear it */
398          if (tc->depth_stencil) {
399             clear_tile(tile, pt->resource->format, tc->clear_val);
400          }
401          else {
402             clear_tile_rgba(tile, pt->resource->format, tc->clear_color);
403          }
404          clear_clear_flag(tc->clear_flags, addr);
405       }
406       else {
407          /* get new tile data from transfer */
408          if (tc->depth_stencil) {
409             pipe_get_tile_raw(tc->pipe, pt,
410                               tile->addr.bits.x * TILE_SIZE, 
411                               tile->addr.bits.y * TILE_SIZE, 
412                               TILE_SIZE, TILE_SIZE,
413                               tile->data.depth32, 0/*STRIDE*/);
414          }
415          else {
416             pipe_get_tile_rgba(tc->pipe, pt,
417                                tile->addr.bits.x * TILE_SIZE, 
418                                tile->addr.bits.y * TILE_SIZE,
419                                TILE_SIZE, TILE_SIZE,
420                                (float *) tile->data.color);
421          }
422       }
423    }
424
425    tc->last_tile = tile;
426    return tile;
427 }
428
429
430
431
432
433 /**
434  * When a whole surface is being cleared to a value we can avoid
435  * fetching tiles above.
436  * Save the color and set a 'clearflag' for each tile of the screen.
437  */
438 void
439 sp_tile_cache_clear(struct softpipe_tile_cache *tc, const float *rgba,
440                     uint clearValue)
441 {
442    uint pos;
443
444    tc->clear_color[0] = rgba[0];
445    tc->clear_color[1] = rgba[1];
446    tc->clear_color[2] = rgba[2];
447    tc->clear_color[3] = rgba[3];
448
449    tc->clear_val = clearValue;
450
451 #if TILE_CLEAR_OPTIMIZATION
452    /* set flags to indicate all the tiles are cleared */
453    memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
454 #else
455    /* disable the optimization */
456    memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
457 #endif
458
459    for (pos = 0; pos < NUM_ENTRIES; pos++) {
460       struct softpipe_cached_tile *tile = tc->entries + pos;
461       tile->addr.bits.invalid = 1;
462    }
463 }