1 /**************************************************************************
2  *
3  * Copyright 2007 VMware, Inc.
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 VMWARE 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/format/u_format.h"
37 #include "util/u_memory.h"
38 #include "util/u_tile.h"
39 #include "sp_tile_cache.h"
40 
41 static struct softpipe_cached_tile *
42 sp_alloc_tile(struct softpipe_tile_cache *tc);
43 
44 
45 /**
46  * Return the position in the cache for the tile that contains win pos (x,y).
47  * We currently use a direct mapped cache so this is like a hack key.
48  * At some point we should investige something more sophisticated, like
49  * a LRU replacement policy.
50  */
51 #define CACHE_POS(x, y, l)                        \
52    (((x) + (y) * 5 + (l) * 10) % NUM_ENTRIES)
53 
54 
addr_to_clear_pos(union tile_address addr)55 static inline int addr_to_clear_pos(union tile_address addr)
56 {
57    int pos;
58    pos = addr.bits.layer * (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE);
59    pos += addr.bits.y * (MAX_WIDTH / TILE_SIZE);
60    pos += addr.bits.x;
61    return pos;
62 }
63 /**
64  * Is the tile at (x,y) in cleared state?
65  */
66 static inline uint
is_clear_flag_set(const uint * bitvec,union tile_address addr,unsigned max)67 is_clear_flag_set(const uint *bitvec, union tile_address addr, unsigned max)
68 {
69    int pos, bit;
70    pos = addr_to_clear_pos(addr);
71    assert(pos / 32 < max);
72    bit = bitvec[pos / 32] & (1 << (pos & 31));
73    return bit;
74 }
75 
76 
77 /**
78  * Mark the tile at (x,y) as not cleared.
79  */
80 static inline void
clear_clear_flag(uint * bitvec,union tile_address addr,unsigned max)81 clear_clear_flag(uint *bitvec, union tile_address addr, unsigned max)
82 {
83    int pos;
84    pos = addr_to_clear_pos(addr);
85    assert(pos / 32 < max);
86    bitvec[pos / 32] &= ~(1 << (pos & 31));
87 }
88 
89 
90 struct softpipe_tile_cache *
sp_create_tile_cache(struct pipe_context * pipe)91 sp_create_tile_cache( struct pipe_context *pipe )
92 {
93    struct softpipe_tile_cache *tc;
94    uint pos;
95 
96    /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
97    assert(MAX_WIDTH >= pipe->screen->get_param(pipe->screen,
98                                                PIPE_CAP_MAX_TEXTURE_2D_SIZE));
99 
100    STATIC_ASSERT(sizeof(union tile_address) == 4);
101 
102    STATIC_ASSERT((TILE_SIZE << TILE_ADDR_BITS) >= MAX_WIDTH);
103 
104    tc = CALLOC_STRUCT( softpipe_tile_cache );
105    if (tc) {
106       tc->pipe = pipe;
107       for (pos = 0; pos < ARRAY_SIZE(tc->tile_addrs); pos++) {
108          tc->tile_addrs[pos].bits.invalid = 1;
109       }
110       tc->last_tile_addr.bits.invalid = 1;
111 
112       /* this allocation allows us to guarantee that allocation
113        * failures are never fatal later
114        */
115       tc->tile = MALLOC_STRUCT( softpipe_cached_tile );
116       if (!tc->tile)
117       {
118          FREE(tc);
119          return NULL;
120       }
121 
122       /* XXX this code prevents valgrind warnings about use of uninitialized
123        * memory in programs that don't clear the surface before rendering.
124        * However, it breaks clearing in other situations (such as in
125        * progs/tests/drawbuffers, see bug 24402).
126        */
127 #if 0
128       /* set flags to indicate all the tiles are cleared */
129       memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
130 #endif
131    }
132    return tc;
133 }
134 
135 
136 void
sp_destroy_tile_cache(struct softpipe_tile_cache * tc)137 sp_destroy_tile_cache(struct softpipe_tile_cache *tc)
138 {
139    if (tc) {
140       uint pos;
141 
142       for (pos = 0; pos < ARRAY_SIZE(tc->entries); pos++) {
143          /*assert(tc->entries[pos].x < 0);*/
144          FREE( tc->entries[pos] );
145       }
146       FREE( tc->tile );
147 
148       if (tc->num_maps) {
149          int i;
150          for (i = 0; i < tc->num_maps; i++)
151             if (tc->transfer[i]) {
152                tc->pipe->transfer_unmap(tc->pipe, tc->transfer[i]);
153             }
154          FREE(tc->transfer);
155          FREE(tc->transfer_map);
156          FREE(tc->clear_flags);
157       }
158 
159       FREE( tc );
160    }
161 }
162 
163 
164 /**
165  * Specify the surface to cache.
166  */
167 void
sp_tile_cache_set_surface(struct softpipe_tile_cache * tc,struct pipe_surface * ps)168 sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
169                           struct pipe_surface *ps)
170 {
171    struct pipe_context *pipe = tc->pipe;
172    int i;
173 
174    if (tc->num_maps) {
175       if (ps == tc->surface)
176          return;
177 
178       for (i = 0; i < tc->num_maps; i++) {
179          pipe->transfer_unmap(pipe, tc->transfer[i]);
180          tc->transfer[i] = NULL;
181          tc->transfer_map[i] = NULL;
182       }
183       FREE(tc->transfer);
184       FREE(tc->transfer_map);
185       tc->num_maps = 0;
186 
187       FREE(tc->clear_flags);
188       tc->clear_flags_size = 0;
189    }
190 
191    tc->surface = ps;
192 
193    if (ps) {
194       tc->num_maps = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
195       tc->transfer = CALLOC(tc->num_maps, sizeof(struct pipe_transfer *));
196       tc->transfer_map = CALLOC(tc->num_maps, sizeof(void *));
197 
198       tc->clear_flags_size = (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) * tc->num_maps / 32 * sizeof(uint);
199       tc->clear_flags = CALLOC(1, tc->clear_flags_size);
200 
201       if (ps->texture->target != PIPE_BUFFER) {
202          for (i = 0; i < tc->num_maps; i++) {
203             tc->transfer_map[i] = pipe_transfer_map(pipe, ps->texture,
204                                                     ps->u.tex.level, ps->u.tex.first_layer + i,
205                                                     PIPE_MAP_READ_WRITE |
206                                                     PIPE_MAP_UNSYNCHRONIZED,
207                                                     0, 0, ps->width, ps->height,
208                                                     &tc->transfer[i]);
209          }
210       }
211       else {
212          /* can't render to buffers */
213          assert(0);
214       }
215 
216       tc->depth_stencil = util_format_is_depth_or_stencil(ps->format);
217    }
218 }
219 
220 
221 /**
222  * Return the transfer being cached.
223  */
224 struct pipe_surface *
sp_tile_cache_get_surface(struct softpipe_tile_cache * tc)225 sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
226 {
227    return tc->surface;
228 }
229 
230 
231 /**
232  * Set pixels in a tile to the given clear color/value, float.
233  */
234 static void
clear_tile_rgba(struct softpipe_cached_tile * tile,enum pipe_format format,const union pipe_color_union * clear_value)235 clear_tile_rgba(struct softpipe_cached_tile *tile,
236                 enum pipe_format format,
237                 const union pipe_color_union *clear_value)
238 {
239    if (clear_value->f[0] == 0.0 &&
240        clear_value->f[1] == 0.0 &&
241        clear_value->f[2] == 0.0 &&
242        clear_value->f[3] == 0.0) {
243       memset(tile->data.color, 0, sizeof(tile->data.color));
244    }
245    else {
246       uint i, j;
247 
248       if (util_format_is_pure_uint(format)) {
249          for (i = 0; i < TILE_SIZE; i++) {
250             for (j = 0; j < TILE_SIZE; j++) {
251                tile->data.colorui128[i][j][0] = clear_value->ui[0];
252                tile->data.colorui128[i][j][1] = clear_value->ui[1];
253                tile->data.colorui128[i][j][2] = clear_value->ui[2];
254                tile->data.colorui128[i][j][3] = clear_value->ui[3];
255             }
256          }
257       } else if (util_format_is_pure_sint(format)) {
258          for (i = 0; i < TILE_SIZE; i++) {
259             for (j = 0; j < TILE_SIZE; j++) {
260                tile->data.colori128[i][j][0] = clear_value->i[0];
261                tile->data.colori128[i][j][1] = clear_value->i[1];
262                tile->data.colori128[i][j][2] = clear_value->i[2];
263                tile->data.colori128[i][j][3] = clear_value->i[3];
264             }
265          }
266       } else {
267          for (i = 0; i < TILE_SIZE; i++) {
268             for (j = 0; j < TILE_SIZE; j++) {
269                tile->data.color[i][j][0] = clear_value->f[0];
270                tile->data.color[i][j][1] = clear_value->f[1];
271                tile->data.color[i][j][2] = clear_value->f[2];
272                tile->data.color[i][j][3] = clear_value->f[3];
273             }
274          }
275       }
276    }
277 }
278 
279 
280 /**
281  * Set a tile to a solid value/color.
282  */
283 static void
clear_tile(struct softpipe_cached_tile * tile,enum pipe_format format,uint64_t clear_value)284 clear_tile(struct softpipe_cached_tile *tile,
285            enum pipe_format format,
286            uint64_t clear_value)
287 {
288    uint i, j;
289 
290    switch (util_format_get_blocksize(format)) {
291    case 1:
292       memset(tile->data.any, (int) clear_value, TILE_SIZE * TILE_SIZE);
293       break;
294    case 2:
295       if (clear_value == 0) {
296          memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE);
297       }
298       else {
299          for (i = 0; i < TILE_SIZE; i++) {
300             for (j = 0; j < TILE_SIZE; j++) {
301                tile->data.depth16[i][j] = (ushort) clear_value;
302             }
303          }
304       }
305       break;
306    case 4:
307       if (clear_value == 0) {
308          memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE);
309       }
310       else {
311          for (i = 0; i < TILE_SIZE; i++) {
312             for (j = 0; j < TILE_SIZE; j++) {
313                tile->data.depth32[i][j] = (uint) clear_value;
314             }
315          }
316       }
317       break;
318    case 8:
319       if (clear_value == 0) {
320          memset(tile->data.any, 0, 8 * TILE_SIZE * TILE_SIZE);
321       }
322       else {
323          for (i = 0; i < TILE_SIZE; i++) {
324             for (j = 0; j < TILE_SIZE; j++) {
325                tile->data.depth64[i][j] = clear_value;
326             }
327          }
328       }
329       break;
330    default:
331       assert(0);
332    }
333 }
334 
335 
336 /**
337  * Actually clear the tiles which were flagged as being in a clear state.
338  */
339 static void
sp_tile_cache_flush_clear(struct softpipe_tile_cache * tc,int layer)340 sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc, int layer)
341 {
342    struct pipe_transfer *pt = tc->transfer[layer];
343    const uint w = tc->transfer[layer]->box.width;
344    const uint h = tc->transfer[layer]->box.height;
345    uint x, y;
346    uint numCleared = 0;
347 
348    assert(pt->resource);
349 
350    /* clear the scratch tile to the clear value */
351    if (tc->depth_stencil) {
352       clear_tile(tc->tile, pt->resource->format, tc->clear_val);
353    } else {
354       clear_tile_rgba(tc->tile, pt->resource->format, &tc->clear_color);
355    }
356 
357    /* push the tile to all positions marked as clear */
358    for (y = 0; y < h; y += TILE_SIZE) {
359       for (x = 0; x < w; x += TILE_SIZE) {
360          union tile_address addr = tile_address(x, y, layer);
361 
362          if (is_clear_flag_set(tc->clear_flags, addr, tc->clear_flags_size)) {
363             /* write the scratch tile to the surface */
364             if (tc->depth_stencil) {
365                pipe_put_tile_raw(pt, tc->transfer_map[layer],
366                                  x, y, TILE_SIZE, TILE_SIZE,
367                                  tc->tile->data.any, 0/*STRIDE*/);
368             }
369             else {
370                pipe_put_tile_rgba(pt, tc->transfer_map[layer],
371                                   x, y, TILE_SIZE, TILE_SIZE,
372                                   tc->surface->format,
373                                   tc->tile->data.color);
374             }
375             numCleared++;
376          }
377       }
378    }
379 
380 
381 #if 0
382    debug_printf("num cleared: %u\n", numCleared);
383 #endif
384 }
385 
386 static void
sp_flush_tile(struct softpipe_tile_cache * tc,unsigned pos)387 sp_flush_tile(struct softpipe_tile_cache* tc, unsigned pos)
388 {
389    int layer = tc->tile_addrs[pos].bits.layer;
390    if (!tc->tile_addrs[pos].bits.invalid) {
391       if (tc->depth_stencil) {
392          pipe_put_tile_raw(tc->transfer[layer], tc->transfer_map[layer],
393                            tc->tile_addrs[pos].bits.x * TILE_SIZE,
394                            tc->tile_addrs[pos].bits.y * TILE_SIZE,
395                            TILE_SIZE, TILE_SIZE,
396                            tc->entries[pos]->data.depth32, 0/*STRIDE*/);
397       }
398       else {
399          pipe_put_tile_rgba(tc->transfer[layer], tc->transfer_map[layer],
400                             tc->tile_addrs[pos].bits.x * TILE_SIZE,
401                             tc->tile_addrs[pos].bits.y * TILE_SIZE,
402                             TILE_SIZE, TILE_SIZE,
403                             tc->surface->format,
404                             tc->entries[pos]->data.color);
405       }
406       tc->tile_addrs[pos].bits.invalid = 1;  /* mark as empty */
407    }
408 }
409 
410 /**
411  * Flush the tile cache: write all dirty tiles back to the transfer.
412  * any tiles "flagged" as cleared will be "really" cleared.
413  */
414 void
sp_flush_tile_cache(struct softpipe_tile_cache * tc)415 sp_flush_tile_cache(struct softpipe_tile_cache *tc)
416 {
417    int inuse = 0, pos;
418    int i;
419    if (tc->num_maps) {
420       /* caching a drawing transfer */
421       for (pos = 0; pos < ARRAY_SIZE(tc->entries); pos++) {
422          struct softpipe_cached_tile *tile = tc->entries[pos];
423          if (!tile)
424          {
425             assert(tc->tile_addrs[pos].bits.invalid);
426             continue;
427          }
428          sp_flush_tile(tc, pos);
429          ++inuse;
430       }
431 
432       if (!tc->tile)
433          tc->tile = sp_alloc_tile(tc);
434 
435       for (i = 0; i < tc->num_maps; i++)
436          sp_tile_cache_flush_clear(tc, i);
437       /* reset all clear flags to zero */
438       memset(tc->clear_flags, 0, tc->clear_flags_size);
439 
440       tc->last_tile_addr.bits.invalid = 1;
441    }
442 
443 #if 0
444    debug_printf("flushed tiles in use: %d\n", inuse);
445 #endif
446 }
447 
448 static struct softpipe_cached_tile *
sp_alloc_tile(struct softpipe_tile_cache * tc)449 sp_alloc_tile(struct softpipe_tile_cache *tc)
450 {
451    struct softpipe_cached_tile * tile = MALLOC_STRUCT(softpipe_cached_tile);
452    if (!tile)
453    {
454       /* in this case, steal an existing tile */
455       if (!tc->tile)
456       {
457          unsigned pos;
458          for (pos = 0; pos < ARRAY_SIZE(tc->entries); ++pos) {
459             if (!tc->entries[pos])
460                continue;
461 
462             sp_flush_tile(tc, pos);
463             tc->tile = tc->entries[pos];
464             tc->entries[pos] = NULL;
465             break;
466          }
467 
468          /* this should never happen */
469          if (!tc->tile)
470             abort();
471       }
472 
473       tile = tc->tile;
474       tc->tile = NULL;
475 
476       tc->last_tile_addr.bits.invalid = 1;
477    }
478    return tile;
479 }
480 
481 /**
482  * Get a tile from the cache.
483  * \param x, y  position of tile, in pixels
484  */
485 struct softpipe_cached_tile *
sp_find_cached_tile(struct softpipe_tile_cache * tc,union tile_address addr)486 sp_find_cached_tile(struct softpipe_tile_cache *tc,
487                     union tile_address addr )
488 {
489    struct pipe_transfer *pt;
490    /* cache pos/entry: */
491    const int pos = CACHE_POS(addr.bits.x,
492                              addr.bits.y, addr.bits.layer);
493    struct softpipe_cached_tile *tile = tc->entries[pos];
494    int layer;
495    if (!tile) {
496       tile = sp_alloc_tile(tc);
497       tc->entries[pos] = tile;
498    }
499 
500    if (addr.value != tc->tile_addrs[pos].value) {
501 
502       layer = tc->tile_addrs[pos].bits.layer;
503       if (tc->tile_addrs[pos].bits.invalid == 0) {
504          /* put dirty tile back in framebuffer */
505          if (tc->depth_stencil) {
506             pipe_put_tile_raw(tc->transfer[layer], tc->transfer_map[layer],
507                               tc->tile_addrs[pos].bits.x * TILE_SIZE,
508                               tc->tile_addrs[pos].bits.y * TILE_SIZE,
509                               TILE_SIZE, TILE_SIZE,
510                               tile->data.depth32, 0/*STRIDE*/);
511          }
512          else {
513             pipe_put_tile_rgba(tc->transfer[layer], tc->transfer_map[layer],
514                                tc->tile_addrs[pos].bits.x * TILE_SIZE,
515                                tc->tile_addrs[pos].bits.y * TILE_SIZE,
516                                TILE_SIZE, TILE_SIZE,
517                                tc->surface->format,
518                                tile->data.color);
519          }
520       }
521 
522       tc->tile_addrs[pos] = addr;
523 
524       layer = tc->tile_addrs[pos].bits.layer;
525       pt = tc->transfer[layer];
526       assert(pt->resource);
527 
528       if (is_clear_flag_set(tc->clear_flags, addr, tc->clear_flags_size)) {
529          /* don't get tile from framebuffer, just clear it */
530          if (tc->depth_stencil) {
531             clear_tile(tile, pt->resource->format, tc->clear_val);
532          }
533          else {
534             clear_tile_rgba(tile, pt->resource->format, &tc->clear_color);
535          }
536          clear_clear_flag(tc->clear_flags, addr, tc->clear_flags_size);
537       }
538       else {
539          /* get new tile data from transfer */
540          if (tc->depth_stencil) {
541             pipe_get_tile_raw(tc->transfer[layer], tc->transfer_map[layer],
542                               tc->tile_addrs[pos].bits.x * TILE_SIZE,
543                               tc->tile_addrs[pos].bits.y * TILE_SIZE,
544                               TILE_SIZE, TILE_SIZE,
545                               tile->data.depth32, 0/*STRIDE*/);
546          }
547          else {
548             pipe_get_tile_rgba(tc->transfer[layer], tc->transfer_map[layer],
549                                tc->tile_addrs[pos].bits.x * TILE_SIZE,
550                                tc->tile_addrs[pos].bits.y * TILE_SIZE,
551                                TILE_SIZE, TILE_SIZE,
552                                tc->surface->format,
553                                tile->data.color);
554          }
555       }
556    }
557 
558    tc->last_tile = tile;
559    tc->last_tile_addr = addr;
560    return tile;
561 }
562 
563 
564 
565 
566 
567 /**
568  * When a whole surface is being cleared to a value we can avoid
569  * fetching tiles above.
570  * Save the color and set a 'clearflag' for each tile of the screen.
571  */
572 void
sp_tile_cache_clear(struct softpipe_tile_cache * tc,const union pipe_color_union * color,uint64_t clearValue)573 sp_tile_cache_clear(struct softpipe_tile_cache *tc,
574                     const union pipe_color_union *color,
575                     uint64_t clearValue)
576 {
577    uint pos;
578 
579    tc->clear_color = *color;
580 
581    tc->clear_val = clearValue;
582 
583    /* set flags to indicate all the tiles are cleared */
584    memset(tc->clear_flags, 255, tc->clear_flags_size);
585 
586    for (pos = 0; pos < ARRAY_SIZE(tc->tile_addrs); pos++) {
587       tc->tile_addrs[pos].bits.invalid = 1;
588    }
589    tc->last_tile_addr.bits.invalid = 1;
590 }
591