Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 2012-2013 LunarG, Inc.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22.  * DEALINGS IN THE SOFTWARE.
  23.  *
  24.  * Authors:
  25.  *    Chia-I Wu <olv@lunarg.com>
  26.  */
  27.  
  28. #include "ilo_screen.h"
  29. #include "ilo_resource.h"
  30.  
  31. /*
  32.  * From the Ivy Bridge PRM, volume 1 part 1, page 105:
  33.  *
  34.  *     "In addition to restrictions on maximum height, width, and depth,
  35.  *      surfaces are also restricted to a maximum size in bytes. This
  36.  *      maximum is 2 GB for all products and all surface types."
  37.  */
  38. static const size_t ilo_max_resource_size = 1u << 31;
  39.  
  40. static const char *
  41. resource_get_bo_name(const struct pipe_resource *templ)
  42. {
  43.    static const char *target_names[PIPE_MAX_TEXTURE_TYPES] = {
  44.       [PIPE_BUFFER] = "buf",
  45.       [PIPE_TEXTURE_1D] = "tex-1d",
  46.       [PIPE_TEXTURE_2D] = "tex-2d",
  47.       [PIPE_TEXTURE_3D] = "tex-3d",
  48.       [PIPE_TEXTURE_CUBE] = "tex-cube",
  49.       [PIPE_TEXTURE_RECT] = "tex-rect",
  50.       [PIPE_TEXTURE_1D_ARRAY] = "tex-1d-array",
  51.       [PIPE_TEXTURE_2D_ARRAY] = "tex-2d-array",
  52.       [PIPE_TEXTURE_CUBE_ARRAY] = "tex-cube-array",
  53.    };
  54.    const char *name = target_names[templ->target];
  55.  
  56.    if (templ->target == PIPE_BUFFER) {
  57.       switch (templ->bind) {
  58.       case PIPE_BIND_VERTEX_BUFFER:
  59.          name = "buf-vb";
  60.          break;
  61.       case PIPE_BIND_INDEX_BUFFER:
  62.          name = "buf-ib";
  63.          break;
  64.       case PIPE_BIND_CONSTANT_BUFFER:
  65.          name = "buf-cb";
  66.          break;
  67.       case PIPE_BIND_STREAM_OUTPUT:
  68.          name = "buf-so";
  69.          break;
  70.       default:
  71.          break;
  72.       }
  73.    }
  74.  
  75.    return name;
  76. }
  77.  
  78. static bool
  79. resource_get_cpu_init(const struct pipe_resource *templ)
  80. {
  81.    return (templ->bind & (PIPE_BIND_DEPTH_STENCIL |
  82.                           PIPE_BIND_RENDER_TARGET |
  83.                           PIPE_BIND_STREAM_OUTPUT)) ? false : true;
  84. }
  85.  
  86. static enum gen_surface_tiling
  87. winsys_to_surface_tiling(enum intel_tiling_mode tiling)
  88. {
  89.    switch (tiling) {
  90.    case INTEL_TILING_NONE:
  91.       return GEN6_TILING_NONE;
  92.    case INTEL_TILING_X:
  93.       return GEN6_TILING_X;
  94.    case INTEL_TILING_Y:
  95.       return GEN6_TILING_Y;
  96.    default:
  97.       assert(!"unknown tiling");
  98.       return GEN6_TILING_NONE;
  99.    }
  100. }
  101.  
  102. static inline enum intel_tiling_mode
  103. surface_to_winsys_tiling(enum gen_surface_tiling tiling)
  104. {
  105.    switch (tiling) {
  106.    case GEN6_TILING_NONE:
  107.       return INTEL_TILING_NONE;
  108.    case GEN6_TILING_X:
  109.       return INTEL_TILING_X;
  110.    case GEN6_TILING_Y:
  111.       return INTEL_TILING_Y;
  112.    default:
  113.       assert(!"unknown tiling");
  114.       return GEN6_TILING_NONE;
  115.    }
  116. }
  117.  
  118. static void
  119. tex_free_slices(struct ilo_texture *tex)
  120. {
  121.    FREE(tex->slices[0]);
  122. }
  123.  
  124. static bool
  125. tex_alloc_slices(struct ilo_texture *tex)
  126. {
  127.    const struct pipe_resource *templ = &tex->base;
  128.    struct ilo_texture_slice *slices;
  129.    int depth, lv;
  130.  
  131.    /* sum the depths of all levels */
  132.    depth = 0;
  133.    for (lv = 0; lv <= templ->last_level; lv++)
  134.       depth += u_minify(templ->depth0, lv);
  135.  
  136.    /*
  137.     * There are (depth * tex->base.array_size) slices in total.  Either depth
  138.     * is one (non-3D) or templ->array_size is one (non-array), but it does
  139.     * not matter.
  140.     */
  141.    slices = CALLOC(depth * templ->array_size, sizeof(*slices));
  142.    if (!slices)
  143.       return false;
  144.  
  145.    tex->slices[0] = slices;
  146.  
  147.    /* point to the respective positions in the buffer */
  148.    for (lv = 1; lv <= templ->last_level; lv++) {
  149.       tex->slices[lv] = tex->slices[lv - 1] +
  150.          u_minify(templ->depth0, lv - 1) * templ->array_size;
  151.    }
  152.  
  153.    return true;
  154. }
  155.  
  156. static bool
  157. tex_create_bo(struct ilo_texture *tex)
  158. {
  159.    struct ilo_screen *is = ilo_screen(tex->base.screen);
  160.    const char *name = resource_get_bo_name(&tex->base);
  161.    const bool cpu_init = resource_get_cpu_init(&tex->base);
  162.    struct intel_bo *bo;
  163.  
  164.    bo = intel_winsys_alloc_bo(is->dev.winsys, name,
  165.          tex->image.bo_stride * tex->image.bo_height, cpu_init);
  166.  
  167.    /* set the tiling for transfer and export */
  168.    if (bo && (tex->image.tiling == GEN6_TILING_X ||
  169.               tex->image.tiling == GEN6_TILING_Y)) {
  170.       const enum intel_tiling_mode tiling =
  171.          surface_to_winsys_tiling(tex->image.tiling);
  172.  
  173.       if (intel_bo_set_tiling(bo, tiling, tex->image.bo_stride)) {
  174.          intel_bo_unref(bo);
  175.          bo = NULL;
  176.       }
  177.    }
  178.    if (!bo)
  179.       return false;
  180.  
  181.    ilo_image_set_bo(&tex->image, bo);
  182.    intel_bo_unref(bo);
  183.  
  184.    return true;
  185. }
  186.  
  187. static bool
  188. tex_create_separate_stencil(struct ilo_texture *tex)
  189. {
  190.    struct pipe_resource templ = tex->base;
  191.    struct pipe_resource *s8;
  192.  
  193.    /*
  194.     * Unless PIPE_BIND_DEPTH_STENCIL is set, the resource may have other
  195.     * tilings.  But that should be fine since it will never be bound as the
  196.     * stencil buffer, and our transfer code can handle all tilings.
  197.     */
  198.    templ.format = PIPE_FORMAT_S8_UINT;
  199.  
  200.    /* no stencil texturing */
  201.    templ.bind &= ~PIPE_BIND_SAMPLER_VIEW;
  202.  
  203.    s8 = tex->base.screen->resource_create(tex->base.screen, &templ);
  204.    if (!s8)
  205.       return false;
  206.  
  207.    tex->separate_s8 = ilo_texture(s8);
  208.  
  209.    assert(tex->separate_s8->image.format == PIPE_FORMAT_S8_UINT);
  210.  
  211.    return true;
  212. }
  213.  
  214. static bool
  215. tex_create_hiz(struct ilo_texture *tex)
  216. {
  217.    const struct pipe_resource *templ = &tex->base;
  218.    struct ilo_screen *is = ilo_screen(tex->base.screen);
  219.    struct intel_bo *bo;
  220.  
  221.    bo = intel_winsys_alloc_bo(is->dev.winsys, "hiz texture",
  222.          tex->image.aux.bo_stride * tex->image.aux.bo_height, false);
  223.    if (!bo)
  224.       return false;
  225.  
  226.    ilo_image_set_aux_bo(&tex->image, bo);
  227.  
  228.    if (tex->imported) {
  229.       unsigned lv;
  230.  
  231.       for (lv = 0; lv <= templ->last_level; lv++) {
  232.          if (tex->image.aux.enables & (1 << lv)) {
  233.             const unsigned num_slices = (templ->target == PIPE_TEXTURE_3D) ?
  234.                u_minify(templ->depth0, lv) : templ->array_size;
  235.             /* this will trigger HiZ resolves */
  236.             const unsigned flags = ILO_TEXTURE_CPU_WRITE;
  237.  
  238.             ilo_texture_set_slice_flags(tex, lv, 0, num_slices, flags, flags);
  239.          }
  240.       }
  241.    }
  242.  
  243.    return true;
  244. }
  245.  
  246. static bool
  247. tex_create_mcs(struct ilo_texture *tex)
  248. {
  249.    struct ilo_screen *is = ilo_screen(tex->base.screen);
  250.    struct intel_bo *bo;
  251.  
  252.    assert(tex->image.aux.enables == (1 << (tex->base.last_level + 1)) - 1);
  253.  
  254.    bo = intel_winsys_alloc_bo(is->dev.winsys, "mcs texture",
  255.          tex->image.aux.bo_stride * tex->image.aux.bo_height, false);
  256.    if (!bo)
  257.       return false;
  258.  
  259.    ilo_image_set_aux_bo(&tex->image, bo);
  260.  
  261.    return true;
  262. }
  263.  
  264. static void
  265. tex_destroy(struct ilo_texture *tex)
  266. {
  267.    if (tex->separate_s8)
  268.       tex_destroy(tex->separate_s8);
  269.  
  270.    ilo_image_cleanup(&tex->image);
  271.  
  272.    tex_free_slices(tex);
  273.    FREE(tex);
  274. }
  275.  
  276. static bool
  277. tex_alloc_bos(struct ilo_texture *tex)
  278. {
  279.    struct ilo_screen *is = ilo_screen(tex->base.screen);
  280.  
  281.    if (!tex->imported && !tex_create_bo(tex))
  282.       return false;
  283.  
  284.    /* allocate separate stencil resource */
  285.    if (tex->image.separate_stencil && !tex_create_separate_stencil(tex))
  286.       return false;
  287.  
  288.    switch (tex->image.aux.type) {
  289.    case ILO_IMAGE_AUX_HIZ:
  290.       if (!tex_create_hiz(tex)) {
  291.          /* Separate Stencil Buffer requires HiZ to be enabled */
  292.          if (ilo_dev_gen(&is->dev) == ILO_GEN(6) &&
  293.              tex->image.separate_stencil)
  294.             return false;
  295.       }
  296.       break;
  297.    case ILO_IMAGE_AUX_MCS:
  298.       if (!tex_create_mcs(tex))
  299.          return false;
  300.       break;
  301.    default:
  302.       break;
  303.    }
  304.  
  305.    return true;
  306. }
  307.  
  308. static bool
  309. tex_import_handle(struct ilo_texture *tex,
  310.                   const struct winsys_handle *handle)
  311. {
  312.    struct ilo_screen *is = ilo_screen(tex->base.screen);
  313.    const struct pipe_resource *templ = &tex->base;
  314.    const char *name = resource_get_bo_name(&tex->base);
  315.    enum intel_tiling_mode tiling;
  316.    unsigned long pitch;
  317.    struct intel_bo *bo;
  318.  
  319.    bo = intel_winsys_import_handle(is->dev.winsys, name, handle,
  320.          tex->image.bo_height, &tiling, &pitch);
  321.    if (!bo)
  322.       return false;
  323.  
  324.    if (!ilo_image_init_for_imported(&tex->image, &is->dev, templ,
  325.             winsys_to_surface_tiling(tiling), pitch)) {
  326.       ilo_err("failed to import handle for texture\n");
  327.       intel_bo_unref(bo);
  328.       return false;
  329.    }
  330.  
  331.    ilo_image_set_bo(&tex->image, bo);
  332.    intel_bo_unref(bo);
  333.  
  334.    tex->imported = true;
  335.  
  336.    return true;
  337. }
  338.  
  339. static bool
  340. tex_init_image(struct ilo_texture *tex,
  341.                const struct winsys_handle *handle)
  342. {
  343.    struct ilo_screen *is = ilo_screen(tex->base.screen);
  344.    const struct pipe_resource *templ = &tex->base;
  345.    struct ilo_image *img = &tex->image;
  346.  
  347.    if (handle) {
  348.       if (!tex_import_handle(tex, handle))
  349.          return false;
  350.    } else {
  351.       ilo_image_init(img, &is->dev, templ);
  352.    }
  353.  
  354.    if (img->bo_height > ilo_max_resource_size / img->bo_stride)
  355.       return false;
  356.  
  357.    if (templ->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) {
  358.       /* require on-the-fly tiling/untiling or format conversion */
  359.       if (img->tiling == GEN8_TILING_W || img->separate_stencil ||
  360.           img->format != templ->format)
  361.          return false;
  362.    }
  363.  
  364.    if (!tex_alloc_slices(tex))
  365.       return false;
  366.  
  367.    return true;
  368. }
  369.  
  370. static struct pipe_resource *
  371. tex_create(struct pipe_screen *screen,
  372.            const struct pipe_resource *templ,
  373.            const struct winsys_handle *handle)
  374. {
  375.    struct ilo_texture *tex;
  376.  
  377.    tex = CALLOC_STRUCT(ilo_texture);
  378.    if (!tex)
  379.       return NULL;
  380.  
  381.    tex->base = *templ;
  382.    tex->base.screen = screen;
  383.    pipe_reference_init(&tex->base.reference, 1);
  384.  
  385.    if (!tex_init_image(tex, handle)) {
  386.       FREE(tex);
  387.       return NULL;
  388.    }
  389.  
  390.    if (!tex_alloc_bos(tex)) {
  391.       tex_destroy(tex);
  392.       return NULL;
  393.    }
  394.  
  395.    return &tex->base;
  396. }
  397.  
  398. static bool
  399. tex_get_handle(struct ilo_texture *tex, struct winsys_handle *handle)
  400. {
  401.    struct ilo_screen *is = ilo_screen(tex->base.screen);
  402.    enum intel_tiling_mode tiling;
  403.    int err;
  404.  
  405.    /* must match what tex_create_bo() sets */
  406.    if (tex->image.tiling == GEN8_TILING_W)
  407.       tiling = INTEL_TILING_NONE;
  408.    else
  409.       tiling = surface_to_winsys_tiling(tex->image.tiling);
  410.  
  411.    err = intel_winsys_export_handle(is->dev.winsys, tex->image.bo, tiling,
  412.          tex->image.bo_stride, tex->image.bo_height, handle);
  413.  
  414.    return !err;
  415. }
  416.  
  417. static bool
  418. buf_create_bo(struct ilo_buffer_resource *buf)
  419. {
  420.    struct ilo_screen *is = ilo_screen(buf->base.screen);
  421.    const char *name = resource_get_bo_name(&buf->base);
  422.    const bool cpu_init = resource_get_cpu_init(&buf->base);
  423.    struct intel_bo *bo;
  424.  
  425.    bo = intel_winsys_alloc_bo(is->dev.winsys, name,
  426.          buf->buffer.bo_size, cpu_init);
  427.    if (!bo)
  428.       return false;
  429.  
  430.    ilo_buffer_set_bo(&buf->buffer, bo);
  431.    intel_bo_unref(bo);
  432.  
  433.    return true;
  434. }
  435.  
  436. static void
  437. buf_destroy(struct ilo_buffer_resource *buf)
  438. {
  439.    ilo_buffer_cleanup(&buf->buffer);
  440.    FREE(buf);
  441. }
  442.  
  443. static struct pipe_resource *
  444. buf_create(struct pipe_screen *screen, const struct pipe_resource *templ)
  445. {
  446.    const struct ilo_screen *is = ilo_screen(screen);
  447.    struct ilo_buffer_resource *buf;
  448.  
  449.    buf = CALLOC_STRUCT(ilo_buffer_resource);
  450.    if (!buf)
  451.       return NULL;
  452.  
  453.    buf->base = *templ;
  454.    buf->base.screen = screen;
  455.    pipe_reference_init(&buf->base.reference, 1);
  456.  
  457.    ilo_buffer_init(&buf->buffer, &is->dev,
  458.          templ->width0, templ->bind, templ->flags);
  459.  
  460.    if (buf->buffer.bo_size < templ->width0 ||
  461.        buf->buffer.bo_size > ilo_max_resource_size ||
  462.        !buf_create_bo(buf)) {
  463.       FREE(buf);
  464.       return NULL;
  465.    }
  466.  
  467.    return &buf->base;
  468. }
  469.  
  470. static boolean
  471. ilo_can_create_resource(struct pipe_screen *screen,
  472.                         const struct pipe_resource *templ)
  473. {
  474.    struct ilo_image img;
  475.  
  476.    if (templ->target == PIPE_BUFFER)
  477.       return (templ->width0 <= ilo_max_resource_size);
  478.  
  479.    memset(&img, 0, sizeof(img));
  480.    ilo_image_init(&img, &ilo_screen(screen)->dev, templ);
  481.  
  482.    return (img.bo_height <= ilo_max_resource_size / img.bo_stride);
  483. }
  484.  
  485. static struct pipe_resource *
  486. ilo_resource_create(struct pipe_screen *screen,
  487.                     const struct pipe_resource *templ)
  488. {
  489.    if (templ->target == PIPE_BUFFER)
  490.       return buf_create(screen, templ);
  491.    else
  492.       return tex_create(screen, templ, NULL);
  493. }
  494.  
  495. static struct pipe_resource *
  496. ilo_resource_from_handle(struct pipe_screen *screen,
  497.                          const struct pipe_resource *templ,
  498.                          struct winsys_handle *handle)
  499. {
  500.    if (templ->target == PIPE_BUFFER)
  501.       return NULL;
  502.    else
  503.       return tex_create(screen, templ, handle);
  504. }
  505.  
  506. static boolean
  507. ilo_resource_get_handle(struct pipe_screen *screen,
  508.                         struct pipe_resource *res,
  509.                         struct winsys_handle *handle)
  510. {
  511.    if (res->target == PIPE_BUFFER)
  512.       return false;
  513.    else
  514.       return tex_get_handle(ilo_texture(res), handle);
  515.  
  516. }
  517.  
  518. static void
  519. ilo_resource_destroy(struct pipe_screen *screen,
  520.                      struct pipe_resource *res)
  521. {
  522.    if (res->target == PIPE_BUFFER)
  523.       buf_destroy((struct ilo_buffer_resource *) res);
  524.    else
  525.       tex_destroy(ilo_texture(res));
  526. }
  527.  
  528. /**
  529.  * Initialize resource-related functions.
  530.  */
  531. void
  532. ilo_init_resource_functions(struct ilo_screen *is)
  533. {
  534.    is->base.can_create_resource = ilo_can_create_resource;
  535.    is->base.resource_create = ilo_resource_create;
  536.    is->base.resource_from_handle = ilo_resource_from_handle;
  537.    is->base.resource_get_handle = ilo_resource_get_handle;
  538.    is->base.resource_destroy = ilo_resource_destroy;
  539. }
  540.  
  541. bool
  542. ilo_resource_rename_bo(struct pipe_resource *res)
  543. {
  544.    if (res->target == PIPE_BUFFER) {
  545.       return buf_create_bo((struct ilo_buffer_resource *) res);
  546.    } else {
  547.       struct ilo_texture *tex = ilo_texture(res);
  548.  
  549.       /* an imported texture cannot be renamed */
  550.       if (tex->imported)
  551.          return false;
  552.  
  553.       return tex_create_bo(tex);
  554.    }
  555. }
  556.