Home | History | Annotate | Download | only in nvc0
      1 /*
      2  * Copyright 2008 Ben Skeggs
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20  * OTHER DEALINGS IN THE SOFTWARE.
     21  */
     22 
     23 #include "pipe/p_state.h"
     24 #include "pipe/p_defines.h"
     25 #include "util/u_inlines.h"
     26 #include "util/u_format.h"
     27 
     28 #include "nvc0/nvc0_context.h"
     29 #include "nvc0/nvc0_resource.h"
     30 
     31 static uint32_t
     32 nvc0_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz, bool is_3d)
     33 {
     34    return nv50_tex_choose_tile_dims_helper(nx, ny, nz, is_3d);
     35 }
     36 
     37 static uint32_t
     38 nvc0_mt_choose_storage_type(struct nv50_miptree *mt, bool compressed)
     39 {
     40    const unsigned ms = util_logbase2(mt->base.base.nr_samples);
     41 
     42    uint32_t tile_flags;
     43 
     44    if (unlikely(mt->base.base.bind & PIPE_BIND_CURSOR))
     45       return 0;
     46    if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR))
     47       return 0;
     48 
     49    switch (mt->base.base.format) {
     50    case PIPE_FORMAT_Z16_UNORM:
     51       if (compressed)
     52          tile_flags = 0x02 + ms;
     53       else
     54          tile_flags = 0x01;
     55       break;
     56    case PIPE_FORMAT_X8Z24_UNORM:
     57    case PIPE_FORMAT_S8X24_UINT:
     58    case PIPE_FORMAT_S8_UINT_Z24_UNORM:
     59       if (compressed)
     60          tile_flags = 0x51 + ms;
     61       else
     62          tile_flags = 0x46;
     63       break;
     64    case PIPE_FORMAT_X24S8_UINT:
     65    case PIPE_FORMAT_Z24X8_UNORM:
     66    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
     67       if (compressed)
     68          tile_flags = 0x17 + ms;
     69       else
     70          tile_flags = 0x11;
     71       break;
     72    case PIPE_FORMAT_Z32_FLOAT:
     73       if (compressed)
     74          tile_flags = 0x86 + ms;
     75       else
     76          tile_flags = 0x7b;
     77       break;
     78    case PIPE_FORMAT_X32_S8X24_UINT:
     79    case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
     80       if (compressed)
     81          tile_flags = 0xce + ms;
     82       else
     83          tile_flags = 0xc3;
     84       break;
     85    default:
     86       switch (util_format_get_blocksizebits(mt->base.base.format)) {
     87       case 128:
     88          if (compressed)
     89             tile_flags = 0xf4 + ms * 2;
     90          else
     91             tile_flags = 0xfe;
     92          break;
     93       case 64:
     94          if (compressed) {
     95             switch (ms) {
     96             case 0: tile_flags = 0xe6; break;
     97             case 1: tile_flags = 0xeb; break;
     98             case 2: tile_flags = 0xed; break;
     99             case 3: tile_flags = 0xf2; break;
    100             default:
    101                return 0;
    102             }
    103          } else {
    104             tile_flags = 0xfe;
    105          }
    106          break;
    107       case 32:
    108          if (compressed && ms) {
    109             switch (ms) {
    110                /* This one makes things blurry:
    111             case 0: tile_flags = 0xdb; break;
    112                */
    113             case 1: tile_flags = 0xdd; break;
    114             case 2: tile_flags = 0xdf; break;
    115             case 3: tile_flags = 0xe4; break;
    116             default:
    117                return 0;
    118             }
    119          } else {
    120             tile_flags = 0xfe;
    121          }
    122          break;
    123       case 16:
    124       case 8:
    125          tile_flags = 0xfe;
    126          break;
    127       default:
    128          return 0;
    129       }
    130       break;
    131    }
    132 
    133    return tile_flags;
    134 }
    135 
    136 static inline bool
    137 nvc0_miptree_init_ms_mode(struct nv50_miptree *mt)
    138 {
    139    switch (mt->base.base.nr_samples) {
    140    case 8:
    141       mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS8;
    142       mt->ms_x = 2;
    143       mt->ms_y = 1;
    144       break;
    145    case 4:
    146       mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS4;
    147       mt->ms_x = 1;
    148       mt->ms_y = 1;
    149       break;
    150    case 2:
    151       mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS2;
    152       mt->ms_x = 1;
    153       break;
    154    case 1:
    155    case 0:
    156       mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS1;
    157       break;
    158    default:
    159       NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples);
    160       return false;
    161    }
    162    return true;
    163 }
    164 
    165 static void
    166 nvc0_miptree_init_layout_video(struct nv50_miptree *mt)
    167 {
    168    const struct pipe_resource *pt = &mt->base.base;
    169    const unsigned blocksize = util_format_get_blocksize(pt->format);
    170 
    171    assert(pt->last_level == 0);
    172    assert(mt->ms_x == 0 && mt->ms_y == 0);
    173    assert(!util_format_is_compressed(pt->format));
    174 
    175    mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
    176 
    177    mt->level[0].tile_mode = 0x10;
    178    mt->level[0].pitch = align(pt->width0 * blocksize, 64);
    179    mt->total_size = align(pt->height0, 16) * mt->level[0].pitch * (mt->layout_3d ? pt->depth0 : 1);
    180 
    181    if (pt->array_size > 1) {
    182       mt->layer_stride = align(mt->total_size, NVC0_TILE_SIZE(0x10));
    183       mt->total_size = mt->layer_stride * pt->array_size;
    184    }
    185 }
    186 
    187 static void
    188 nvc0_miptree_init_layout_tiled(struct nv50_miptree *mt)
    189 {
    190    struct pipe_resource *pt = &mt->base.base;
    191    unsigned w, h, d, l;
    192    const unsigned blocksize = util_format_get_blocksize(pt->format);
    193 
    194    mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
    195 
    196    w = pt->width0 << mt->ms_x;
    197    h = pt->height0 << mt->ms_y;
    198 
    199    /* For 3D textures, a mipmap is spanned by all the layers, for array
    200     * textures and cube maps, each layer contains its own mipmaps.
    201     */
    202    d = mt->layout_3d ? pt->depth0 : 1;
    203 
    204    assert(!mt->ms_mode || !pt->last_level);
    205 
    206    for (l = 0; l <= pt->last_level; ++l) {
    207       struct nv50_miptree_level *lvl = &mt->level[l];
    208       unsigned tsx, tsy, tsz;
    209       unsigned nbx = util_format_get_nblocksx(pt->format, w);
    210       unsigned nby = util_format_get_nblocksy(pt->format, h);
    211 
    212       lvl->offset = mt->total_size;
    213 
    214       lvl->tile_mode = nvc0_tex_choose_tile_dims(nbx, nby, d, mt->layout_3d);
    215 
    216       tsx = NVC0_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */
    217       tsy = NVC0_TILE_SIZE_Y(lvl->tile_mode);
    218       tsz = NVC0_TILE_SIZE_Z(lvl->tile_mode);
    219 
    220       lvl->pitch = align(nbx * blocksize, tsx);
    221 
    222       mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz);
    223 
    224       w = u_minify(w, 1);
    225       h = u_minify(h, 1);
    226       d = u_minify(d, 1);
    227    }
    228 
    229    if (pt->array_size > 1) {
    230       mt->layer_stride = align(mt->total_size,
    231                                NVC0_TILE_SIZE(mt->level[0].tile_mode));
    232       mt->total_size = mt->layer_stride * pt->array_size;
    233    }
    234 }
    235 
    236 const struct u_resource_vtbl nvc0_miptree_vtbl =
    237 {
    238    nv50_miptree_get_handle,         /* get_handle */
    239    nv50_miptree_destroy,            /* resource_destroy */
    240    nvc0_miptree_transfer_map,       /* transfer_map */
    241    u_default_transfer_flush_region, /* transfer_flush_region */
    242    nvc0_miptree_transfer_unmap,     /* transfer_unmap */
    243 };
    244 
    245 struct pipe_resource *
    246 nvc0_miptree_create(struct pipe_screen *pscreen,
    247                     const struct pipe_resource *templ)
    248 {
    249    struct nouveau_device *dev = nouveau_screen(pscreen)->device;
    250    struct nouveau_drm *drm = nouveau_screen(pscreen)->drm;
    251    struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);
    252    struct pipe_resource *pt = &mt->base.base;
    253    bool compressed = drm->version >= 0x01000101;
    254    int ret;
    255    union nouveau_bo_config bo_config;
    256    uint32_t bo_flags;
    257 
    258    if (!mt)
    259       return NULL;
    260 
    261    mt->base.vtbl = &nvc0_miptree_vtbl;
    262    *pt = *templ;
    263    pipe_reference_init(&pt->reference, 1);
    264    pt->screen = pscreen;
    265 
    266    if (pt->usage == PIPE_USAGE_STAGING) {
    267       switch (pt->target) {
    268       case PIPE_TEXTURE_2D:
    269       case PIPE_TEXTURE_RECT:
    270          if (pt->last_level == 0 &&
    271              !util_format_is_depth_or_stencil(pt->format) &&
    272              pt->nr_samples <= 1)
    273             pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
    274          break;
    275       default:
    276          break;
    277       }
    278    }
    279 
    280    if (pt->bind & PIPE_BIND_LINEAR)
    281       pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
    282 
    283    bo_config.nvc0.memtype = nvc0_mt_choose_storage_type(mt, compressed);
    284 
    285    if (!nvc0_miptree_init_ms_mode(mt)) {
    286       FREE(mt);
    287       return NULL;
    288    }
    289 
    290    if (unlikely(pt->flags & NVC0_RESOURCE_FLAG_VIDEO)) {
    291       nvc0_miptree_init_layout_video(mt);
    292    } else
    293    if (likely(bo_config.nvc0.memtype)) {
    294       nvc0_miptree_init_layout_tiled(mt);
    295    } else
    296    if (!nv50_miptree_init_layout_linear(mt, 128)) {
    297       FREE(mt);
    298       return NULL;
    299    }
    300    bo_config.nvc0.tile_mode = mt->level[0].tile_mode;
    301 
    302    if (!bo_config.nvc0.memtype && (pt->usage == PIPE_USAGE_STAGING || pt->bind & PIPE_BIND_SHARED))
    303       mt->base.domain = NOUVEAU_BO_GART;
    304    else
    305       mt->base.domain = NV_VRAM_DOMAIN(nouveau_screen(pscreen));
    306 
    307    bo_flags = mt->base.domain | NOUVEAU_BO_NOSNOOP;
    308 
    309    if (mt->base.base.bind & (PIPE_BIND_CURSOR | PIPE_BIND_DISPLAY_TARGET))
    310       bo_flags |= NOUVEAU_BO_CONTIG;
    311 
    312    ret = nouveau_bo_new(dev, bo_flags, 4096, mt->total_size, &bo_config,
    313                         &mt->base.bo);
    314    if (ret) {
    315       FREE(mt);
    316       return NULL;
    317    }
    318    mt->base.address = mt->base.bo->offset;
    319 
    320    NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_count, 1);
    321    NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_bytes,
    322                     mt->total_size);
    323 
    324    return pt;
    325 }
    326 
    327 /* Offset of zslice @z from start of level @l. */
    328 inline unsigned
    329 nvc0_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z)
    330 {
    331    const struct pipe_resource *pt = &mt->base.base;
    332 
    333    unsigned tds = NVC0_TILE_SHIFT_Z(mt->level[l].tile_mode);
    334    unsigned ths = NVC0_TILE_SHIFT_Y(mt->level[l].tile_mode);
    335 
    336    unsigned nby = util_format_get_nblocksy(pt->format,
    337                                            u_minify(pt->height0, l));
    338 
    339    /* to next 2D tile slice within a 3D tile */
    340    unsigned stride_2d = NVC0_TILE_SIZE_2D(mt->level[l].tile_mode);
    341 
    342    /* to slice in the next (in z direction) 3D tile */
    343    unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds;
    344 
    345    return (z & (1 << (tds - 1))) * stride_2d + (z >> tds) * stride_3d;
    346 }
    347 
    348 /* Surface functions.
    349  */
    350 
    351 struct pipe_surface *
    352 nvc0_miptree_surface_new(struct pipe_context *pipe,
    353                          struct pipe_resource *pt,
    354                          const struct pipe_surface *templ)
    355 {
    356    struct nv50_surface *ns = nv50_surface_from_miptree(nv50_miptree(pt), templ);
    357    if (!ns)
    358       return NULL;
    359    ns->base.context = pipe;
    360    return &ns->base;
    361 }
    362