/* Copy a block of pixels from one surface to another. */
static void r300_resource_copy_region(struct pipe_context *pipe,
                                      struct pipe_resource *dst,
                                      unsigned dst_level,
                                      unsigned dstx, unsigned dsty, unsigned dstz,
                                      struct pipe_resource *src,
                                      unsigned src_level,
                                      const struct pipe_box *src_box)
{
    enum pipe_format old_format = dst->format;
    enum pipe_format new_format = old_format;
    boolean is_depth;
    if (!pipe->screen->is_format_supported(pipe->screen,
                                           old_format, src->target,
                                           src->nr_samples,
                                           PIPE_BIND_RENDER_TARGET |
                                           PIPE_BIND_SAMPLER_VIEW, 0) &&
        util_format_is_plain(old_format)) {
        switch (util_format_get_blocksize(old_format)) {
            case 1:
                new_format = PIPE_FORMAT_I8_UNORM;
                break;
            case 2:
                new_format = PIPE_FORMAT_B4G4R4A4_UNORM;
                break;
            case 4:
                new_format = PIPE_FORMAT_B8G8R8A8_UNORM;
                break;
            case 8:
                new_format = PIPE_FORMAT_R16G16B16A16_UNORM;
                break;
            default:
                debug_printf("r300: surface_copy: Unhandled format: %s. Falling back to software.\n"
                             "r300: surface_copy: Software fallback doesn't work for tiled textures.\n",
                             util_format_short_name(old_format));
        }
    }

    is_depth = util_format_get_component_bits(src->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0;
    if (is_depth) {
        r300_flush_depth_stencil(pipe, src, src_level, src_box->z);
    }
    if (old_format != new_format) {
        r300_texture_reinterpret_format(pipe->screen,
                                        dst, new_format);
        r300_texture_reinterpret_format(pipe->screen,
                                        src, new_format);
    }

    r300_hw_copy_region(pipe, dst, dst_level, dstx, dsty, dstz,
                        src, src_level, src_box);

    if (old_format != new_format) {
        r300_texture_reinterpret_format(pipe->screen,
                                        dst, old_format);
        r300_texture_reinterpret_format(pipe->screen,
                                        src, old_format);
    }
}
/**
 * Return the stride, in bytes, of the texture image of the given texture
 * at the given level.
 */
static unsigned r300_texture_get_stride(struct r300_screen *screen,
                                        struct r300_texture_desc *desc,
                                        unsigned level)
{
    unsigned tile_width, width, stride;

    if (desc->stride_in_bytes_override)
        return desc->stride_in_bytes_override;

    /* Check the level. */
    if (level > desc->b.b.last_level) {
        SCREEN_DBG(screen, DBG_TEX, "%s: level (%u) > last_level (%u)\n",
                   __FUNCTION__, level, desc->b.b.last_level);
        return 0;
    }

    width = u_minify(desc->b.b.width0, level);

    if (util_format_is_plain(desc->b.b.format)) {
        tile_width = r300_get_pixel_alignment(desc->b.b.format,
                                              desc->b.b.nr_samples,
                                              desc->microtile,
                                              desc->macrotile[level],
                                              DIM_WIDTH);
        width = align(width, tile_width);

        stride = util_format_get_stride(desc->b.b.format, width);

        /* Some IGPs need a minimum stride of 64 bytes, hmm... */
        if (!desc->macrotile[level] &&
            (screen->caps.family == CHIP_FAMILY_RS600 ||
             screen->caps.family == CHIP_FAMILY_RS690 ||
             screen->caps.family == CHIP_FAMILY_RS740)) {
            unsigned min_stride;

            if (desc->microtile) {
                unsigned tile_height =
                        r300_get_pixel_alignment(desc->b.b.format,
                                                 desc->b.b.nr_samples,
                                                 desc->microtile,
                                                 desc->macrotile[level],
                                                 DIM_HEIGHT);

                min_stride = 64 / tile_height;
            } else {
                min_stride = 64;
            }

            return stride < min_stride ? min_stride : stride;
        }

        /* The alignment to 32 bytes is sort of implied by the layout... */
        return stride;
    } else {
        return align(util_format_get_stride(desc->b.b.format, width), 32);
    }
}
static void r300_setup_tiling(struct r300_screen *screen,
                              struct r300_resource *tex)
{
    enum pipe_format format = tex->b.b.format;
    boolean rv350_mode = screen->caps.family >= CHIP_R350;
    boolean is_zb = util_format_is_depth_or_stencil(format);
    boolean dbg_no_tiling = SCREEN_DBG_ON(screen, DBG_NO_TILING);
    boolean force_microtiling =
        (tex->b.b.flags & R300_RESOURCE_FORCE_MICROTILING) != 0;

    if (tex->b.b.nr_samples > 1) {
        tex->tex.microtile = RADEON_LAYOUT_TILED;
        tex->tex.macrotile[0] = RADEON_LAYOUT_TILED;
        return;
    }

    tex->tex.microtile = RADEON_LAYOUT_LINEAR;
    tex->tex.macrotile[0] = RADEON_LAYOUT_LINEAR;

    if (tex->b.b.usage == PIPE_USAGE_STAGING) {
       return;
    }

    if (!util_format_is_plain(format)) {
        return;
    }

    /* If height == 1, disable microtiling except for zbuffer. */
    if (!force_microtiling && !is_zb &&
        (tex->b.b.height0 == 1 || dbg_no_tiling)) {
        return;
    }

    /* Set microtiling. */
    switch (util_format_get_blocksize(format)) {
        case 1:
        case 4:
        case 8:
            tex->tex.microtile = RADEON_LAYOUT_TILED;
            break;

        case 2:
            tex->tex.microtile = RADEON_LAYOUT_SQUARETILED;
            break;
    }

    if (dbg_no_tiling) {
        return;
    }

    /* Set macrotiling. */
    if (r300_texture_macro_switch(tex, 0, rv350_mode, DIM_WIDTH) &&
        r300_texture_macro_switch(tex, 0, rv350_mode, DIM_HEIGHT)) {
        tex->tex.macrotile[0] = RADEON_LAYOUT_TILED;
    }
}
Exemple #4
0
static unsigned r300_texture_get_nblocksy(struct r300_resource *tex,
                                          unsigned level,
                                          boolean *out_aligned_for_cbzb)
{
    unsigned height, tile_height;

    height = u_minify(tex->tex.height0, level);

    /* Mipmapped and 3D textures must have their height aligned to POT. */
    if ((tex->b.b.b.target != PIPE_TEXTURE_1D &&
         tex->b.b.b.target != PIPE_TEXTURE_2D &&
         tex->b.b.b.target != PIPE_TEXTURE_RECT) ||
        tex->b.b.b.last_level != 0) {
        height = util_next_power_of_two(height);
    }

    if (util_format_is_plain(tex->b.b.b.format)) {
        tile_height = r300_get_pixel_alignment(tex->b.b.b.format,
                                               tex->b.b.b.nr_samples,
                                               tex->tex.microtile,
                                               tex->tex.macrotile[level],
                                               DIM_HEIGHT, 0);
        height = align(height, tile_height);

        /* See if the CBZB clear can be used on the buffer,
         * taking the texture size into account. */
        if (out_aligned_for_cbzb) {
            if (tex->tex.macrotile[level]) {
                /* When clearing, the layer (width*height) is horizontally split
                 * into two, and the upper and lower halves are cleared by the CB
                 * and ZB units, respectively. Therefore, the number of macrotiles
                 * in the Y direction must be even. */

                /* Align the height so that there is an even number of macrotiles.
                 * Do so for 3 or more macrotiles in the Y direction. */
                if (level == 0 && tex->b.b.b.last_level == 0 &&
                    (tex->b.b.b.target == PIPE_TEXTURE_1D ||
                     tex->b.b.b.target == PIPE_TEXTURE_2D ||
                     tex->b.b.b.target == PIPE_TEXTURE_RECT) &&
                    height >= tile_height * 3) {
                    height = align(height, tile_height * 2);
                }

                *out_aligned_for_cbzb = height % (tile_height * 2) == 0;
            } else {
                *out_aligned_for_cbzb = FALSE;
            }
        }
    }

    return util_format_get_nblocksy(tex->b.b.b.format, height);
}
static void r300_setup_tiling(struct r300_screen *screen,
                              struct r300_texture_desc *desc)
{
    struct r300_winsys_screen *rws = screen->rws;
    enum pipe_format format = desc->b.b.format;
    boolean rv350_mode = screen->caps.family >= CHIP_FAMILY_R350;
    boolean is_zb = util_format_is_depth_or_stencil(format);
    boolean dbg_no_tiling = SCREEN_DBG_ON(screen, DBG_NO_TILING);

    if (!util_format_is_plain(format)) {
        return;
    }

    /* If height == 1, disable microtiling except for zbuffer. */
    if (!is_zb && (desc->b.b.height0 == 1 || dbg_no_tiling)) {
        return;
    }

    /* Set microtiling. */
    switch (util_format_get_blocksize(format)) {
        case 1:
        case 4:
            desc->microtile = R300_BUFFER_TILED;
            break;

        case 2:
        case 8:
            if (rws->get_value(rws, R300_VID_SQUARE_TILING_SUPPORT)) {
                desc->microtile = R300_BUFFER_SQUARETILED;
            }
            break;
    }

    if (dbg_no_tiling) {
        return;
    }

    /* Set macrotiling. */
    if (r300_texture_macro_switch(desc, 0, rv350_mode, DIM_WIDTH) &&
        r300_texture_macro_switch(desc, 0, rv350_mode, DIM_HEIGHT)) {
        desc->macrotile[0] = R300_BUFFER_TILED;
    }
}
Exemple #6
0
/**
 * Return the stride, in bytes, of the texture image of the given texture
 * at the given level.
 */
static unsigned r300_texture_get_stride(struct r300_screen *screen,
                                        struct r300_resource *tex,
                                        unsigned level)
{
    unsigned tile_width, width, stride;
    boolean is_rs690 = (screen->caps.family == CHIP_FAMILY_RS600 ||
                        screen->caps.family == CHIP_FAMILY_RS690 ||
                        screen->caps.family == CHIP_FAMILY_RS740);

    if (tex->tex.stride_in_bytes_override)
        return tex->tex.stride_in_bytes_override;

    /* Check the level. */
    if (level > tex->b.b.b.last_level) {
        SCREEN_DBG(screen, DBG_TEX, "%s: level (%u) > last_level (%u)\n",
                   __FUNCTION__, level, tex->b.b.b.last_level);
        return 0;
    }

    width = u_minify(tex->tex.width0, level);

    if (util_format_is_plain(tex->b.b.b.format)) {
        tile_width = r300_get_pixel_alignment(tex->b.b.b.format,
                                              tex->b.b.b.nr_samples,
                                              tex->tex.microtile,
                                              tex->tex.macrotile[level],
                                              DIM_WIDTH, is_rs690);
        width = align(width, tile_width);

        stride = util_format_get_stride(tex->b.b.b.format, width);
        /* The alignment to 32 bytes is sort of implied by the layout... */
        return stride;
    } else {
        return align(util_format_get_stride(tex->b.b.b.format, width), is_rs690 ? 64 : 32);
    }
}
Exemple #7
0
void *
nvc0_miptree_transfer_map(struct pipe_context *pctx,
                          struct pipe_resource *res,
                          unsigned level,
                          unsigned usage,
                          const struct pipe_box *box,
                          struct pipe_transfer **ptransfer)
{
   struct nvc0_context *nvc0 = nvc0_context(pctx);
   struct nouveau_device *dev = nvc0->screen->base.device;
   struct nv50_miptree *mt = nv50_miptree(res);
   struct nvc0_transfer *tx;
   uint32_t size;
   int ret;
   unsigned flags = 0;

   if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
      return NULL;

   tx = CALLOC_STRUCT(nvc0_transfer);
   if (!tx)
      return NULL;

   pipe_resource_reference(&tx->base.resource, res);

   tx->base.level = level;
   tx->base.usage = usage;
   tx->base.box = *box;

   if (util_format_is_plain(res->format)) {
      tx->nblocksx = box->width << mt->ms_x;
      tx->nblocksy = box->height << mt->ms_y;
   } else {
      tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
      tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
   }
   tx->nlayers = box->depth;

   tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format);
   tx->base.layer_stride = tx->nblocksy * tx->base.stride;

   nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z);

   size = tx->base.layer_stride;

   ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
                        size * tx->nlayers, NULL, &tx->rect[1].bo);
   if (ret) {
      pipe_resource_reference(&tx->base.resource, NULL);
      FREE(tx);
      return NULL;
   }

   tx->rect[1].cpp = tx->rect[0].cpp;
   tx->rect[1].width = tx->nblocksx;
   tx->rect[1].height = tx->nblocksy;
   tx->rect[1].depth = 1;
   tx->rect[1].pitch = tx->base.stride;
   tx->rect[1].domain = NOUVEAU_BO_GART;

   if (usage & PIPE_TRANSFER_READ) {
      unsigned base = tx->rect[0].base;
      unsigned z = tx->rect[0].z;
      unsigned i;
      for (i = 0; i < tx->nlayers; ++i) {
         nvc0->m2mf_copy_rect(nvc0, &tx->rect[1], &tx->rect[0],
                              tx->nblocksx, tx->nblocksy);
         if (mt->layout_3d)
            tx->rect[0].z++;
         else
            tx->rect[0].base += mt->layer_stride;
         tx->rect[1].base += size;
      }
      tx->rect[0].z = z;
      tx->rect[0].base = base;
      tx->rect[1].base = 0;
   }

   if (tx->rect[1].bo->map) {
      *ptransfer = &tx->base;
      return tx->rect[1].bo->map;
   }

   if (usage & PIPE_TRANSFER_READ)
      flags = NOUVEAU_BO_RD;
   if (usage & PIPE_TRANSFER_WRITE)
      flags |= NOUVEAU_BO_WR;

   ret = nouveau_bo_map(tx->rect[1].bo, flags, nvc0->screen->base.client);
   if (ret) {
      pipe_resource_reference(&tx->base.resource, NULL);
      nouveau_bo_ref(NULL, &tx->rect[1].bo);
      FREE(tx);
      return NULL;
   }

   *ptransfer = &tx->base;
   return tx->rect[1].bo->map;
}