Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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, boolean 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, boolean 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 boolean
  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.    u_default_transfer_inline_write  /* transfer_inline_write */
  244. };
  245.  
  246. struct pipe_resource *
  247. nvc0_miptree_create(struct pipe_screen *pscreen,
  248.                     const struct pipe_resource *templ)
  249. {
  250.    struct nouveau_device *dev = nouveau_screen(pscreen)->device;
  251.    struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);
  252.    struct pipe_resource *pt = &mt->base.base;
  253.    boolean compressed = dev->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 = NOUVEAU_BO_VRAM;
  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.