/* 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; } }
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; } }
/** * 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); } }
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; }