return (modifier & AFBC_FORMAT_MOD_TILED) ? 4096 : 64;
}
+static inline unsigned
+format_minimum_alignment(const struct panfrost_device *dev,
+ enum pipe_format format, bool afbc)
+{
+ if (afbc)
+ return 16;
+
+ if (dev->arch < 7)
+ return 63;
+
+ switch (format) {
+ /* For v7+, NV12 and NV21 have a looser alignment requirement of 16 bytes */
+ case PIPE_FORMAT_R8_G8B8_420_UNORM:
+ case PIPE_FORMAT_G8_B8R8_420_UNORM:
+ return 16;
+ default:
+ return 64;
+ }
+}
+
/* Computes sizes for checksumming, which is 8 bytes per 16x16 tile.
* Checksumming is believed to be a CRC variant (CRC64 based on the size?).
* This feature is also known as "transaction elimination". */
}
bool
-pan_image_layout_init(struct pan_image_layout *layout,
+pan_image_layout_init(const struct panfrost_device *dev,
+ struct pan_image_layout *layout,
const struct pan_image_explicit_layout *explicit_layout)
{
/* Explicit stride only work with non-mipmap, non-array, single-sample
layout->crc))
return false;
- /* Mandate 64 byte alignement */
- if (explicit_layout && (explicit_layout->offset & 63))
- return false;
+ bool afbc = drm_is_afbc(layout->modifier);
+ int align_req = format_minimum_alignment(dev, layout->format, afbc);
+
+ /* Mandate alignment */
+ if (explicit_layout) {
+ bool rejected = false;
+
+ int align_mask = align_req - 1;
+
+ if (dev->arch >= 7) {
+ rejected = ((explicit_layout->offset & align_mask) ||
+ (explicit_layout->row_stride & align_mask));
+ } else {
+ rejected = (explicit_layout->offset & align_mask);
+ }
+
+ if (rejected) {
+ mesa_loge(
+ "panfrost: rejecting image due to unsupported offset or stride "
+ "alignment.\n");
+ return false;
+ }
+ }
unsigned fmt_blocksize = util_format_get_blocksize(layout->format);
assert(layout->depth == 1 || layout->nr_samples == 1);
- bool afbc = drm_is_afbc(layout->modifier);
bool linear = layout->modifier == DRM_FORMAT_MOD_LINEAR;
bool is_3d = layout->dim == MALI_TEXTURE_DIMENSION_3D;
unsigned row_stride = fmt_blocksize * effective_width * block_size.height;
+ /* On v7+ row_stride and offset alignment requirement are equal */
+ if (dev->arch >= 7) {
+ row_stride = ALIGN_POT(row_stride, align_req);
+ }
+
if (explicit_layout && !afbc) {
/* Make sure the explicit stride is valid */
- if (explicit_layout->row_stride < row_stride)
+ if (explicit_layout->row_stride < row_stride) {
+ mesa_loge("panfrost: rejecting image due to invalid row stride.\n");
return false;
+ }
row_stride = explicit_layout->row_stride;
} else if (linear) {
ALIGN_POT(slice->row_stride * (effective_height / align_h),
pan_afbc_body_align(layout->modifier));
- if (explicit_layout && explicit_layout->row_stride < slice->row_stride)
+ if (explicit_layout &&
+ explicit_layout->row_stride < slice->row_stride) {
+ mesa_loge("panfrost: rejecting image due to invalid row stride.\n");
return false;
+ }
/* AFBC body size */
slice->afbc.body_size = slice_one_size;
/* dEQP-GLES3.functional.texture.format.compressed.etc1_2d_pot */
TEST(Layout, ImplicitLayoutInterleavedETC2)
{
+ struct panfrost_device dev = {0};
+
struct pan_image_layout l = {
.modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,
.format = PIPE_FORMAT_ETC2_RGB8,
unsigned offsets[9] = {0, 8192, 10240, 10752, 10880,
11008, 11136, 11264, 11392};
- ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+ ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
for (unsigned i = 0; i < 8; ++i) {
unsigned size = (offsets[i + 1] - offsets[i]);
TEST(Layout, ImplicitLayoutInterleavedASTC5x5)
{
+ struct panfrost_device dev = {0};
+
struct pan_image_layout l = {
.modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,
.format = PIPE_FORMAT_ASTC_5x5,
.dim = MALI_TEXTURE_DIMENSION_2D,
.nr_slices = 1};
- ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+ ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
/* The image is 50x50 pixels, with 5x5 blocks. So it is a 10x10 grid of ASTC
* blocks. 4x4 tiles of ASTC blocks are u-interleaved, so we have to round up
TEST(Layout, ImplicitLayoutLinearASTC5x5)
{
+ struct panfrost_device dev = {0};
+
struct pan_image_layout l = {.modifier = DRM_FORMAT_MOD_LINEAR,
.format = PIPE_FORMAT_ASTC_5x5,
.width = 50,
.dim = MALI_TEXTURE_DIMENSION_2D,
.nr_slices = 1};
- ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+ ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
/* The image is 50x50 pixels, with 5x5 blocks. So it is a 10x10 grid of ASTC
* blocks. Each ASTC block is 16 bytes, so the row stride is 160 bytes,
/* dEQP-GLES3.functional.texture.format.unsized.rgba_unsigned_byte_3d_pot */
TEST(AFBCLayout, Linear3D)
{
+ struct panfrost_device dev = {0};
+
uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC(
AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE);
.dim = MALI_TEXTURE_DIMENSION_3D,
.nr_slices = 1};
- ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+ ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
/* AFBC Surface stride is bytes between consecutive surface headers, which is
* the header size since this is a 3D texture. At superblock size 16x16, the
TEST(AFBCLayout, Tiled16x16)
{
+ struct panfrost_device dev = {0};
+
uint64_t modifier =
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
AFBC_FORMAT_MOD_TILED | AFBC_FORMAT_MOD_SPARSE);
.dim = MALI_TEXTURE_DIMENSION_2D,
.nr_slices = 1};
- ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+ ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
/* The image is 917x417. Superblocks are 16x16, so there are 58x27
* superblocks. Superblocks are grouped into 8x8 tiles, so there are 8x4
TEST(AFBCLayout, Linear16x16Minimal)
{
+ struct panfrost_device dev = {0};
+
uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC(
AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE);
.dim = MALI_TEXTURE_DIMENSION_2D,
.nr_slices = 1};
- ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+ ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
/* Image is 1x1 to test for correct alignment everywhere. */
EXPECT_EQ(l.slices[0].offset, 0);
TEST(AFBCLayout, Tiled16x16Minimal)
{
+ struct panfrost_device dev = {0};
+
uint64_t modifier =
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
AFBC_FORMAT_MOD_TILED | AFBC_FORMAT_MOD_SPARSE);
.dim = MALI_TEXTURE_DIMENSION_2D,
.nr_slices = 1};
- ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+ ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
/* Image is 1x1 to test for correct alignment everywhere. */
EXPECT_EQ(l.slices[0].offset, 0);