Skip to content
Snippets Groups Projects
Commit 811f8a19 authored by Alyssa Rosenzweig's avatar Alyssa Rosenzweig Committed by Marge Bot
Browse files

panfrost: Require 64-byte alignment on imports


While Panfrost allocates linear images with strides that are a multiple of 64
bytes, other dma-buf producers on the system may not satisfy this requirement.
However, at least on v7 and newer, any image with a regular format must have a
stride that is a multiple of 64 bytes.

This fixes a real bug in an application that created a linear R8_UNORM image
with stride 480 bytes, imported it as an EGL_image, and then tried to texture
from it with the GPU. Previously, the driver allowed this situation but it
resulted in an imprecise fault from the GPU. This patch corrects the driver to
reject the import as invalid due to the unaligned stride, ensuring we never
attempt to texture from such a resource.

To implement, we add some new layout queries to centralize knowledge about the
stride alignment requirements, and we sprinkle in asserts to show how the
invariant is upheld throughout the lifecycle of image creation to texturing.

Cc: mesa-stable
Signed-off-by: default avatarAlyssa Rosenzweig <alyssa@collabora.com>
Reviewed-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
Part-of: <mesa/mesa!19620>
parent 1827b4a2
No related branches found
No related tags found
No related merge requests found
......@@ -275,6 +275,34 @@ panfrost_texture_offset(const struct pan_image_layout *layout,
(surface_idx * layout->slices[level].surface_stride);
}
/*
* Return the minimum stride alignment in bytes for a given texture format.
*
* There is no format on any supported Mali with a minimum alignment greater
* than 64 bytes, but 64 bytes is the required alignment of all regular formats
* in v7 and newer. If this alignment is not met, imprecise faults may be
* raised.
*
* This may not be necessary on older hardware but we enforce it there too for
* uniformity. If this poses a problem there, we'll need a solution that can
* handle v7 as well.
*
* Certain non-regular formats require smaller power-of-two alignments.
* This requirement could be loosened in the future if there is a compelling
* reason, by making this query more precise.
*/
uint32_t
pan_stride_align_B(UNUSED enum pipe_format format)
{
return 64;
}
bool
pan_is_stride_aligned(enum pipe_format format, uint32_t stride_B)
{
return (stride_B % pan_stride_align_B(format)) == 0;
}
bool
pan_image_layout_init(struct pan_image_layout *layout,
const struct pan_image_explicit_layout *explicit_layout)
......@@ -288,8 +316,15 @@ pan_image_layout_init(struct pan_image_layout *layout,
layout->nr_slices > 1 || layout->crc))
return false;
/* Mandate 64 byte alignement */
if (explicit_layout && (explicit_layout->offset & 63))
/* Require both offsets and strides to be aligned to the hardware
* requirement. Panfrost allocates offsets and strides like this, so
* this requirement is satisfied by any image that was exported from
* another process with Panfrost. However, it does restrict imports of
* EGL external images.
*/
if (explicit_layout &&
!(pan_is_stride_aligned(layout->format, explicit_layout->offset) &&
pan_is_stride_aligned(layout->format, explicit_layout->row_stride)))
return false;
unsigned fmt_blocksize = util_format_get_blocksize(layout->format);
......@@ -342,10 +377,19 @@ pan_image_layout_init(struct pan_image_layout *layout,
row_stride = explicit_layout->row_stride;
} else if (linear) {
/* Keep lines alignment on 64 byte for performance */
/* Keep lines alignment on 64 byte for performance.
*
* Note that this is a multiple of the minimum
* stride alignment, so the hardware requirement is
* satisfied as a result.
*/
row_stride = ALIGN_POT(row_stride, 64);
}
assert(pan_is_stride_aligned(layout->format, row_stride) &&
"alignment gauranteed in both code paths");
unsigned slice_one_size = row_stride * (effective_height / block_size.height);
/* Compute AFBC sizes if necessary */
......@@ -385,6 +429,10 @@ pan_image_layout_init(struct pan_image_layout *layout,
slice->surface_stride = slice_one_size;
assert(pan_is_stride_aligned(layout->format, slice->surface_stride) &&
"integer multiple of aligned is still aligned, "
"and AFBC header is at least 64 byte aligned");
/* Compute AFBC sizes if necessary */
offset += slice_full_size;
......
......@@ -247,10 +247,18 @@ panfrost_get_surface_strides(const struct pan_image_layout *layout,
* repurposed as a Y offset which we don't use */
*row_stride = PAN_ARCH < 7 ? 0 : slice->row_stride;
*surf_stride = slice->afbc.surface_stride;
/* Row stride alignment requirement does not apply to AFBC */
} else {
*row_stride = slice->row_stride;
*surf_stride = slice->surface_stride;
/* Particular for linear, the row stride must be aligned */
assert(pan_is_stride_aligned(layout->format, *row_stride));
}
/* All surface strides are aligned, required for linear */
assert(pan_is_stride_aligned(layout->format, *surf_stride));
}
static mali_ptr
......
......@@ -238,6 +238,12 @@ panfrost_from_legacy_stride(unsigned legacy_stride,
enum pipe_format format,
uint64_t modifier);
uint32_t
pan_stride_align_B(enum pipe_format format);
bool
pan_is_stride_aligned(enum pipe_format format, unsigned stride_B);
struct pan_surface {
union {
mali_ptr data;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment