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:
Boris Brezillon 2025-06-16 15:11:21 +02:00
parent 18f87b6ada
commit e6f8cab698

View file

@ -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);
}
}