Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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 "nv50_context.h"
  29. #include "nv50_resource.h"
  30.  
  31. uint32_t
  32. nv50_tex_choose_tile_dims_helper(unsigned nx, unsigned ny, unsigned nz)
  33. {
  34.    uint32_t tile_mode = 0x000;
  35.  
  36.    if (ny > 64) tile_mode = 0x040; /* height 128 tiles */
  37.    else
  38.    if (ny > 32) tile_mode = 0x030; /* height 64 tiles */
  39.    else
  40.    if (ny > 16) tile_mode = 0x020; /* height 32 tiles */
  41.    else
  42.    if (ny >  8) tile_mode = 0x010; /* height 16 tiles */
  43.  
  44.    if (nz == 1)
  45.       return tile_mode;
  46.    else
  47.       if (tile_mode > 0x020)
  48.          tile_mode = 0x020;
  49.  
  50.    if (nz > 16 && tile_mode < 0x020)
  51.       return tile_mode | 0x500; /* depth 32 tiles */
  52.    if (nz > 8) return tile_mode | 0x400; /* depth 16 tiles */
  53.    if (nz > 4) return tile_mode | 0x300; /* depth 8 tiles */
  54.    if (nz > 2) return tile_mode | 0x200; /* depth 4 tiles */
  55.  
  56.    return tile_mode | 0x100;
  57. }
  58.  
  59. static uint32_t
  60. nv50_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz)
  61. {
  62.    return nv50_tex_choose_tile_dims_helper(nx, ny * 2, nz);
  63. }
  64.  
  65. static uint32_t
  66. nv50_mt_choose_storage_type(struct nv50_miptree *mt, boolean compressed)
  67. {
  68.    const unsigned ms = mt->ms_x + mt->ms_y;
  69.  
  70.    uint32_t tile_flags;
  71.  
  72.    if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR))
  73.       return 0;
  74.    if (unlikely(mt->base.base.bind & PIPE_BIND_CURSOR))
  75.       return 0;
  76.  
  77.    switch (mt->base.base.format) {
  78.    case PIPE_FORMAT_Z16_UNORM:
  79.       tile_flags = 0x6c + ms;
  80.       break;
  81.    case PIPE_FORMAT_S8_UINT_Z24_UNORM:
  82.       tile_flags = 0x18 + ms;
  83.       break;
  84.    case PIPE_FORMAT_Z24X8_UNORM:
  85.    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
  86.       tile_flags = 0x128 + ms;
  87.       break;
  88.    case PIPE_FORMAT_Z32_FLOAT:
  89.       tile_flags = 0x40 + ms;
  90.       break;
  91.    case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
  92.       tile_flags = 0x60 + ms;
  93.       break;
  94.    default:
  95.       switch (util_format_get_blocksizebits(mt->base.base.format)) {
  96.       case 128:
  97.          assert(ms < 3);
  98.          tile_flags = 0x74;
  99.          break;
  100.       case 64:
  101.          switch (ms) {
  102.          case 2: tile_flags = 0xfc; break;
  103.          case 3: tile_flags = 0xfd; break;
  104.          default:
  105.             tile_flags = 0x70;
  106.             break;
  107.          }
  108.          break;
  109.       case 32:
  110.          if (mt->base.base.bind & PIPE_BIND_SCANOUT) {
  111.             assert(ms == 0);
  112.             tile_flags = 0x7a;
  113.          } else {
  114.             switch (ms) {
  115.             case 2: tile_flags = 0xf8; break;
  116.             case 3: tile_flags = 0xf9; break;
  117.             default:
  118.                tile_flags = 0x70;
  119.                break;
  120.             }
  121.          }
  122.          break;
  123.       case 16:
  124.       case 8:
  125.          tile_flags = 0x70;
  126.          break;
  127.       default:
  128.          return 0;
  129.       }
  130.       if (mt->base.base.bind & PIPE_BIND_CURSOR)
  131.          tile_flags = 0;
  132.    }
  133.  
  134.    if (!compressed)
  135.       tile_flags &= ~0x180;
  136.  
  137.    return tile_flags;
  138. }
  139.  
  140. void
  141. nv50_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)
  142. {
  143.    struct nv50_miptree *mt = nv50_miptree(pt);
  144.  
  145.    nouveau_bo_ref(NULL, &mt->base.bo);
  146.  
  147.    nouveau_fence_ref(NULL, &mt->base.fence);
  148.    nouveau_fence_ref(NULL, &mt->base.fence_wr);
  149.  
  150.    NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_count, -1);
  151.    NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_bytes,
  152.                     -(uint64_t)mt->total_size);
  153.  
  154.    FREE(mt);
  155. }
  156.  
  157. boolean
  158. nv50_miptree_get_handle(struct pipe_screen *pscreen,
  159.                         struct pipe_resource *pt,
  160.                         struct winsys_handle *whandle)
  161. {
  162.    struct nv50_miptree *mt = nv50_miptree(pt);
  163.    unsigned stride;
  164.  
  165.    if (!mt || !mt->base.bo)
  166.       return FALSE;
  167.  
  168.    stride = mt->level[0].pitch;
  169.  
  170.    return nouveau_screen_bo_get_handle(pscreen,
  171.                                        mt->base.bo,
  172.                                        stride,
  173.                                        whandle);
  174. }
  175.  
  176. const struct u_resource_vtbl nv50_miptree_vtbl =
  177. {
  178.    nv50_miptree_get_handle,         /* get_handle */
  179.    nv50_miptree_destroy,            /* resource_destroy */
  180.    nv50_miptree_transfer_map,       /* transfer_map */
  181.    u_default_transfer_flush_region, /* transfer_flush_region */
  182.    nv50_miptree_transfer_unmap,     /* transfer_unmap */
  183.    u_default_transfer_inline_write  /* transfer_inline_write */
  184. };
  185.  
  186. static INLINE boolean
  187. nv50_miptree_init_ms_mode(struct nv50_miptree *mt)
  188. {
  189.    switch (mt->base.base.nr_samples) {
  190.    case 8:
  191.       mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS8;
  192.       mt->ms_x = 2;
  193.       mt->ms_y = 1;
  194.       break;
  195.    case 4:
  196.       mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS4;
  197.       mt->ms_x = 1;
  198.       mt->ms_y = 1;
  199.       break;
  200.    case 2:
  201.       mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS2;
  202.       mt->ms_x = 1;
  203.       break;
  204.    case 1:
  205.    case 0:
  206.       mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1;
  207.       break;
  208.    default:
  209.       NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples);
  210.       return FALSE;
  211.    }
  212.    return TRUE;
  213. }
  214.  
  215. boolean
  216. nv50_miptree_init_layout_linear(struct nv50_miptree *mt, unsigned pitch_align)
  217. {
  218.    struct pipe_resource *pt = &mt->base.base;
  219.    const unsigned blocksize = util_format_get_blocksize(pt->format);
  220.    unsigned h = pt->height0;
  221.  
  222.    if (util_format_is_depth_or_stencil(pt->format))
  223.       return FALSE;
  224.  
  225.    if ((pt->last_level > 0) || (pt->depth0 > 1) || (pt->array_size > 1))
  226.       return FALSE;
  227.    if (mt->ms_x | mt->ms_y)
  228.       return FALSE;
  229.  
  230.    mt->level[0].pitch = align(pt->width0 * blocksize, pitch_align);
  231.  
  232.    /* Account for very generous prefetch (allocate size as if tiled). */
  233.    h = MAX2(h, 8);
  234.    h = util_next_power_of_two(h);
  235.  
  236.    mt->total_size = mt->level[0].pitch * h;
  237.  
  238.    return TRUE;
  239. }
  240.  
  241. static void
  242. nv50_miptree_init_layout_video(struct nv50_miptree *mt)
  243. {
  244.    const struct pipe_resource *pt = &mt->base.base;
  245.    const unsigned blocksize = util_format_get_blocksize(pt->format);
  246.  
  247.    assert(pt->last_level == 0);
  248.    assert(mt->ms_x == 0 && mt->ms_y == 0);
  249.    assert(!util_format_is_compressed(pt->format));
  250.  
  251.    mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
  252.  
  253.    mt->level[0].tile_mode = 0x20;
  254.    mt->level[0].pitch = align(pt->width0 * blocksize, 64);
  255.    mt->total_size = align(pt->height0, 16) * mt->level[0].pitch * (mt->layout_3d ? pt->depth0 : 1);
  256.  
  257.    if (pt->array_size > 1) {
  258.       mt->layer_stride = align(mt->total_size, NV50_TILE_SIZE(0x20));
  259.       mt->total_size = mt->layer_stride * pt->array_size;
  260.    }
  261. }
  262.  
  263. static void
  264. nv50_miptree_init_layout_tiled(struct nv50_miptree *mt)
  265. {
  266.    struct pipe_resource *pt = &mt->base.base;
  267.    unsigned w, h, d, l;
  268.    const unsigned blocksize = util_format_get_blocksize(pt->format);
  269.  
  270.    mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
  271.  
  272.    w = pt->width0 << mt->ms_x;
  273.    h = pt->height0 << mt->ms_y;
  274.  
  275.    /* For 3D textures, a mipmap is spanned by all the layers, for array
  276.     * textures and cube maps, each layer contains its own mipmaps.
  277.     */
  278.    d = mt->layout_3d ? pt->depth0 : 1;
  279.  
  280.    for (l = 0; l <= pt->last_level; ++l) {
  281.       struct nv50_miptree_level *lvl = &mt->level[l];
  282.       unsigned tsx, tsy, tsz;
  283.       unsigned nbx = util_format_get_nblocksx(pt->format, w);
  284.       unsigned nby = util_format_get_nblocksy(pt->format, h);
  285.  
  286.       lvl->offset = mt->total_size;
  287.  
  288.       lvl->tile_mode = nv50_tex_choose_tile_dims(nbx, nby, d);
  289.  
  290.       tsx = NV50_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */
  291.       tsy = NV50_TILE_SIZE_Y(lvl->tile_mode);
  292.       tsz = NV50_TILE_SIZE_Z(lvl->tile_mode);
  293.  
  294.       lvl->pitch = align(nbx * blocksize, tsx);
  295.  
  296.       mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz);
  297.  
  298.       w = u_minify(w, 1);
  299.       h = u_minify(h, 1);
  300.       d = u_minify(d, 1);
  301.    }
  302.  
  303.    if (pt->array_size > 1) {
  304.       mt->layer_stride = align(mt->total_size,
  305.                                NV50_TILE_SIZE(mt->level[0].tile_mode));
  306.       mt->total_size = mt->layer_stride * pt->array_size;
  307.    }
  308. }
  309.  
  310. struct pipe_resource *
  311. nv50_miptree_create(struct pipe_screen *pscreen,
  312.                     const struct pipe_resource *templ)
  313. {
  314.    struct nouveau_device *dev = nouveau_screen(pscreen)->device;
  315.    struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);
  316.    struct pipe_resource *pt = &mt->base.base;
  317.    int ret;
  318.    union nouveau_bo_config bo_config;
  319.    uint32_t bo_flags;
  320.  
  321.    if (!mt)
  322.       return NULL;
  323.  
  324.    mt->base.vtbl = &nv50_miptree_vtbl;
  325.    *pt = *templ;
  326.    pipe_reference_init(&pt->reference, 1);
  327.    pt->screen = pscreen;
  328.  
  329.    bo_config.nv50.memtype = nv50_mt_choose_storage_type(mt, TRUE);
  330.  
  331.    if (!nv50_miptree_init_ms_mode(mt)) {
  332.       FREE(mt);
  333.       return NULL;
  334.    }
  335.  
  336.    if (unlikely(pt->flags & NV50_RESOURCE_FLAG_VIDEO)) {
  337.       nv50_miptree_init_layout_video(mt);
  338.       /* BO allocation done by client */
  339.       return pt;
  340.    } else
  341.    if (bo_config.nv50.memtype != 0) {
  342.       nv50_miptree_init_layout_tiled(mt);
  343.    } else
  344.    if (!nv50_miptree_init_layout_linear(mt, 64)) {
  345.       FREE(mt);
  346.       return NULL;
  347.    }
  348.    bo_config.nv50.tile_mode = mt->level[0].tile_mode;
  349.  
  350.    bo_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP;
  351.    if (mt->base.base.bind & (PIPE_BIND_CURSOR | PIPE_BIND_DISPLAY_TARGET))
  352.       bo_flags |= NOUVEAU_BO_CONTIG;
  353.  
  354.    ret = nouveau_bo_new(dev, bo_flags, 4096, mt->total_size, &bo_config,
  355.                         &mt->base.bo);
  356.    if (ret) {
  357.       FREE(mt);
  358.       return NULL;
  359.    }
  360.    mt->base.domain = NOUVEAU_BO_VRAM;
  361.    mt->base.address = mt->base.bo->offset;
  362.  
  363.    return pt;
  364. }
  365.  
  366. struct pipe_resource *
  367. nv50_miptree_from_handle(struct pipe_screen *pscreen,
  368.                          const struct pipe_resource *templ,
  369.                          struct winsys_handle *whandle)
  370. {
  371.    struct nv50_miptree *mt;
  372.    unsigned stride;
  373.  
  374.    /* only supports 2D, non-mipmapped textures for the moment */
  375.    if ((templ->target != PIPE_TEXTURE_2D &&
  376.         templ->target != PIPE_TEXTURE_RECT) ||
  377.        templ->last_level != 0 ||
  378.        templ->depth0 != 1 ||
  379.        templ->array_size > 1)
  380.       return NULL;
  381.  
  382.    mt = CALLOC_STRUCT(nv50_miptree);
  383.    if (!mt)
  384.       return NULL;
  385.  
  386.    mt->base.bo = nouveau_screen_bo_from_handle(pscreen, whandle, &stride);
  387.    if (mt->base.bo == NULL) {
  388.       FREE(mt);
  389.       return NULL;
  390.    }
  391.    mt->base.domain = NOUVEAU_BO_VRAM;
  392.    mt->base.address = mt->base.bo->offset;
  393.  
  394.    mt->base.base = *templ;
  395.    mt->base.vtbl = &nv50_miptree_vtbl;
  396.    pipe_reference_init(&mt->base.base.reference, 1);
  397.    mt->base.base.screen = pscreen;
  398.    mt->level[0].pitch = stride;
  399.    mt->level[0].offset = 0;
  400.    mt->level[0].tile_mode = mt->base.bo->config.nv50.tile_mode;
  401.  
  402.    /* no need to adjust bo reference count */
  403.    return &mt->base.base;
  404. }
  405.  
  406.  
  407. /* Offset of zslice @z from start of level @l. */
  408. INLINE unsigned
  409. nv50_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z)
  410. {
  411.    const struct pipe_resource *pt = &mt->base.base;
  412.  
  413.    unsigned tds = NV50_TILE_SHIFT_Z(mt->level[l].tile_mode);
  414.    unsigned ths = NV50_TILE_SHIFT_Y(mt->level[l].tile_mode);
  415.  
  416.    unsigned nby = util_format_get_nblocksy(pt->format,
  417.                                            u_minify(pt->height0, l));
  418.  
  419.    /* to next 2D tile slice within a 3D tile */
  420.    unsigned stride_2d = NV50_TILE_SIZE_2D(mt->level[l].tile_mode);
  421.  
  422.    /* to slice in the next (in z direction) 3D tile */
  423.    unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds;
  424.  
  425.    return (z & ((1 << tds) - 1)) * stride_2d + (z >> tds) * stride_3d;
  426. }
  427.  
  428. /* Surface functions.
  429.  */
  430.  
  431. struct nv50_surface *
  432. nv50_surface_from_miptree(struct nv50_miptree *mt,
  433.                           const struct pipe_surface *templ)
  434. {
  435.    struct pipe_surface *ps;
  436.    struct nv50_surface *ns = CALLOC_STRUCT(nv50_surface);
  437.    if (!ns)
  438.       return NULL;
  439.    ps = &ns->base;
  440.  
  441.    pipe_reference_init(&ps->reference, 1);
  442.    pipe_resource_reference(&ps->texture, &mt->base.base);
  443.  
  444.    ps->format = templ->format;
  445.    ps->writable = templ->writable;
  446.    ps->u.tex.level = templ->u.tex.level;
  447.    ps->u.tex.first_layer = templ->u.tex.first_layer;
  448.    ps->u.tex.last_layer = templ->u.tex.last_layer;
  449.  
  450.    ns->width = u_minify(mt->base.base.width0, ps->u.tex.level);
  451.    ns->height = u_minify(mt->base.base.height0, ps->u.tex.level);
  452.    ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
  453.    ns->offset = mt->level[templ->u.tex.level].offset;
  454.  
  455.    /* comment says there are going to be removed, but they're used by the st */
  456.    ps->width = ns->width;
  457.    ps->height = ns->height;
  458.  
  459.    ns->width <<= mt->ms_x;
  460.    ns->height <<= mt->ms_y;
  461.  
  462.    return ns;
  463. }
  464.  
  465. struct pipe_surface *
  466. nv50_miptree_surface_new(struct pipe_context *pipe,
  467.                          struct pipe_resource *pt,
  468.                          const struct pipe_surface *templ)
  469. {
  470.    struct nv50_miptree *mt = nv50_miptree(pt);
  471.    struct nv50_surface *ns = nv50_surface_from_miptree(mt, templ);
  472.    if (!ns)
  473.       return NULL;
  474.    ns->base.context = pipe;
  475.  
  476.    if (ns->base.u.tex.first_layer) {
  477.       const unsigned l = ns->base.u.tex.level;
  478.       const unsigned z = ns->base.u.tex.first_layer;
  479.  
  480.       if (mt->layout_3d) {
  481.          ns->offset += nv50_mt_zslice_offset(mt, l, z);
  482.  
  483.          /* TODO: switch to depth 1 tiles; but actually this shouldn't happen */
  484.          if (ns->depth > 1 &&
  485.              (z & (NV50_TILE_SIZE_Z(mt->level[l].tile_mode) - 1)))
  486.             NOUVEAU_ERR("Creating unsupported 3D surface !\n");
  487.       } else {
  488.          ns->offset += mt->layer_stride * z;
  489.       }
  490.    }
  491.  
  492.    return &ns->base;
  493. }
  494.