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