Home | History | Annotate | Download | only in softpipe
      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  * 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((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 < NUM_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 < NUM_ENTRIES; pos++) {
     74          /*assert(tc->entries[pos].x < 0);*/
     75       }
     76       if (tc->transfer) {
     77          tc->pipe->transfer_destroy(tc->pipe, tc->transfer);
     78       }
     79       if (tc->tex_trans) {
     80          tc->pipe->transfer_destroy(tc->pipe, tc->tex_trans);
     81       }
     82 
     83       FREE( tc );
     84    }
     85 }
     86 
     87 
     88 
     89 
     90 void
     91 sp_tex_tile_cache_map_transfers(struct softpipe_tex_tile_cache *tc)
     92 {
     93    if (tc->tex_trans && !tc->tex_trans_map)
     94       tc->tex_trans_map = tc->pipe->transfer_map(tc->pipe, tc->tex_trans);
     95 }
     96 
     97 
     98 void
     99 sp_tex_tile_cache_unmap_transfers(struct softpipe_tex_tile_cache *tc)
    100 {
    101    if (tc->tex_trans_map) {
    102       tc->pipe->transfer_unmap(tc->pipe, tc->tex_trans);
    103       tc->tex_trans_map = NULL;
    104    }
    105 }
    106 
    107 /**
    108  * Invalidate all cached tiles for the cached texture.
    109  * Should be called when the texture is modified.
    110  */
    111 void
    112 sp_tex_tile_cache_validate_texture(struct softpipe_tex_tile_cache *tc)
    113 {
    114    unsigned i;
    115 
    116    assert(tc);
    117    assert(tc->texture);
    118 
    119    for (i = 0; i < NUM_ENTRIES; i++) {
    120       tc->entries[i].addr.bits.invalid = 1;
    121    }
    122 }
    123 
    124 static boolean
    125 sp_tex_tile_is_compat_view(struct softpipe_tex_tile_cache *tc,
    126                            struct pipe_sampler_view *view)
    127 {
    128    if (!view)
    129       return FALSE;
    130    return (tc->texture == view->texture &&
    131            tc->format == view->format &&
    132            tc->swizzle_r == view->swizzle_r &&
    133            tc->swizzle_g == view->swizzle_g &&
    134            tc->swizzle_b == view->swizzle_b &&
    135            tc->swizzle_a == view->swizzle_a);
    136 }
    137 
    138 /**
    139  * Specify the sampler view to cache.
    140  */
    141 void
    142 sp_tex_tile_cache_set_sampler_view(struct softpipe_tex_tile_cache *tc,
    143                                    struct pipe_sampler_view *view)
    144 {
    145    struct pipe_resource *texture = view ? view->texture : NULL;
    146    uint i;
    147 
    148    assert(!tc->transfer);
    149 
    150    if (!sp_tex_tile_is_compat_view(tc, view)) {
    151       pipe_resource_reference(&tc->texture, texture);
    152 
    153       if (tc->tex_trans) {
    154          if (tc->tex_trans_map) {
    155             tc->pipe->transfer_unmap(tc->pipe, tc->tex_trans);
    156             tc->tex_trans_map = NULL;
    157          }
    158 
    159          tc->pipe->transfer_destroy(tc->pipe, tc->tex_trans);
    160          tc->tex_trans = NULL;
    161       }
    162 
    163       if (view) {
    164          tc->swizzle_r = view->swizzle_r;
    165          tc->swizzle_g = view->swizzle_g;
    166          tc->swizzle_b = view->swizzle_b;
    167          tc->swizzle_a = view->swizzle_a;
    168          tc->format = view->format;
    169       }
    170 
    171       /* mark as entries as invalid/empty */
    172       /* XXX we should try to avoid this when the teximage hasn't changed */
    173       for (i = 0; i < NUM_ENTRIES; i++) {
    174          tc->entries[i].addr.bits.invalid = 1;
    175       }
    176 
    177       tc->tex_face = -1; /* any invalid value here */
    178    }
    179 }
    180 
    181 
    182 
    183 
    184 /**
    185  * Flush the tile cache: write all dirty tiles back to the transfer.
    186  * any tiles "flagged" as cleared will be "really" cleared.
    187  */
    188 void
    189 sp_flush_tex_tile_cache(struct softpipe_tex_tile_cache *tc)
    190 {
    191    int pos;
    192 
    193    if (tc->texture) {
    194       /* caching a texture, mark all entries as empty */
    195       for (pos = 0; pos < NUM_ENTRIES; pos++) {
    196          tc->entries[pos].addr.bits.invalid = 1;
    197       }
    198       tc->tex_face = -1;
    199    }
    200 
    201 }
    202 
    203 
    204 /**
    205  * Given the texture face, level, zslice, x and y values, compute
    206  * the cache entry position/index where we'd hope to find the
    207  * cached texture tile.
    208  * This is basically a direct-map cache.
    209  * XXX There's probably lots of ways in which we can improve this.
    210  */
    211 static INLINE uint
    212 tex_cache_pos( union tex_tile_address addr )
    213 {
    214    uint entry = (addr.bits.x +
    215                  addr.bits.y * 9 +
    216                  addr.bits.z * 3 +
    217                  addr.bits.face +
    218                  addr.bits.level * 7);
    219 
    220    return entry % NUM_ENTRIES;
    221 }
    222 
    223 /**
    224  * Similar to sp_get_cached_tile() but for textures.
    225  * Tiles are read-only and indexed with more params.
    226  */
    227 const struct softpipe_tex_cached_tile *
    228 sp_find_cached_tile_tex(struct softpipe_tex_tile_cache *tc,
    229                         union tex_tile_address addr )
    230 {
    231    struct softpipe_tex_cached_tile *tile;
    232    boolean zs = util_format_is_depth_or_stencil(tc->format);
    233 
    234    tile = tc->entries + tex_cache_pos( addr );
    235 
    236    if (addr.value != tile->addr.value) {
    237 
    238       /* cache miss.  Most misses are because we've invaldiated the
    239        * texture cache previously -- most commonly on binding a new
    240        * texture.  Currently we effectively flush the cache on texture
    241        * bind.
    242        */
    243 #if 0
    244       _debug_printf("miss at %u:  x=%d y=%d z=%d face=%d level=%d\n"
    245                     "   tile %u:  x=%d y=%d z=%d face=%d level=%d\n",
    246                     pos, x/TILE_SIZE, y/TILE_SIZE, z, face, level,
    247                     pos, tile->addr.bits.x, tile->addr.bits.y, tile->z, tile->face, tile->level);
    248 #endif
    249 
    250       /* check if we need to get a new transfer */
    251       if (!tc->tex_trans ||
    252           tc->tex_face != addr.bits.face ||
    253           tc->tex_level != addr.bits.level ||
    254           tc->tex_z != addr.bits.z) {
    255          /* get new transfer (view into texture) */
    256          unsigned width, height, layer;
    257 
    258          if (tc->tex_trans) {
    259             if (tc->tex_trans_map) {
    260                tc->pipe->transfer_unmap(tc->pipe, tc->tex_trans);
    261                tc->tex_trans_map = NULL;
    262             }
    263 
    264             tc->pipe->transfer_destroy(tc->pipe, tc->tex_trans);
    265             tc->tex_trans = NULL;
    266          }
    267 
    268          width = u_minify(tc->texture->width0, addr.bits.level);
    269          if (tc->texture->target == PIPE_TEXTURE_1D_ARRAY) {
    270             height = tc->texture->array_size;
    271             layer = 0;
    272          }
    273          else {
    274             height = u_minify(tc->texture->height0, addr.bits.level);
    275             layer = addr.bits.face + addr.bits.z;
    276          }
    277 
    278          tc->tex_trans =
    279             pipe_get_transfer(tc->pipe, tc->texture,
    280                               addr.bits.level,
    281                               layer,
    282                               PIPE_TRANSFER_READ | PIPE_TRANSFER_UNSYNCHRONIZED,
    283                               0, 0, width, height);
    284 
    285          tc->tex_trans_map = tc->pipe->transfer_map(tc->pipe, tc->tex_trans);
    286 
    287          tc->tex_face = addr.bits.face;
    288          tc->tex_level = addr.bits.level;
    289          tc->tex_z = addr.bits.z;
    290       }
    291 
    292       /* Get tile from the transfer (view into texture), explicitly passing
    293        * the image format.
    294        */
    295       if (!zs && util_format_is_pure_uint(tc->format)) {
    296          pipe_get_tile_ui_format(tc->pipe,
    297                                  tc->tex_trans,
    298                                  addr.bits.x * TILE_SIZE,
    299                                  addr.bits.y * TILE_SIZE,
    300                                  TILE_SIZE,
    301                                  TILE_SIZE,
    302                                  tc->format,
    303                                  (unsigned *) tile->data.colorui);
    304       } else if (!zs && util_format_is_pure_sint(tc->format)) {
    305          pipe_get_tile_i_format(tc->pipe,
    306                                 tc->tex_trans,
    307                                 addr.bits.x * TILE_SIZE,
    308                                 addr.bits.y * TILE_SIZE,
    309                                 TILE_SIZE,
    310                                  TILE_SIZE,
    311                                 tc->format,
    312                                 (int *) tile->data.colori);
    313       } else {
    314          pipe_get_tile_rgba_format(tc->pipe,
    315                                    tc->tex_trans,
    316                                    addr.bits.x * TILE_SIZE,
    317                                    addr.bits.y * TILE_SIZE,
    318                                    TILE_SIZE,
    319                                    TILE_SIZE,
    320                                    tc->format,
    321                                    (float *) tile->data.color);
    322       }
    323       tile->addr = addr;
    324    }
    325 
    326    tc->last_tile = tile;
    327    return tile;
    328 }
    329