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