Home | History | Annotate | Download | only in softpipe
      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  * Texture tile caching.
     30  *
     31  * Author:
     32  *    Brian Paul
     33  */
     34 
     35 #include "util/u_inlines.h"
     36 #include "util/u_memory.h"
     37 #include "util/u_tile.h"
     38 #include "util/u_format.h"
     39 #include "util/u_math.h"
     40 #include "sp_context.h"
     41 #include "sp_texture.h"
     42 #include "sp_tex_tile_cache.h"
     43 
     44 
     45 
     46 struct softpipe_tex_tile_cache *
     47 sp_create_tex_tile_cache( struct pipe_context *pipe )
     48 {
     49    struct softpipe_tex_tile_cache *tc;
     50    uint pos;
     51 
     52    /* make sure max texture size works */
     53    assert((TEX_TILE_SIZE << TEX_ADDR_BITS) >= (1 << (SP_MAX_TEXTURE_2D_LEVELS-1)));
     54 
     55    tc = CALLOC_STRUCT( softpipe_tex_tile_cache );
     56    if (tc) {
     57       tc->pipe = pipe;
     58       for (pos = 0; pos < ARRAY_SIZE(tc->entries); pos++) {
     59          tc->entries[pos].addr.bits.invalid = 1;
     60       }
     61       tc->last_tile = &tc->entries[0]; /* any tile */
     62    }
     63    return tc;
     64 }
     65 
     66 
     67 void
     68 sp_destroy_tex_tile_cache(struct softpipe_tex_tile_cache *tc)
     69 {
     70    if (tc) {
     71       uint pos;
     72 
     73       for (pos = 0; pos < ARRAY_SIZE(tc->entries); pos++) {
     74          /*assert(tc->entries[pos].x < 0);*/
     75       }
     76       if (tc->transfer) {
     77          tc->pipe->transfer_unmap(tc->pipe, tc->transfer);
     78       }
     79       if (tc->tex_trans) {
     80          tc->pipe->transfer_unmap(tc->pipe, tc->tex_trans);
     81       }
     82 
     83       FREE( tc );
     84    }
     85 }
     86 
     87 
     88 /**
     89  * Invalidate all cached tiles for the cached texture.
     90  * Should be called when the texture is modified.
     91  */
     92 void
     93 sp_tex_tile_cache_validate_texture(struct softpipe_tex_tile_cache *tc)
     94 {
     95    unsigned i;
     96 
     97    assert(tc);
     98    assert(tc->texture);
     99 
    100    for (i = 0; i < ARRAY_SIZE(tc->entries); i++) {
    101       tc->entries[i].addr.bits.invalid = 1;
    102    }
    103 }
    104 
    105 static boolean
    106 sp_tex_tile_is_compat_view(struct softpipe_tex_tile_cache *tc,
    107                            struct pipe_sampler_view *view)
    108 {
    109    if (!view)
    110       return FALSE;
    111    return (tc->texture == view->texture &&
    112            tc->format == view->format &&
    113            tc->swizzle_r == view->swizzle_r &&
    114            tc->swizzle_g == view->swizzle_g &&
    115            tc->swizzle_b == view->swizzle_b &&
    116            tc->swizzle_a == view->swizzle_a);
    117 }
    118 
    119 /**
    120  * Specify the sampler view to cache.
    121  */
    122 void
    123 sp_tex_tile_cache_set_sampler_view(struct softpipe_tex_tile_cache *tc,
    124                                    struct pipe_sampler_view *view)
    125 {
    126    struct pipe_resource *texture = view ? view->texture : NULL;
    127    uint i;
    128 
    129    assert(!tc->transfer);
    130 
    131    if (!sp_tex_tile_is_compat_view(tc, view)) {
    132       pipe_resource_reference(&tc->texture, texture);
    133 
    134       if (tc->tex_trans_map) {
    135          tc->pipe->transfer_unmap(tc->pipe, tc->tex_trans);
    136          tc->tex_trans = NULL;
    137          tc->tex_trans_map = NULL;
    138       }
    139 
    140       if (view) {
    141          tc->swizzle_r = view->swizzle_r;
    142          tc->swizzle_g = view->swizzle_g;
    143          tc->swizzle_b = view->swizzle_b;
    144          tc->swizzle_a = view->swizzle_a;
    145          tc->format = view->format;
    146       }
    147 
    148       /* mark as entries as invalid/empty */
    149       /* XXX we should try to avoid this when the teximage hasn't changed */
    150       for (i = 0; i < ARRAY_SIZE(tc->entries); i++) {
    151          tc->entries[i].addr.bits.invalid = 1;
    152       }
    153 
    154       tc->tex_z = -1; /* any invalid value here */
    155    }
    156 }
    157 
    158 
    159 
    160 
    161 /**
    162  * Flush the tile cache: write all dirty tiles back to the transfer.
    163  * any tiles "flagged" as cleared will be "really" cleared.
    164  */
    165 void
    166 sp_flush_tex_tile_cache(struct softpipe_tex_tile_cache *tc)
    167 {
    168    int pos;
    169 
    170    if (tc->texture) {
    171       /* caching a texture, mark all entries as empty */
    172       for (pos = 0; pos < ARRAY_SIZE(tc->entries); pos++) {
    173          tc->entries[pos].addr.bits.invalid = 1;
    174       }
    175       tc->tex_z = -1;
    176    }
    177 
    178 }
    179 
    180 
    181 /**
    182  * Given the texture face, level, zslice, x and y values, compute
    183  * the cache entry position/index where we'd hope to find the
    184  * cached texture tile.
    185  * This is basically a direct-map cache.
    186  * XXX There's probably lots of ways in which we can improve this.
    187  */
    188 static inline uint
    189 tex_cache_pos( union tex_tile_address addr )
    190 {
    191    uint entry = (addr.bits.x +
    192                  addr.bits.y * 9 +
    193                  addr.bits.z +
    194                  addr.bits.level * 7);
    195 
    196    return entry % NUM_TEX_TILE_ENTRIES;
    197 }
    198 
    199 /**
    200  * Similar to sp_get_cached_tile() but for textures.
    201  * Tiles are read-only and indexed with more params.
    202  */
    203 const struct softpipe_tex_cached_tile *
    204 sp_find_cached_tile_tex(struct softpipe_tex_tile_cache *tc,
    205                         union tex_tile_address addr )
    206 {
    207    struct softpipe_tex_cached_tile *tile;
    208    boolean zs = util_format_is_depth_or_stencil(tc->format);
    209 
    210    tile = tc->entries + tex_cache_pos( addr );
    211 
    212    if (addr.value != tile->addr.value) {
    213 
    214       /* cache miss.  Most misses are because we've invalidated the
    215        * texture cache previously -- most commonly on binding a new
    216        * texture.  Currently we effectively flush the cache on texture
    217        * bind.
    218        */
    219 #if 0
    220       _debug_printf("miss at %u:  x=%d y=%d z=%d face=%d level=%d\n"
    221                     "   tile %u:  x=%d y=%d z=%d face=%d level=%d\n",
    222                     pos, x/TILE_SIZE, y/TILE_SIZE, z, face, level,
    223                     pos, tile->addr.bits.x, tile->addr.bits.y, tile->z, tile->face, tile->level);
    224 #endif
    225 
    226       /* check if we need to get a new transfer */
    227       if (!tc->tex_trans ||
    228           tc->tex_level != addr.bits.level ||
    229           tc->tex_z != addr.bits.z) {
    230          /* get new transfer (view into texture) */
    231          unsigned width, height, layer;
    232 
    233          if (tc->tex_trans_map) {
    234             tc->pipe->transfer_unmap(tc->pipe, tc->tex_trans);
    235             tc->tex_trans = NULL;
    236             tc->tex_trans_map = NULL;
    237          }
    238 
    239          width = u_minify(tc->texture->width0, addr.bits.level);
    240          if (tc->texture->target == PIPE_TEXTURE_1D_ARRAY) {
    241             height = tc->texture->array_size;
    242             layer = 0;
    243          }
    244          else {
    245             height = u_minify(tc->texture->height0, addr.bits.level);
    246             layer = addr.bits.z;
    247          }
    248 
    249          tc->tex_trans_map =
    250             pipe_transfer_map(tc->pipe, tc->texture,
    251                               addr.bits.level,
    252                               layer,
    253                               PIPE_TRANSFER_READ | PIPE_TRANSFER_UNSYNCHRONIZED,
    254                               0, 0, width, height, &tc->tex_trans);
    255 
    256          tc->tex_level = addr.bits.level;
    257          tc->tex_z = addr.bits.z;
    258       }
    259 
    260       /* Get tile from the transfer (view into texture), explicitly passing
    261        * the image format.
    262        */
    263       if (!zs && util_format_is_pure_uint(tc->format)) {
    264          pipe_get_tile_ui_format(tc->tex_trans, tc->tex_trans_map,
    265                                  addr.bits.x * TEX_TILE_SIZE,
    266                                  addr.bits.y * TEX_TILE_SIZE,
    267                                  TEX_TILE_SIZE,
    268                                  TEX_TILE_SIZE,
    269                                  tc->format,
    270                                  (unsigned *) tile->data.colorui);
    271       } else if (!zs && util_format_is_pure_sint(tc->format)) {
    272          pipe_get_tile_i_format(tc->tex_trans, tc->tex_trans_map,
    273                                 addr.bits.x * TEX_TILE_SIZE,
    274                                 addr.bits.y * TEX_TILE_SIZE,
    275                                 TEX_TILE_SIZE,
    276                                 TEX_TILE_SIZE,
    277                                 tc->format,
    278                                 (int *) tile->data.colori);
    279       } else {
    280          pipe_get_tile_rgba_format(tc->tex_trans, tc->tex_trans_map,
    281                                    addr.bits.x * TEX_TILE_SIZE,
    282                                    addr.bits.y * TEX_TILE_SIZE,
    283                                    TEX_TILE_SIZE,
    284                                    TEX_TILE_SIZE,
    285                                    tc->format,
    286                                    (float *) tile->data.color);
    287       }
    288       tile->addr = addr;
    289    }
    290 
    291    tc->last_tile = tile;
    292    return tile;
    293 }
    294