mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-04-23 22:30:40 +02:00
pan/layout: Split the logic per modifier
Prepare for mod handlers by splitting the layout logic per modifier. Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> Reviewed-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com> Reviewed-by: Eric R. Smith <eric.smith@collabora.com> Tested-by: Eric R. Smith <eric.smith@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35555>
This commit is contained in:
parent
18f87b6ada
commit
e6f8cab698
1 changed files with 449 additions and 278 deletions
|
|
@ -138,76 +138,84 @@ init_slice_crc_info(unsigned arch, struct pan_image_slice_layout *slice,
|
|||
slice->crc.size_B = slice->crc.stride_B * tile_count_y;
|
||||
}
|
||||
|
||||
unsigned
|
||||
pan_image_get_wsi_row_pitch(const struct pan_image_props *props,
|
||||
unsigned plane_idx,
|
||||
const struct pan_image_layout *layout,
|
||||
unsigned level)
|
||||
static struct pan_image_extent
|
||||
get_mip_level_extent(const struct pan_image_props *props, unsigned plane_idx,
|
||||
unsigned mip_level)
|
||||
{
|
||||
const unsigned row_stride_B = layout->slices[level].row_stride_B;
|
||||
const struct pan_image_block_size block_size_el =
|
||||
pan_image_renderblock_size_el(props->modifier, props->format, plane_idx);
|
||||
return (struct pan_image_extent){
|
||||
.width = u_minify(util_format_get_plane_width(props->format, plane_idx,
|
||||
props->extent_px.width),
|
||||
mip_level),
|
||||
.height = u_minify(util_format_get_plane_height(props->format, plane_idx,
|
||||
props->extent_px.height),
|
||||
mip_level),
|
||||
.depth = u_minify(props->extent_px.depth, mip_level),
|
||||
};
|
||||
}
|
||||
|
||||
if (drm_is_afbc(props->modifier)) {
|
||||
const struct pan_image_block_size afbc_tile_extent_el =
|
||||
pan_image_block_size_el(props->modifier, props->format, plane_idx);
|
||||
const unsigned afbc_tile_payload_size_B =
|
||||
afbc_tile_extent_el.width * afbc_tile_extent_el.height *
|
||||
pan_format_get_plane_blocksize(props->format, plane_idx);
|
||||
const unsigned afbc_tile_row_payload_size_B =
|
||||
pan_afbc_stride_blocks(props->modifier, row_stride_B) *
|
||||
afbc_tile_payload_size_B;
|
||||
static unsigned
|
||||
get_afbc_wsi_row_pitch(const struct pan_image_props *props, unsigned plane_idx,
|
||||
const struct pan_image_slice_layout *slayout)
|
||||
{
|
||||
const unsigned header_row_stride_B = slayout->row_stride_B;
|
||||
const struct pan_image_block_size tile_extent_el =
|
||||
pan_afbc_superblock_size_el(props->format, props->modifier);
|
||||
const unsigned tile_payload_size_B =
|
||||
tile_extent_el.width * tile_extent_el.height *
|
||||
pan_format_get_plane_blocksize(props->format, plane_idx);
|
||||
const unsigned tile_row_payload_size_B =
|
||||
pan_afbc_stride_blocks(props->modifier, header_row_stride_B) *
|
||||
tile_payload_size_B;
|
||||
|
||||
return afbc_tile_row_payload_size_B /
|
||||
pan_afbc_superblock_height(props->modifier);
|
||||
}
|
||||
|
||||
if (drm_is_afrc(props->modifier)) {
|
||||
const struct pan_image_block_size tile_size_px =
|
||||
pan_afrc_tile_size(props->format, props->modifier);
|
||||
|
||||
return row_stride_B / tile_size_px.height;
|
||||
}
|
||||
|
||||
return row_stride_B / block_size_el.height;
|
||||
return tile_row_payload_size_B / pan_afbc_superblock_height(props->modifier);
|
||||
}
|
||||
|
||||
static bool
|
||||
wsi_row_pitch_to_row_stride(
|
||||
init_afbc_slice_layout(
|
||||
unsigned arch, const struct pan_image_props *props, unsigned plane_idx,
|
||||
struct pan_image_extent mip_extent_px,
|
||||
const struct pan_image_layout_constraints *layout_constraints,
|
||||
unsigned *row_stride_B)
|
||||
struct pan_image_slice_layout *slayout)
|
||||
{
|
||||
unsigned row_align_mask, offset_align_mask, width_px;
|
||||
unsigned wsi_row_pitch_B = layout_constraints->wsi_row_pitch_B;
|
||||
enum pipe_format format = props->format;
|
||||
uint64_t modifier = props->modifier;
|
||||
/* Use explicit layout only when wsi_row_pitch_B is non-zero */
|
||||
const bool use_explicit_layout =
|
||||
layout_constraints && layout_constraints->wsi_row_pitch_B;
|
||||
struct pan_image_block_size afbc_tile_extent_px =
|
||||
pan_afbc_superblock_size(props->modifier);
|
||||
unsigned offset_align_mask =
|
||||
pan_afbc_header_align(arch, props->modifier) - 1;
|
||||
unsigned row_align_mask =
|
||||
pan_afbc_header_row_stride_align(arch, props->format, props->modifier) -
|
||||
1;
|
||||
struct pan_image_block_size afbc_tile_extent_el =
|
||||
pan_afbc_superblock_size_el(props->format, props->modifier);
|
||||
unsigned afbc_tile_payload_size_B =
|
||||
afbc_tile_extent_el.width * afbc_tile_extent_el.height *
|
||||
pan_format_get_plane_blocksize(props->format, plane_idx);
|
||||
|
||||
if (drm_is_afbc(modifier)) {
|
||||
struct pan_image_block_size afbc_tile_extent_px =
|
||||
pan_afbc_superblock_size(modifier);
|
||||
/* YUV packed formats can have a block extent bigger than one pixel,
|
||||
* but the block extent must be a multiple of the tile extent. */
|
||||
assert(
|
||||
!(afbc_tile_extent_px.width % util_format_get_blockwidth(format)) &&
|
||||
!(afbc_tile_extent_px.height % util_format_get_blockheight(format)));
|
||||
unsigned pixels_per_blk = util_format_get_blockwidth(format) *
|
||||
util_format_get_blockheight(format);
|
||||
unsigned pixels_per_tile = afbc_tile_extent_px.width *
|
||||
afbc_tile_extent_px.height;
|
||||
unsigned blks_per_tile = pixels_per_tile / pixels_per_blk;
|
||||
unsigned afbc_tile_payload_size_B =
|
||||
blks_per_tile * pan_format_get_plane_blocksize(format, plane_idx);
|
||||
struct pan_image_block_size align_px =
|
||||
pan_afbc_renderblock_size(props->modifier);
|
||||
|
||||
/* If superblock tiling is used, align on a superblock tile. */
|
||||
if (props->modifier & AFBC_FORMAT_MOD_TILED) {
|
||||
align_px.width =
|
||||
ALIGN_POT(align_px.width, afbc_tile_extent_px.width *
|
||||
pan_afbc_tile_size(props->modifier));
|
||||
align_px.height =
|
||||
ALIGN_POT(align_px.height, afbc_tile_extent_px.height *
|
||||
pan_afbc_tile_size(props->modifier));
|
||||
}
|
||||
|
||||
struct pan_image_extent aligned_extent_px = {
|
||||
.width = ALIGN_POT(mip_extent_px.width, align_px.width),
|
||||
.height = ALIGN_POT(mip_extent_px.height, align_px.height),
|
||||
.depth = mip_extent_px.depth,
|
||||
};
|
||||
|
||||
if (use_explicit_layout) {
|
||||
unsigned afbc_tile_payload_row_stride_B =
|
||||
wsi_row_pitch_B * afbc_tile_extent_px.height;
|
||||
|
||||
offset_align_mask = pan_afbc_header_align(arch, modifier) - 1;
|
||||
row_align_mask =
|
||||
pan_afbc_header_row_stride_align(arch, format, modifier) - 1;
|
||||
width_px =
|
||||
(afbc_tile_payload_row_stride_B / afbc_tile_payload_size_B) *
|
||||
afbc_tile_extent_px.width;
|
||||
*row_stride_B = pan_afbc_row_stride(modifier, width_px);
|
||||
layout_constraints->wsi_row_pitch_B *
|
||||
pan_afbc_superblock_height(props->modifier);
|
||||
|
||||
/* For quite some time, we've been accepting WSI row pitch that
|
||||
* didn't match exactly the image size and have been assuming tightly
|
||||
|
|
@ -220,77 +228,363 @@ wsi_row_pitch_to_row_stride(
|
|||
mesa_loge("WSI pitch is not aligned on an AFBC tile");
|
||||
return false;
|
||||
}
|
||||
} else if (drm_is_afrc(modifier)) {
|
||||
struct pan_image_block_size tile_size_px =
|
||||
pan_afrc_tile_size(format, modifier);
|
||||
unsigned afrc_blk_size_B =
|
||||
pan_afrc_block_size_from_modifier(props->modifier) *
|
||||
AFRC_CLUMPS_PER_TILE;
|
||||
|
||||
row_align_mask = pan_afrc_buffer_alignment_from_modifier(modifier) - 1;
|
||||
offset_align_mask = row_align_mask;
|
||||
*row_stride_B = wsi_row_pitch_B * tile_size_px.height;
|
||||
width_px = (*row_stride_B / afrc_blk_size_B) * tile_size_px.width;
|
||||
} else {
|
||||
struct pan_image_block_size block_size_el =
|
||||
pan_image_renderblock_size_el(modifier, format, plane_idx);
|
||||
unsigned width_from_wsi_row_stride =
|
||||
(afbc_tile_payload_row_stride_B / afbc_tile_payload_size_B) *
|
||||
pan_afbc_superblock_width(props->modifier);
|
||||
|
||||
if (!util_format_is_compressed(format)) {
|
||||
/* Block-based YUV needs special care, because the U-tile extent
|
||||
* is in pixels, not blocks in that case. */
|
||||
if (block_size_el.width * block_size_el.height > 1) {
|
||||
assert(block_size_el.width % util_format_get_blockwidth(format) ==
|
||||
0);
|
||||
block_size_el.width /= util_format_get_blockwidth(format);
|
||||
assert(block_size_el.height % util_format_get_blockheight(format) ==
|
||||
0);
|
||||
block_size_el.height /= util_format_get_blockheight(format);
|
||||
} else {
|
||||
block_size_el.width = util_format_get_blockwidth(format);
|
||||
assert(util_format_get_blockheight(format) == 1);
|
||||
}
|
||||
if (width_from_wsi_row_stride < mip_extent_px.width) {
|
||||
mesa_loge("WSI pitch too small");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned tile_size_B = block_size_el.width * block_size_el.height *
|
||||
pan_format_get_plane_blocksize(format, plane_idx);
|
||||
slayout->row_stride_B =
|
||||
pan_afbc_row_stride(props->modifier, width_from_wsi_row_stride);
|
||||
if (slayout->row_stride_B & row_align_mask) {
|
||||
mesa_loge("WSI pitch not properly aligned");
|
||||
return false;
|
||||
}
|
||||
|
||||
row_align_mask =
|
||||
pan_linear_or_tiled_row_align_req(arch, format, plane_idx) - 1;
|
||||
offset_align_mask = row_align_mask;
|
||||
*row_stride_B = wsi_row_pitch_B * block_size_el.height;
|
||||
width_px = (*row_stride_B / tile_size_B) *
|
||||
(block_size_el.width * util_format_get_blockwidth(format));
|
||||
slayout->offset_B = layout_constraints->offset_B;
|
||||
if (slayout->offset_B & offset_align_mask) {
|
||||
mesa_loge("WSI offset not properly aligned");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If this is not a strict import, ignore the WSI row pitch and use
|
||||
* the resource width to get the size. */
|
||||
if (!layout_constraints->strict) {
|
||||
slayout->row_stride_B = ALIGN_POT(
|
||||
pan_afbc_row_stride(props->modifier, aligned_extent_px.width),
|
||||
row_align_mask + 1);
|
||||
}
|
||||
} else {
|
||||
slayout->offset_B =
|
||||
ALIGN_POT(layout_constraints ? layout_constraints->offset_B : 0,
|
||||
offset_align_mask + 1);
|
||||
slayout->row_stride_B = ALIGN_POT(
|
||||
pan_afbc_row_stride(props->modifier, aligned_extent_px.width),
|
||||
row_align_mask + 1);
|
||||
}
|
||||
|
||||
if (*row_stride_B & row_align_mask) {
|
||||
mesa_loge("WSI pitch not properly aligned");
|
||||
return false;
|
||||
}
|
||||
const unsigned row_stride_sb =
|
||||
pan_afbc_stride_blocks(props->modifier, slayout->row_stride_B);
|
||||
const unsigned surface_stride_sb =
|
||||
row_stride_sb * (aligned_extent_px.height / afbc_tile_extent_px.height);
|
||||
|
||||
if (layout_constraints->offset_B & offset_align_mask) {
|
||||
mesa_loge("WSI offset not properly aligned");
|
||||
return false;
|
||||
}
|
||||
slayout->afbc.surface_stride_B =
|
||||
surface_stride_sb * AFBC_HEADER_BYTES_PER_TILE;
|
||||
slayout->afbc.surface_stride_B =
|
||||
ALIGN_POT(slayout->afbc.surface_stride_B, offset_align_mask + 1);
|
||||
|
||||
unsigned min_width_px =
|
||||
util_format_get_plane_width(format, plane_idx, props->extent_px.width);
|
||||
if (width_px < min_width_px) {
|
||||
mesa_loge("WSI pitch too small");
|
||||
return false;
|
||||
slayout->afbc.header_size_B =
|
||||
ALIGN_POT(slayout->afbc.surface_stride_B * aligned_extent_px.depth,
|
||||
pan_afbc_body_align(arch, props->modifier));
|
||||
|
||||
slayout->surface_stride_B = surface_stride_sb * afbc_tile_payload_size_B;
|
||||
slayout->afbc.body_size_B =
|
||||
surface_stride_sb * afbc_tile_payload_size_B * aligned_extent_px.depth;
|
||||
slayout->size_B =
|
||||
(uint64_t)slayout->afbc.header_size_B + slayout->afbc.body_size_B;
|
||||
|
||||
if (props->dim != MALI_TEXTURE_DIMENSION_3D) {
|
||||
/* FIXME: it doesn't make sense to have the header size counted in the
|
||||
* surface stride. Will be fixed once we revisit the
|
||||
* pan_image_slice_layout fields to make them mod-specific. */
|
||||
slayout->surface_stride_B += slayout->afbc.header_size_B;
|
||||
slayout->afbc.surface_stride_B = slayout->surface_stride_B;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
pan_image_layout_init(
|
||||
static unsigned
|
||||
get_afrc_wsi_row_pitch(const struct pan_image_props *props, unsigned plane_idx,
|
||||
const struct pan_image_slice_layout *slayout)
|
||||
{
|
||||
const struct pan_image_block_size tile_extent_px =
|
||||
pan_afrc_tile_size(props->format, props->modifier);
|
||||
|
||||
return slayout->row_stride_B / tile_extent_px.height;
|
||||
}
|
||||
|
||||
static bool
|
||||
init_afrc_slice_layout(
|
||||
unsigned arch, const struct pan_image_props *props, unsigned plane_idx,
|
||||
struct pan_image_extent mip_extent_px,
|
||||
const struct pan_image_layout_constraints *layout_constraints,
|
||||
struct pan_image_layout *layout)
|
||||
struct pan_image_slice_layout *slayout)
|
||||
{
|
||||
/* Use explicit layout only when wsi_row_pitch_B is non-zero */
|
||||
const bool use_explicit_layout =
|
||||
layout_constraints && layout_constraints->wsi_row_pitch_B;
|
||||
const unsigned align_mask =
|
||||
pan_afrc_buffer_alignment_from_modifier(props->modifier) - 1;
|
||||
struct pan_image_block_size tile_extent_px =
|
||||
pan_afrc_tile_size(props->format, props->modifier);
|
||||
struct pan_image_extent aligned_extent_px = {
|
||||
.width = ALIGN_POT(mip_extent_px.width, tile_extent_px.width),
|
||||
.height = ALIGN_POT(mip_extent_px.height, tile_extent_px.height),
|
||||
.depth = mip_extent_px.depth,
|
||||
};
|
||||
|
||||
if (use_explicit_layout) {
|
||||
slayout->row_stride_B =
|
||||
layout_constraints->wsi_row_pitch_B * tile_extent_px.height;
|
||||
if (slayout->row_stride_B & align_mask) {
|
||||
mesa_loge("WSI pitch not properly aligned");
|
||||
return false;
|
||||
}
|
||||
|
||||
slayout->offset_B = layout_constraints->offset_B;
|
||||
if (slayout->offset_B & align_mask) {
|
||||
mesa_loge("WSI offset not properly aligned");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned afrc_blk_size_B =
|
||||
pan_afrc_block_size_from_modifier(props->modifier) *
|
||||
AFRC_CLUMPS_PER_TILE;
|
||||
unsigned width_from_wsi_row_stride =
|
||||
(slayout->row_stride_B / afrc_blk_size_B) * tile_extent_px.width;
|
||||
|
||||
if (width_from_wsi_row_stride < mip_extent_px.width) {
|
||||
mesa_loge("WSI pitch too small");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If this is not a strict import, ignore the WSI row pitch and use
|
||||
* the resource width to get the size. */
|
||||
if (!layout_constraints->strict) {
|
||||
slayout->row_stride_B = pan_afrc_row_stride(
|
||||
props->format, props->modifier, mip_extent_px.width);
|
||||
}
|
||||
} else {
|
||||
/* Align levels to cache-line as a performance improvement for
|
||||
* linear/tiled and as a requirement for AFBC */
|
||||
slayout->offset_B = ALIGN_POT(
|
||||
layout_constraints ? layout_constraints->offset_B : 0, align_mask + 1);
|
||||
slayout->row_stride_B =
|
||||
ALIGN_POT(pan_afrc_row_stride(props->format, props->modifier,
|
||||
mip_extent_px.width),
|
||||
align_mask + 1);
|
||||
}
|
||||
|
||||
slayout->surface_stride_B =
|
||||
slayout->row_stride_B *
|
||||
DIV_ROUND_UP(aligned_extent_px.height, aligned_extent_px.height);
|
||||
slayout->size_B = (uint64_t)slayout->surface_stride_B *
|
||||
aligned_extent_px.depth * props->nr_samples;
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
get_u_tiled_wsi_row_pitch(const struct pan_image_props *props,
|
||||
unsigned plane_idx,
|
||||
const struct pan_image_slice_layout *slayout)
|
||||
{
|
||||
return slayout->row_stride_B /
|
||||
pan_u_interleaved_tile_size_el(props->format).height;
|
||||
}
|
||||
|
||||
static bool
|
||||
init_u_tiled_slice_layout(
|
||||
unsigned arch, const struct pan_image_props *props, unsigned plane_idx,
|
||||
struct pan_image_extent mip_extent_px,
|
||||
const struct pan_image_layout_constraints *layout_constraints,
|
||||
struct pan_image_slice_layout *slayout)
|
||||
{
|
||||
/* Use explicit layout only when wsi_row_pitch_B is non-zero */
|
||||
const bool use_explicit_layout =
|
||||
layout_constraints && layout_constraints->wsi_row_pitch_B;
|
||||
unsigned align_mask =
|
||||
pan_linear_or_tiled_row_align_req(arch, props->format, plane_idx) - 1;
|
||||
struct pan_image_block_size tile_extent_el =
|
||||
pan_u_interleaved_tile_size_el(props->format);
|
||||
struct pan_image_extent mip_extent_el;
|
||||
unsigned tile_size_B;
|
||||
|
||||
if (util_format_is_compressed(props->format)) {
|
||||
assert(util_format_get_num_planes(props->format) == 1);
|
||||
mip_extent_el.width = DIV_ROUND_UP(
|
||||
mip_extent_px.width, util_format_get_blockwidth(props->format));
|
||||
mip_extent_el.height = DIV_ROUND_UP(
|
||||
mip_extent_px.height, util_format_get_blockheight(props->format));
|
||||
mip_extent_el.depth = DIV_ROUND_UP(
|
||||
mip_extent_px.depth, util_format_get_blockdepth(props->format));
|
||||
tile_size_B = tile_extent_el.width * tile_extent_el.height *
|
||||
pan_format_get_plane_blocksize(props->format, plane_idx);
|
||||
} else {
|
||||
/* Block-based YUV needs special care, because the U-tile extent
|
||||
* is in pixels, not blocks in that case. */
|
||||
assert(tile_extent_el.width % util_format_get_blockwidth(props->format) ==
|
||||
0);
|
||||
assert(tile_extent_el.height %
|
||||
util_format_get_blockheight(props->format) ==
|
||||
0);
|
||||
mip_extent_el = mip_extent_px;
|
||||
tile_size_B =
|
||||
(tile_extent_el.width / util_format_get_blockwidth(props->format)) *
|
||||
(tile_extent_el.height / util_format_get_blockheight(props->format)) *
|
||||
pan_format_get_plane_blocksize(props->format, plane_idx);
|
||||
}
|
||||
|
||||
if (use_explicit_layout) {
|
||||
slayout->row_stride_B =
|
||||
layout_constraints->wsi_row_pitch_B * tile_extent_el.height;
|
||||
if (slayout->row_stride_B & align_mask) {
|
||||
mesa_loge("WSI pitch not properly aligned");
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned width_from_wsi_row_stride =
|
||||
(slayout->row_stride_B / tile_size_B) * tile_extent_el.width;
|
||||
|
||||
if (width_from_wsi_row_stride < mip_extent_el.width) {
|
||||
mesa_loge("WSI pitch too small");
|
||||
return false;
|
||||
}
|
||||
|
||||
slayout->offset_B = layout_constraints->offset_B;
|
||||
if (slayout->offset_B & align_mask) {
|
||||
mesa_loge("WSI offset not properly aligned");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* When we can decide of the layout, we want things aligned on at least a
|
||||
* cacheline for performance reasons. */
|
||||
align_mask = MAX2(align_mask, 63);
|
||||
slayout->offset_B = ALIGN_POT(
|
||||
layout_constraints ? layout_constraints->offset_B : 0,
|
||||
MAX2(align_mask + 1, pan_image_slice_align(props->modifier)));
|
||||
slayout->row_stride_B = ALIGN_POT(
|
||||
tile_size_B * DIV_ROUND_UP(mip_extent_el.width, tile_extent_el.width),
|
||||
align_mask + 1);
|
||||
}
|
||||
|
||||
uint64_t surf_stride_B =
|
||||
(uint64_t)slayout->row_stride_B *
|
||||
DIV_ROUND_UP(mip_extent_el.height, tile_extent_el.height);
|
||||
surf_stride_B = ALIGN_POT(surf_stride_B, (uint64_t)align_mask + 1);
|
||||
|
||||
slayout->surface_stride_B = surf_stride_B;
|
||||
slayout->size_B = surf_stride_B * mip_extent_el.depth * props->nr_samples;
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
get_linear_wsi_row_pitch(const struct pan_image_props *props,
|
||||
unsigned plane_idx,
|
||||
const struct pan_image_slice_layout *slayout)
|
||||
{
|
||||
return slayout->row_stride_B;
|
||||
}
|
||||
|
||||
static bool
|
||||
init_linear_slice_layout(
|
||||
unsigned arch, const struct pan_image_props *props, unsigned plane_idx,
|
||||
struct pan_image_extent mip_extent_px,
|
||||
const struct pan_image_layout_constraints *layout_constraints,
|
||||
struct pan_image_slice_layout *slayout)
|
||||
{
|
||||
/* Use explicit layout only when wsi_row_pitch_B is non-zero */
|
||||
const bool use_explicit_layout =
|
||||
layout_constraints && layout_constraints->wsi_row_pitch_B;
|
||||
unsigned align_mask =
|
||||
pan_linear_or_tiled_row_align_req(arch, props->format, plane_idx) - 1;
|
||||
const unsigned fmt_blksize_B =
|
||||
pan_format_get_plane_blocksize(props->format, plane_idx);
|
||||
struct pan_image_extent mip_extent_el;
|
||||
|
||||
if (util_format_is_compressed(props->format)) {
|
||||
assert(util_format_get_num_planes(props->format) == 1);
|
||||
mip_extent_el.width = DIV_ROUND_UP(
|
||||
mip_extent_px.width, util_format_get_blockwidth(props->format));
|
||||
mip_extent_el.height = DIV_ROUND_UP(
|
||||
mip_extent_px.height, util_format_get_blockheight(props->format));
|
||||
mip_extent_el.depth = DIV_ROUND_UP(
|
||||
mip_extent_px.depth, util_format_get_blockdepth(props->format));
|
||||
} else {
|
||||
mip_extent_el = mip_extent_px;
|
||||
}
|
||||
|
||||
if (use_explicit_layout) {
|
||||
unsigned width_from_wsi_row_stride =
|
||||
layout_constraints->wsi_row_pitch_B / fmt_blksize_B;
|
||||
|
||||
if (!util_format_is_compressed(props->format))
|
||||
width_from_wsi_row_stride *= util_format_get_blockwidth(props->format);
|
||||
|
||||
if (width_from_wsi_row_stride < mip_extent_el.width) {
|
||||
mesa_loge("WSI pitch too small");
|
||||
return false;
|
||||
}
|
||||
|
||||
slayout->row_stride_B = layout_constraints->wsi_row_pitch_B;
|
||||
if (slayout->row_stride_B & align_mask) {
|
||||
mesa_loge("WSI pitch not properly aligned");
|
||||
return false;
|
||||
}
|
||||
|
||||
slayout->offset_B = layout_constraints->offset_B;
|
||||
if (slayout->offset_B & align_mask) {
|
||||
mesa_loge("WSI offset not properly aligned");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* When we can decide of the layout, we want things aligned on at least a
|
||||
* cacheline for performance reasons. */
|
||||
align_mask = MAX2(align_mask, 63);
|
||||
slayout->offset_B = ALIGN_POT(
|
||||
layout_constraints ? layout_constraints->offset_B : 0,
|
||||
MAX2(align_mask + 1, pan_image_slice_align(props->modifier)));
|
||||
slayout->row_stride_B =
|
||||
ALIGN_POT(mip_extent_el.width * fmt_blksize_B, align_mask + 1);
|
||||
}
|
||||
|
||||
uint64_t surf_stride_B = (uint64_t)mip_extent_el.height * slayout->row_stride_B;
|
||||
surf_stride_B = ALIGN_POT(surf_stride_B, (uint64_t)align_mask + 1);
|
||||
|
||||
slayout->surface_stride_B = surf_stride_B;
|
||||
slayout->size_B = surf_stride_B * mip_extent_el.depth * props->nr_samples;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
init_slice_layout(
|
||||
unsigned arch, const struct pan_image_props *props, unsigned plane_idx,
|
||||
struct pan_image_extent mip_extent_px,
|
||||
const struct pan_image_layout_constraints *layout_constraints,
|
||||
struct pan_image_slice_layout *slayout)
|
||||
{
|
||||
if (drm_is_afbc(props->modifier)) {
|
||||
return init_afbc_slice_layout(arch, props, plane_idx, mip_extent_px,
|
||||
layout_constraints, slayout);
|
||||
} else if (drm_is_afrc(props->modifier)) {
|
||||
return init_afrc_slice_layout(arch, props, plane_idx, mip_extent_px,
|
||||
layout_constraints, slayout);
|
||||
} else if (props->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
|
||||
return init_u_tiled_slice_layout(arch, props, plane_idx, mip_extent_px,
|
||||
layout_constraints, slayout);
|
||||
} else {
|
||||
assert(props->modifier == DRM_FORMAT_MOD_LINEAR);
|
||||
return init_linear_slice_layout(arch, props, plane_idx, mip_extent_px,
|
||||
layout_constraints, slayout);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
pan_image_layout_init(
|
||||
unsigned arch, const struct pan_image_props *props, unsigned plane_idx,
|
||||
const struct pan_image_layout_constraints *explicit_layout_constraints,
|
||||
struct pan_image_layout *layout)
|
||||
{
|
||||
/* Use explicit layout only when wsi_row_pitch_B is non-zero */
|
||||
struct pan_image_layout_constraints layout_constraints = {0};
|
||||
if (explicit_layout_constraints)
|
||||
layout_constraints = *explicit_layout_constraints;
|
||||
|
||||
const bool use_explicit_layout = layout_constraints.wsi_row_pitch_B != 0;
|
||||
|
||||
/* Explicit stride only work with non-mipmap, non-array, single-sample
|
||||
* 2D image without CRC.
|
||||
|
|
@ -304,201 +598,78 @@ pan_image_layout_init(
|
|||
if (plane_idx >= util_format_get_num_planes(props->format))
|
||||
return false;
|
||||
|
||||
const bool afbc = drm_is_afbc(props->modifier);
|
||||
const bool afrc = drm_is_afrc(props->modifier);
|
||||
int align_req_B;
|
||||
|
||||
if (afbc) {
|
||||
align_req_B =
|
||||
pan_afbc_header_row_stride_align(arch, props->format, props->modifier);
|
||||
} else if (afrc) {
|
||||
align_req_B = pan_afrc_buffer_alignment_from_modifier(props->modifier);
|
||||
} else {
|
||||
/* This is the alignment for non-explicit layout, and we want things
|
||||
* aligned on at least a cacheline for performance reasons in that case.
|
||||
*/
|
||||
align_req_B =
|
||||
pan_linear_or_tiled_row_align_req(arch, props->format, plane_idx);
|
||||
align_req_B = MAX2(align_req_B, 64);
|
||||
}
|
||||
|
||||
/* Mandate alignment */
|
||||
unsigned wsi_row_stride_B = 0;
|
||||
if (use_explicit_layout) {
|
||||
if (!wsi_row_pitch_to_row_stride(arch, props, plane_idx,
|
||||
layout_constraints, &wsi_row_stride_B))
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned fmt_blocksize_B =
|
||||
pan_format_get_plane_blocksize(props->format, plane_idx);
|
||||
|
||||
/* MSAA is implemented as a 3D texture with z corresponding to the
|
||||
* sample #, horrifyingly enough */
|
||||
|
||||
assert(props->extent_px.depth == 1 || props->nr_samples == 1);
|
||||
|
||||
const bool linear = props->modifier == DRM_FORMAT_MOD_LINEAR;
|
||||
const bool is_3d = props->dim == MALI_TEXTURE_DIMENSION_3D;
|
||||
struct pan_image_extent mip_extent_px = {
|
||||
.width = util_format_get_plane_width(props->format, plane_idx,
|
||||
props->extent_px.width),
|
||||
.height = util_format_get_plane_height(props->format, plane_idx,
|
||||
props->extent_px.height),
|
||||
.depth = props->extent_px.depth,
|
||||
};
|
||||
|
||||
const struct pan_image_block_size renderblk_size_el =
|
||||
pan_image_renderblock_size_el(props->modifier, props->format, plane_idx);
|
||||
const struct pan_image_block_size block_size_el =
|
||||
pan_image_block_size_el(props->modifier, props->format, plane_idx);
|
||||
|
||||
unsigned width_px = util_format_get_plane_width(props->format, plane_idx,
|
||||
props->extent_px.width);
|
||||
unsigned height_px = util_format_get_plane_height(props->format, plane_idx,
|
||||
props->extent_px.height);
|
||||
unsigned blk_width_px = util_format_get_blockwidth(props->format);
|
||||
unsigned blk_height_px = util_format_get_blockheight(props->format);
|
||||
unsigned depth_px = props->extent_px.depth;
|
||||
|
||||
unsigned align_w_el = renderblk_size_el.width;
|
||||
unsigned align_h_el = renderblk_size_el.height;
|
||||
|
||||
/* For tiled AFBC, align to tiles of superblocks (this can be large) */
|
||||
if (afbc) {
|
||||
align_w_el *= pan_afbc_tile_size(props->modifier);
|
||||
align_h_el *= pan_afbc_tile_size(props->modifier);
|
||||
}
|
||||
|
||||
uint64_t offset_B = layout_constraints ? layout_constraints->offset_B : 0;
|
||||
for (unsigned l = 0; l < props->nr_slices; ++l) {
|
||||
struct pan_image_slice_layout *slice = &layout->slices[l];
|
||||
struct pan_image_slice_layout *slayout = &layout->slices[l];
|
||||
|
||||
const unsigned effective_width_el =
|
||||
ALIGN_POT(DIV_ROUND_UP(width_px, blk_width_px), align_w_el);
|
||||
const unsigned effective_height_el =
|
||||
ALIGN_POT(DIV_ROUND_UP(height_px, blk_height_px), align_h_el);
|
||||
const unsigned effective_width_px = effective_width_el * blk_width_px;
|
||||
const unsigned effective_height_px = effective_height_el * blk_height_px;
|
||||
unsigned row_stride_B;
|
||||
if (!init_slice_layout(arch, props, plane_idx, mip_extent_px,
|
||||
&layout_constraints, slayout))
|
||||
return false;
|
||||
|
||||
/* Align levels to cache-line as a performance improvement for
|
||||
* linear/tiled and as a requirement for AFBC */
|
||||
|
||||
if (!use_explicit_layout)
|
||||
offset_B = ALIGN_POT(offset_B, pan_image_slice_align(props->modifier));
|
||||
|
||||
slice->offset_B = offset_B;
|
||||
|
||||
if (afrc) {
|
||||
row_stride_B = pan_afrc_row_stride(props->format, props->modifier,
|
||||
effective_width_px);
|
||||
} else {
|
||||
row_stride_B =
|
||||
fmt_blocksize_B * effective_width_el * block_size_el.height;
|
||||
}
|
||||
|
||||
/* On v7+ row_stride and offset alignment requirement are equal */
|
||||
if (arch >= 7) {
|
||||
row_stride_B = ALIGN_POT(row_stride_B, align_req_B);
|
||||
}
|
||||
|
||||
if (use_explicit_layout && !afbc) {
|
||||
/* Explicit stride should be rejected by wsi_row_pitch_to_row_stride()
|
||||
* if it's too small. */
|
||||
assert(wsi_row_stride_B >= row_stride_B);
|
||||
|
||||
if (!afrc || layout_constraints->strict)
|
||||
row_stride_B = wsi_row_stride_B;
|
||||
} else if (linear) {
|
||||
/* Keep lines alignment on 64 byte for performance */
|
||||
row_stride_B = ALIGN_POT(row_stride_B, 64);
|
||||
}
|
||||
|
||||
uint64_t slice_one_size_B =
|
||||
(uint64_t)row_stride_B * (effective_height_el / block_size_el.height);
|
||||
|
||||
/* Compute AFBC sizes if necessary */
|
||||
if (afbc) {
|
||||
slice->row_stride_B =
|
||||
pan_afbc_row_stride(props->modifier, effective_width_px);
|
||||
|
||||
/* Explicit stride should be rejected by wsi_row_pitch_to_row_stride()
|
||||
* if it's too small. */
|
||||
assert(!use_explicit_layout ||
|
||||
wsi_row_stride_B >= slice->row_stride_B);
|
||||
|
||||
if (use_explicit_layout && layout_constraints->strict) {
|
||||
slice->row_stride_B = wsi_row_stride_B;
|
||||
slice_one_size_B = (uint64_t)layout_constraints->wsi_row_pitch_B *
|
||||
effective_height_el;
|
||||
}
|
||||
|
||||
const unsigned stride_sb =
|
||||
pan_afbc_stride_blocks(props->modifier, slice->row_stride_B);
|
||||
const unsigned nr_sblocks =
|
||||
stride_sb * (effective_height_px / block_size_el.height);
|
||||
|
||||
slice->afbc.header_size_B =
|
||||
ALIGN_POT(nr_sblocks * AFBC_HEADER_BYTES_PER_TILE,
|
||||
pan_afbc_body_align(arch, props->modifier));
|
||||
|
||||
/* AFBC body size */
|
||||
slice->afbc.body_size_B = slice_one_size_B;
|
||||
|
||||
/* 3D AFBC resources have all headers placed at the
|
||||
* beginning instead of having them split per depth
|
||||
* level
|
||||
*/
|
||||
if (is_3d) {
|
||||
slice->afbc.surface_stride_B = slice->afbc.header_size_B;
|
||||
slice->afbc.header_size_B *= depth_px;
|
||||
slice->afbc.body_size_B *= depth_px;
|
||||
offset_B += slice->afbc.header_size_B;
|
||||
} else {
|
||||
slice_one_size_B += slice->afbc.header_size_B;
|
||||
slice->afbc.surface_stride_B = slice_one_size_B;
|
||||
}
|
||||
} else {
|
||||
slice->row_stride_B = row_stride_B;
|
||||
}
|
||||
|
||||
const uint64_t slice_full_size_B =
|
||||
slice_one_size_B * depth_px * props->nr_samples;
|
||||
|
||||
slice->surface_stride_B = slice_one_size_B;
|
||||
|
||||
/* Compute AFBC sizes if necessary */
|
||||
|
||||
offset_B += slice_full_size_B;
|
||||
|
||||
/* We can't use slice_full_size_B for AFBC(3D), otherwise the headers are
|
||||
* not counted. */
|
||||
if (afbc)
|
||||
slice->size_B = slice->afbc.body_size_B + slice->afbc.header_size_B;
|
||||
else
|
||||
slice->size_B = slice_full_size_B;
|
||||
layout_constraints.offset_B += slayout->size_B;
|
||||
|
||||
/* Add a checksum region if necessary */
|
||||
if (props->crc) {
|
||||
init_slice_crc_info(arch, slice, width_px, height_px, offset_B);
|
||||
offset_B += slice->crc.size_B;
|
||||
slice->size_B += slice->crc.size_B;
|
||||
init_slice_crc_info(arch, slayout, mip_extent_px.width,
|
||||
mip_extent_px.height, layout_constraints.offset_B);
|
||||
layout_constraints.offset_B += slayout->crc.size_B;
|
||||
slayout->size_B += slayout->crc.size_B;
|
||||
}
|
||||
|
||||
width_px = u_minify(width_px, 1);
|
||||
height_px = u_minify(height_px, 1);
|
||||
depth_px = u_minify(depth_px, 1);
|
||||
mip_extent_px.width = u_minify(mip_extent_px.width, 1);
|
||||
mip_extent_px.height = u_minify(mip_extent_px.height, 1);
|
||||
mip_extent_px.depth = u_minify(mip_extent_px.depth, 1);
|
||||
}
|
||||
|
||||
/* Arrays and cubemaps have the entire miptree duplicated */
|
||||
layout->array_stride_B =
|
||||
ALIGN_POT(offset_B - layout->slices[0].offset_B, 64);
|
||||
ALIGN_POT(layout_constraints.offset_B - layout->slices[0].offset_B, 64);
|
||||
if (use_explicit_layout) {
|
||||
layout->data_size_B = offset_B - layout_constraints->offset_B;
|
||||
layout->data_size_B =
|
||||
layout_constraints.offset_B - explicit_layout_constraints->offset_B;
|
||||
} else {
|
||||
/* Native images start from offset 0, and the planar plane offset has
|
||||
* been at least 4K page aligned below. So the base level slice offset
|
||||
* should always be the same with the plane offset.
|
||||
*/
|
||||
assert(!layout_constraints ||
|
||||
layout_constraints->offset_B == layout->slices[0].offset_B);
|
||||
assert(!explicit_layout_constraints ||
|
||||
explicit_layout_constraints->offset_B ==
|
||||
layout->slices[0].offset_B);
|
||||
layout->data_size_B = ALIGN_POT(
|
||||
(uint64_t)layout->array_stride_B * (uint64_t)props->array_size, 4096);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned
|
||||
pan_image_get_wsi_row_pitch(const struct pan_image_props *props,
|
||||
unsigned plane_idx,
|
||||
const struct pan_image_layout *layout,
|
||||
unsigned level)
|
||||
{
|
||||
const struct pan_image_slice_layout *slayout = &layout->slices[level];
|
||||
|
||||
if (drm_is_afbc(props->modifier)) {
|
||||
return get_afbc_wsi_row_pitch(props, plane_idx, slayout);
|
||||
} else if (drm_is_afrc(props->modifier)) {
|
||||
return get_afrc_wsi_row_pitch(props, plane_idx, slayout);
|
||||
} else if (props->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
|
||||
return get_u_tiled_wsi_row_pitch(props, plane_idx, slayout);
|
||||
} else {
|
||||
assert(props->modifier == DRM_FORMAT_MOD_LINEAR);
|
||||
return get_linear_wsi_row_pitch(props, plane_idx, slayout);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue