Home | History | Annotate | Download | only in ilo
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 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 (at) lunarg.com>
     26  */
     27 
     28 #include "genhw/genhw.h"
     29 #include "core/ilo_builder_mi.h"
     30 #include "core/ilo_builder_blt.h"
     31 #include "util/u_pack_color.h"
     32 
     33 #include "ilo_context.h"
     34 #include "ilo_cp.h"
     35 #include "ilo_blit.h"
     36 #include "ilo_resource.h"
     37 #include "ilo_blitter.h"
     38 
     39 static uint32_t
     40 ilo_blitter_blt_begin(struct ilo_blitter *blitter, int max_cmd_size,
     41                       struct intel_bo *dst,
     42                       enum gen_surface_tiling dst_tiling,
     43                       struct intel_bo *src,
     44                       enum gen_surface_tiling src_tiling)
     45 {
     46    struct ilo_cp *cp = blitter->ilo->cp;
     47    struct intel_bo *aper_check[2];
     48    int count;
     49    uint32_t swctrl;
     50 
     51    /* change owner */
     52    ilo_cp_set_owner(cp, INTEL_RING_BLT, NULL);
     53 
     54    /* check aperture space */
     55    aper_check[0] = dst;
     56    count = 1;
     57 
     58    if (src) {
     59       aper_check[1] = src;
     60       count++;
     61    }
     62 
     63    if (!ilo_builder_validate(&cp->builder, count, aper_check))
     64       ilo_cp_submit(cp, "out of aperture");
     65 
     66    /* set BCS_SWCTRL */
     67    swctrl = 0x0;
     68 
     69    assert(dst_tiling == GEN6_TILING_NONE ||
     70           dst_tiling == GEN6_TILING_X ||
     71           dst_tiling == GEN6_TILING_Y);
     72    assert(src_tiling == GEN6_TILING_NONE ||
     73           src_tiling == GEN6_TILING_X ||
     74           src_tiling == GEN6_TILING_Y);
     75 
     76    if (dst_tiling == GEN6_TILING_Y) {
     77       swctrl |= GEN6_REG_BCS_SWCTRL_DST_TILING_Y << 16 |
     78                 GEN6_REG_BCS_SWCTRL_DST_TILING_Y;
     79    }
     80 
     81    if (src && src_tiling == GEN6_TILING_Y) {
     82       swctrl |= GEN6_REG_BCS_SWCTRL_SRC_TILING_Y << 16 |
     83                 GEN6_REG_BCS_SWCTRL_SRC_TILING_Y;
     84    }
     85 
     86    /*
     87     * Most clients expect BLT engine to be stateless.  If we have to set
     88     * BCS_SWCTRL to a non-default value, we have to set it back in the same
     89     * batch buffer.
     90     */
     91    if (swctrl)
     92       max_cmd_size += (4 + 3) * 2;
     93 
     94    if (ilo_cp_space(cp) < max_cmd_size) {
     95       ilo_cp_submit(cp, "out of space");
     96       assert(ilo_cp_space(cp) >= max_cmd_size);
     97    }
     98 
     99    if (swctrl) {
    100       /*
    101        * From the Ivy Bridge PRM, volume 1 part 4, page 133:
    102        *
    103        *     "SW is required to flush the HW before changing the polarity of
    104        *      this bit (Tile Y Destination/Source)."
    105        */
    106       gen6_MI_FLUSH_DW(&cp->builder);
    107       gen6_MI_LOAD_REGISTER_IMM(&cp->builder, GEN6_REG_BCS_SWCTRL, swctrl);
    108 
    109       swctrl &= ~(GEN6_REG_BCS_SWCTRL_DST_TILING_Y |
    110                   GEN6_REG_BCS_SWCTRL_SRC_TILING_Y);
    111    }
    112 
    113    return swctrl;
    114 }
    115 
    116 static void
    117 ilo_blitter_blt_end(struct ilo_blitter *blitter, uint32_t swctrl)
    118 {
    119    struct ilo_builder *builder = &blitter->ilo->cp->builder;
    120 
    121    /* set BCS_SWCTRL back */
    122    if (swctrl) {
    123       gen6_MI_FLUSH_DW(builder);
    124       gen6_MI_LOAD_REGISTER_IMM(builder, GEN6_REG_BCS_SWCTRL, swctrl);
    125    }
    126 }
    127 
    128 static bool
    129 buf_clear_region(struct ilo_blitter *blitter,
    130                  struct ilo_buffer_resource *buf, unsigned offset,
    131                  uint32_t val, unsigned size,
    132                  enum gen6_blt_mask value_mask,
    133                  enum gen6_blt_mask write_mask)
    134 {
    135    const uint8_t rop = 0xf0; /* PATCOPY */
    136    const int cpp = gen6_blt_translate_value_cpp(value_mask);
    137    struct ilo_builder *builder = &blitter->ilo->cp->builder;
    138    struct gen6_blt_bo dst;
    139 
    140    if (offset % cpp || size % cpp)
    141       return false;
    142 
    143    dst.bo = buf->vma.bo;
    144    dst.offset = buf->vma.bo_offset + offset;
    145 
    146    ilo_blitter_blt_begin(blitter, GEN6_COLOR_BLT__SIZE *
    147          (1 + size / 32764 / gen6_blt_max_scanlines),
    148          dst.bo, GEN6_TILING_NONE, NULL, GEN6_TILING_NONE);
    149 
    150    while (size) {
    151       unsigned width, height;
    152 
    153       width = size;
    154       height = 1;
    155 
    156       if (width > gen6_blt_max_bytes_per_scanline) {
    157          /* less than INT16_MAX and dword-aligned */
    158          width = 32764;
    159          height = size / width;
    160          if (height > gen6_blt_max_scanlines)
    161             height = gen6_blt_max_scanlines;
    162 
    163          dst.pitch = width;
    164       } else {
    165          dst.pitch = 0;
    166       }
    167 
    168       gen6_COLOR_BLT(builder, &dst, val,
    169             width, height, rop, value_mask, write_mask);
    170 
    171       dst.offset += dst.pitch * height;
    172       size -= width * height;
    173    }
    174 
    175    ilo_blitter_blt_end(blitter, 0);
    176 
    177    return true;
    178 }
    179 
    180 static bool
    181 buf_copy_region(struct ilo_blitter *blitter,
    182                 struct ilo_buffer_resource *dst_buf, unsigned dst_offset,
    183                 struct ilo_buffer_resource *src_buf, unsigned src_offset,
    184                 unsigned size)
    185 {
    186    const uint8_t rop = 0xcc; /* SRCCOPY */
    187    struct ilo_builder *builder = &blitter->ilo->cp->builder;
    188    struct gen6_blt_bo dst, src;
    189 
    190    dst.bo = dst_buf->vma.bo;
    191    dst.offset = dst_buf->vma.bo_offset + dst_offset;
    192    dst.pitch = 0;
    193 
    194    src.bo = src_buf->vma.bo;
    195    src.offset = src_buf->vma.bo_offset + src_offset;
    196    src.pitch = 0;
    197 
    198    ilo_blitter_blt_begin(blitter, GEN6_SRC_COPY_BLT__SIZE *
    199          (1 + size / 32764 / gen6_blt_max_scanlines),
    200          dst_buf->vma.bo, GEN6_TILING_NONE,
    201          src_buf->vma.bo, GEN6_TILING_NONE);
    202 
    203    while (size) {
    204       unsigned width, height;
    205 
    206       width = size;
    207       height = 1;
    208 
    209       if (width > gen6_blt_max_bytes_per_scanline) {
    210          /* less than INT16_MAX and dword-aligned */
    211          width = 32764;
    212          height = size / width;
    213          if (height > gen6_blt_max_scanlines)
    214             height = gen6_blt_max_scanlines;
    215 
    216          dst.pitch = width;
    217          src.pitch = width;
    218       } else {
    219          dst.pitch = 0;
    220          src.pitch = 0;
    221       }
    222 
    223       gen6_SRC_COPY_BLT(builder, &dst, &src,
    224             width, height, rop, GEN6_BLT_MASK_8, GEN6_BLT_MASK_8);
    225 
    226       dst.offset += dst.pitch * height;
    227       src.offset += src.pitch * height;
    228       size -= width * height;
    229    }
    230 
    231    ilo_blitter_blt_end(blitter, 0);
    232 
    233    return true;
    234 }
    235 
    236 static bool
    237 tex_clear_region(struct ilo_blitter *blitter,
    238                  struct ilo_texture *dst_tex, unsigned dst_level,
    239                  const struct pipe_box *dst_box,
    240                  uint32_t val,
    241                  enum gen6_blt_mask value_mask,
    242                  enum gen6_blt_mask write_mask)
    243 {
    244    const int cpp = gen6_blt_translate_value_cpp(value_mask);
    245    const unsigned max_extent = 32767; /* INT16_MAX */
    246    const uint8_t rop = 0xf0; /* PATCOPY */
    247    struct ilo_builder *builder = &blitter->ilo->cp->builder;
    248    struct gen6_blt_xy_bo dst;
    249    uint32_t swctrl;
    250    int slice;
    251 
    252    /* no W-tiling nor separate stencil support */
    253    if (dst_tex->image.tiling == GEN8_TILING_W || dst_tex->separate_s8)
    254       return false;
    255 
    256    if (dst_tex->image.bo_stride > max_extent)
    257       return false;
    258 
    259    if (dst_box->width * cpp > gen6_blt_max_bytes_per_scanline)
    260       return false;
    261 
    262    dst.bo = dst_tex->vma.bo;
    263    dst.offset = dst_tex->vma.bo_offset;
    264    dst.pitch = dst_tex->image.bo_stride;
    265    dst.tiling = dst_tex->image.tiling;
    266 
    267    swctrl = ilo_blitter_blt_begin(blitter,
    268          GEN6_XY_COLOR_BLT__SIZE * dst_box->depth,
    269          dst_tex->vma.bo, dst_tex->image.tiling, NULL, GEN6_TILING_NONE);
    270 
    271    for (slice = 0; slice < dst_box->depth; slice++) {
    272       unsigned x, y;
    273 
    274       ilo_image_get_slice_pos(&dst_tex->image,
    275             dst_level, dst_box->z + slice, &x, &y);
    276 
    277       dst.x = x + dst_box->x;
    278       dst.y = y + dst_box->y;
    279 
    280       if (dst.x + dst_box->width > max_extent ||
    281           dst.y + dst_box->height > max_extent)
    282          break;
    283 
    284       gen6_XY_COLOR_BLT(builder, &dst, val,
    285             dst_box->width, dst_box->height, rop, value_mask, write_mask);
    286    }
    287 
    288    ilo_blitter_blt_end(blitter, swctrl);
    289 
    290    return (slice == dst_box->depth);
    291 }
    292 
    293 static bool
    294 tex_copy_region(struct ilo_blitter *blitter,
    295                 struct ilo_texture *dst_tex,
    296                 unsigned dst_level,
    297                 unsigned dst_x, unsigned dst_y, unsigned dst_z,
    298                 struct ilo_texture *src_tex,
    299                 unsigned src_level,
    300                 const struct pipe_box *src_box)
    301 {
    302    const struct util_format_description *desc =
    303       util_format_description(dst_tex->image_format);
    304    const unsigned max_extent = 32767; /* INT16_MAX */
    305    const uint8_t rop = 0xcc; /* SRCCOPY */
    306    struct ilo_builder *builder = &blitter->ilo->cp->builder;
    307    enum gen6_blt_mask mask;
    308    struct gen6_blt_xy_bo dst, src;
    309    uint32_t swctrl;
    310    int cpp, xscale, slice;
    311 
    312    /* no W-tiling nor separate stencil support */
    313    if (dst_tex->image.tiling == GEN8_TILING_W || dst_tex->separate_s8 ||
    314        src_tex->image.tiling == GEN8_TILING_W || src_tex->separate_s8)
    315       return false;
    316 
    317    if (dst_tex->image.bo_stride > max_extent ||
    318        src_tex->image.bo_stride > max_extent)
    319       return false;
    320 
    321    cpp = desc->block.bits / 8;
    322    xscale = 1;
    323 
    324    /* accommodate for larger cpp */
    325    if (cpp > 4) {
    326       if (cpp % 2 == 1)
    327          return false;
    328 
    329       cpp = (cpp % 4 == 0) ? 4 : 2;
    330       xscale = (desc->block.bits / 8) / cpp;
    331    }
    332 
    333    if (src_box->width * cpp * xscale > gen6_blt_max_bytes_per_scanline)
    334       return false;
    335 
    336    switch (cpp) {
    337    case 1:
    338       mask = GEN6_BLT_MASK_8;
    339       break;
    340    case 2:
    341       mask = GEN6_BLT_MASK_16;
    342       break;
    343    case 4:
    344       mask = GEN6_BLT_MASK_32;
    345       break;
    346    default:
    347       return false;
    348       break;
    349    }
    350 
    351    dst.bo = dst_tex->vma.bo;
    352    dst.offset = dst_tex->vma.bo_offset;
    353    dst.pitch = dst_tex->image.bo_stride;
    354    dst.tiling = dst_tex->image.tiling;
    355 
    356    src.bo = src_tex->vma.bo;
    357    src.offset = src_tex->vma.bo_offset;
    358    src.pitch = src_tex->image.bo_stride;
    359    src.tiling = src_tex->image.tiling;
    360 
    361    swctrl = ilo_blitter_blt_begin(blitter,
    362          GEN6_XY_SRC_COPY_BLT__SIZE * src_box->depth,
    363          dst.bo, dst.tiling, src.bo, src.tiling);
    364 
    365    for (slice = 0; slice < src_box->depth; slice++) {
    366       unsigned dx, dy, sx, sy, width, height;
    367 
    368       ilo_image_get_slice_pos(&dst_tex->image,
    369             dst_level, dst_z + slice, &dx, &dy);
    370       ilo_image_get_slice_pos(&src_tex->image,
    371             src_level, src_box->z + slice, &sx, &sy);
    372 
    373       dst.x = (dx + dst_x) * xscale;
    374       dst.y = dy + dst_y;
    375       src.x = (sx + src_box->x) * xscale;
    376       src.y = sy + src_box->y;
    377       width = src_box->width * xscale;
    378       height = src_box->height;
    379 
    380       /* in blocks */
    381       dst.x /= desc->block.width;
    382       dst.y /= desc->block.height;
    383       src.x /= desc->block.width;
    384       src.y /= desc->block.height;
    385       width /= desc->block.width;
    386       height /= desc->block.height;
    387 
    388       if (src.x + width > max_extent || src.y + height > max_extent ||
    389           dst.x + width > max_extent || dst.y + height > max_extent)
    390          break;
    391 
    392       gen6_XY_SRC_COPY_BLT(builder, &dst, &src,
    393             width, height, rop, mask, mask);
    394    }
    395 
    396    ilo_blitter_blt_end(blitter, swctrl);
    397 
    398    return (slice == src_box->depth);
    399 }
    400 
    401 bool
    402 ilo_blitter_blt_copy_resource(struct ilo_blitter *blitter,
    403                               struct pipe_resource *dst, unsigned dst_level,
    404                               unsigned dst_x, unsigned dst_y, unsigned dst_z,
    405                               struct pipe_resource *src, unsigned src_level,
    406                               const struct pipe_box *src_box)
    407 {
    408    bool success;
    409 
    410    ilo_blit_resolve_slices(blitter->ilo, src, src_level,
    411          src_box->z, src_box->depth, ILO_TEXTURE_BLT_READ);
    412    ilo_blit_resolve_slices(blitter->ilo, dst, dst_level,
    413          dst_z, src_box->depth, ILO_TEXTURE_BLT_WRITE);
    414 
    415    if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
    416       const unsigned dst_offset = dst_x;
    417       const unsigned src_offset = src_box->x;
    418       const unsigned size = src_box->width;
    419 
    420       assert(dst_level == 0 && dst_y == 0 && dst_z == 0);
    421       assert(src_level == 0 &&
    422              src_box->y == 0 &&
    423              src_box->z == 0 &&
    424              src_box->height == 1 &&
    425              src_box->depth == 1);
    426 
    427       success = buf_copy_region(blitter, ilo_buffer_resource(dst), dst_offset,
    428             ilo_buffer_resource(src), src_offset, size);
    429    }
    430    else if (dst->target != PIPE_BUFFER && src->target != PIPE_BUFFER) {
    431       success = tex_copy_region(blitter,
    432             ilo_texture(dst), dst_level, dst_x, dst_y, dst_z,
    433             ilo_texture(src), src_level, src_box);
    434    }
    435    else {
    436       success = false;
    437    }
    438 
    439    return success;
    440 }
    441 
    442 bool
    443 ilo_blitter_blt_clear_rt(struct ilo_blitter *blitter,
    444                          struct pipe_surface *rt,
    445                          const union pipe_color_union *color,
    446                          unsigned x, unsigned y,
    447                          unsigned width, unsigned height)
    448 {
    449    const int cpp = util_format_get_blocksize(rt->format);
    450    enum gen6_blt_mask mask;
    451    union util_color packed;
    452    bool success;
    453 
    454    if (ilo_skip_rendering(blitter->ilo))
    455       return true;
    456 
    457    switch (cpp) {
    458    case 1:
    459       mask = GEN6_BLT_MASK_8;
    460       break;
    461    case 2:
    462       mask = GEN6_BLT_MASK_16;
    463       break;
    464    case 4:
    465       mask = GEN6_BLT_MASK_32;
    466       break;
    467    default:
    468       return false;
    469       break;
    470    }
    471 
    472    if (util_format_is_pure_integer(rt->format) ||
    473        util_format_is_compressed(rt->format))
    474       return false;
    475 
    476    ilo_blit_resolve_surface(blitter->ilo, rt, ILO_TEXTURE_BLT_WRITE);
    477 
    478    util_pack_color(color->f, rt->format, &packed);
    479 
    480    if (rt->texture->target == PIPE_BUFFER) {
    481       unsigned offset, end, size;
    482 
    483       assert(y == 0 && height == 1);
    484 
    485       offset = (rt->u.buf.first_element + x) * cpp;
    486       end = (rt->u.buf.last_element + 1) * cpp;
    487 
    488       size = width * cpp;
    489       if (offset + size > end)
    490          size = end - offset;
    491 
    492       success = buf_clear_region(blitter, ilo_buffer_resource(rt->texture),
    493             offset, packed.ui[0], size, mask, mask);
    494    }
    495    else {
    496       struct pipe_box box;
    497 
    498       u_box_3d(x, y, rt->u.tex.first_layer, width, height,
    499             rt->u.tex.last_layer - rt->u.tex.first_layer + 1, &box);
    500 
    501       success = tex_clear_region(blitter, ilo_texture(rt->texture),
    502             rt->u.tex.level, &box, packed.ui[0], mask, mask);
    503    }
    504 
    505    return success;
    506 }
    507 
    508 bool
    509 ilo_blitter_blt_clear_zs(struct ilo_blitter *blitter,
    510                          struct pipe_surface *zs,
    511                          unsigned clear_flags,
    512                          double depth, unsigned stencil,
    513                          unsigned x, unsigned y,
    514                          unsigned width, unsigned height)
    515 {
    516    enum gen6_blt_mask value_mask, write_mask;
    517    struct pipe_box box;
    518    uint32_t val;
    519 
    520    if (ilo_skip_rendering(blitter->ilo))
    521       return true;
    522 
    523    switch (zs->format) {
    524    case PIPE_FORMAT_Z16_UNORM:
    525       if (!(clear_flags & PIPE_CLEAR_DEPTH))
    526          return true;
    527 
    528       value_mask = GEN6_BLT_MASK_16;
    529       write_mask = GEN6_BLT_MASK_16;
    530       break;
    531    case PIPE_FORMAT_Z32_FLOAT:
    532       if (!(clear_flags & PIPE_CLEAR_DEPTH))
    533          return true;
    534 
    535       value_mask = GEN6_BLT_MASK_32;
    536       write_mask = GEN6_BLT_MASK_32;
    537       break;
    538    case PIPE_FORMAT_Z24X8_UNORM:
    539       if (!(clear_flags & PIPE_CLEAR_DEPTH))
    540          return true;
    541 
    542       value_mask = GEN6_BLT_MASK_32;
    543       write_mask = GEN6_BLT_MASK_32_LO;
    544       break;
    545    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
    546       if (!(clear_flags & PIPE_CLEAR_DEPTHSTENCIL))
    547          return true;
    548 
    549       value_mask = GEN6_BLT_MASK_32;
    550 
    551       if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) == PIPE_CLEAR_DEPTHSTENCIL)
    552          write_mask = GEN6_BLT_MASK_32;
    553       else if (clear_flags & PIPE_CLEAR_DEPTH)
    554          write_mask = GEN6_BLT_MASK_32_LO;
    555       else
    556          write_mask = GEN6_BLT_MASK_32_HI;
    557       break;
    558    default:
    559       return false;
    560       break;
    561    }
    562 
    563    ilo_blit_resolve_surface(blitter->ilo, zs, ILO_TEXTURE_BLT_WRITE);
    564 
    565    val = util_pack_z_stencil(zs->format, depth, stencil);
    566 
    567    u_box_3d(x, y, zs->u.tex.first_layer, width, height,
    568          zs->u.tex.last_layer - zs->u.tex.first_layer + 1, &box);
    569 
    570    assert(zs->texture->target != PIPE_BUFFER);
    571 
    572    return tex_clear_region(blitter, ilo_texture(zs->texture),
    573          zs->u.tex.level, &box, val, value_mask, write_mask);
    574 }
    575