diff --git a/src/panfrost/lib/meson.build b/src/panfrost/lib/meson.build index d39978511cc..8163af1736b 100644 --- a/src/panfrost/lib/meson.build +++ b/src/panfrost/lib/meson.build @@ -55,6 +55,7 @@ libpanfrost_lib_files = files( 'pan_encoder.h', 'pan_afbc.c', + 'pan_afrc.c', 'pan_attributes.c', 'pan_blend.c', 'pan_clear.c', diff --git a/src/panfrost/lib/pan_afrc.c b/src/panfrost/lib/pan_afrc.c new file mode 100644 index 00000000000..473a3d0d26d --- /dev/null +++ b/src/panfrost/lib/pan_afrc.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2023 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Louis-Francis Ratté-Boulianne + */ + +#include "pan_texture.h" + +/* Arm Fixed-Rate Compression (AFRC) is a lossy compression scheme natively + * implemented in Mali GPUs. AFRC images can only be rendered or textured + * from. It is currently not possible to do image reads or writes to such + * resources. + * + * AFRC divides the image into an array of fixed-size coding units which are + * grouped into paging tiles. The size of the coding units (clump size) + * depends on the image format and the pixel layout (whether it is optimized + * for 2D locality and rotation, or for scan line order access). The last + * parameter is the size of the compressed block that can be either 16, 24, + * or 32 bytes. + * + * The compression rate can be calculated by dividing the compressed block + * size by the uncompressed block size (clump size multiplied by the component + * size and the number of components). + */ + +struct pan_afrc_format_info +panfrost_afrc_get_format_info(enum pipe_format format) +{ + const struct util_format_description *desc = util_format_description(format); + struct pan_afrc_format_info info = {0}; + + /* No AFRC(ZS). */ + if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) + return info; + + unsigned bpc = 0; + for (unsigned c = 0; c < desc->nr_channels; c++) { + if (bpc && bpc != desc->channel[c].size) + return info; + + bpc = desc->channel[0].size; + } + + info.bpc = bpc; + + if (desc->colorspace == UTIL_FORMAT_COLORSPACE_YUV) { + if (desc->layout != UTIL_FORMAT_LAYOUT_SUBSAMPLED) + info.ichange_fmt = PAN_AFRC_ICHANGE_FORMAT_YUV444; + else if (util_format_is_subsampled_422(format)) + info.ichange_fmt = PAN_AFRC_ICHANGE_FORMAT_YUV422; + else + info.ichange_fmt = PAN_AFRC_ICHANGE_FORMAT_YUV420; + } else { + assert(desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || + desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB); + info.ichange_fmt = PAN_AFRC_ICHANGE_FORMAT_RAW; + } + + info.num_planes = util_format_get_num_planes(format); + info.num_comps = util_format_get_nr_components(format); + return info; +} diff --git a/src/panfrost/lib/pan_layout.c b/src/panfrost/lib/pan_layout.c index d85d54eb7de..ab35f0b2a9e 100644 --- a/src/panfrost/lib/pan_layout.c +++ b/src/panfrost/lib/pan_layout.c @@ -116,6 +116,16 @@ panfrost_afbc_subblock_size(uint64_t modifier) return (struct pan_block_size){4, 4}; } +/* + * Given an AFRC modifier, return whether the layout is optimized for scan + * order (vs rotation order). + */ +bool +panfrost_afrc_is_scan(uint64_t modifier) +{ + return modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN; +} + /* * Given a format, determine the tile size used for u-interleaving. For formats * that are already block compressed, this is 4x4. For all other formats, this diff --git a/src/panfrost/lib/pan_texture.c b/src/panfrost/lib/pan_texture.c index 8f4f4e817cd..db43a0d2510 100644 --- a/src/panfrost/lib/pan_texture.c +++ b/src/panfrost/lib/pan_texture.c @@ -735,3 +735,96 @@ GENX(pan_afbc_compression_mode)(enum pipe_format format) unreachable("all AFBC formats handled"); } #endif + +#if PAN_ARCH >= 10 +enum mali_afrc_format +GENX(pan_afrc_format)(struct pan_afrc_format_info info, uint64_t modifier, + unsigned plane) +{ + bool scan = panfrost_afrc_is_scan(modifier); + + assert(info.bpc == 8 || info.bpc == 10); + assert(info.num_comps > 0 && info.num_comps <= 4); + + switch (info.ichange_fmt) { + case PAN_AFRC_ICHANGE_FORMAT_RAW: + assert(plane == 0); + + if (info.bpc == 8) + return (scan ? MALI_AFRC_FORMAT_R8_SCAN : MALI_AFRC_FORMAT_R8_ROT) + + (info.num_comps - 1); + + assert(info.num_comps == 4); + return (scan ? MALI_AFRC_FORMAT_R10G10B10A10_SCAN + : MALI_AFRC_FORMAT_R10G10B10A10_ROT); + + case PAN_AFRC_ICHANGE_FORMAT_YUV444: + if (info.bpc == 8) { + if (plane == 0 || info.num_planes == 3) + return (scan ? MALI_AFRC_FORMAT_R8_444_SCAN + : MALI_AFRC_FORMAT_R8_444_ROT); + + return (scan ? MALI_AFRC_FORMAT_R8G8_444_SCAN + : MALI_AFRC_FORMAT_R8G8_444_ROT); + } + + assert(info.num_planes == 3); + return (scan ? MALI_AFRC_FORMAT_R10_444_SCAN + : MALI_AFRC_FORMAT_R10_444_ROT); + + case PAN_AFRC_ICHANGE_FORMAT_YUV422: + if (info.bpc == 8) { + if (plane == 0 || info.num_planes == 3) + return (scan ? MALI_AFRC_FORMAT_R8_422_SCAN + : MALI_AFRC_FORMAT_R8_422_ROT); + + return (scan ? MALI_AFRC_FORMAT_R8G8_422_SCAN + : MALI_AFRC_FORMAT_R8G8_422_ROT); + } + + if (plane == 0 || info.num_planes == 3) + return (scan ? MALI_AFRC_FORMAT_R10_422_SCAN + : MALI_AFRC_FORMAT_R10_422_ROT); + + return (scan ? MALI_AFRC_FORMAT_R10G10_422_SCAN + : MALI_AFRC_FORMAT_R10G10_422_ROT); + + case PAN_AFRC_ICHANGE_FORMAT_YUV420: + if (info.bpc == 8) { + if (plane == 0 || info.num_planes == 3) + return (scan ? MALI_AFRC_FORMAT_R8_420_SCAN + : MALI_AFRC_FORMAT_R8_420_ROT); + + return (scan ? MALI_AFRC_FORMAT_R8G8_420_SCAN + : MALI_AFRC_FORMAT_R8G8_420_ROT); + } + + if (plane == 0 || info.num_planes == 3) + return (scan ? MALI_AFRC_FORMAT_R10_420_SCAN + : MALI_AFRC_FORMAT_R10_420_ROT); + + return (scan ? MALI_AFRC_FORMAT_R10G10_420_SCAN + : MALI_AFRC_FORMAT_R10G10_420_ROT); + + default: + return MALI_AFRC_FORMAT_INVALID; + } +} + +enum mali_afrc_block_size +GENX(pan_afrc_block_size)(uint64_t modifier, unsigned index) +{ + /* Clump size flag for planes 1 and 2 is shifted by 4 bits */ + unsigned shift = index == 0 ? 0 : 4; + uint64_t flag = (modifier >> shift) & AFRC_FORMAT_MOD_CU_SIZE_MASK; + + /* clang-format off */ + switch (flag) { + case AFRC_FORMAT_MOD_CU_SIZE_16: return MALI_AFRC_BLOCK_SIZE_16; + case AFRC_FORMAT_MOD_CU_SIZE_24: return MALI_AFRC_BLOCK_SIZE_24; + case AFRC_FORMAT_MOD_CU_SIZE_32: return MALI_AFRC_BLOCK_SIZE_32; + default: unreachable("invalid code unit size"); + } + /* clang-format on */ +} +#endif diff --git a/src/panfrost/lib/pan_texture.h b/src/panfrost/lib/pan_texture.h index fc7c0851ac9..3a0080c7567 100644 --- a/src/panfrost/lib/pan_texture.h +++ b/src/panfrost/lib/pan_texture.h @@ -278,6 +278,29 @@ uint32_t pan_slice_align(uint64_t modifier); uint32_t pan_afbc_body_align(uint64_t modifier); +/* AFRC */ + +#define AFRC_CLUMPS_PER_TILE 64 + +enum pan_afrc_interchange_format { + PAN_AFRC_ICHANGE_FORMAT_RAW, + PAN_AFRC_ICHANGE_FORMAT_YUV444, + PAN_AFRC_ICHANGE_FORMAT_YUV422, + PAN_AFRC_ICHANGE_FORMAT_YUV420, +}; + +struct pan_afrc_format_info { + unsigned bpc : 4; + unsigned num_comps : 3; + unsigned ichange_fmt : 2; + unsigned num_planes : 2; +}; + +struct pan_afrc_format_info +panfrost_afrc_get_format_info(enum pipe_format format); + +bool panfrost_afrc_is_scan(uint64_t modifier); + struct pan_block_size panfrost_block_size(uint64_t modifier, enum pipe_format format); @@ -302,6 +325,10 @@ unsigned panfrost_texture_offset(const struct pan_image_layout *layout, ((mod >> 52) == \ (DRM_FORMAT_MOD_ARM_TYPE_AFBC | (DRM_FORMAT_MOD_VENDOR_ARM << 4))) +#define drm_is_afrc(mod) \ + ((mod >> 52) == \ + (DRM_FORMAT_MOD_ARM_TYPE_AFRC | (DRM_FORMAT_MOD_VENDOR_ARM << 4))) + struct pan_image_explicit_layout { unsigned offset; unsigned row_stride; @@ -337,6 +364,14 @@ enum mali_afbc_compression_mode GENX(pan_afbc_compression_mode)(enum pipe_format format); #endif +#if PAN_ARCH >= 10 +enum mali_afrc_format +GENX(pan_afrc_format)(struct pan_afrc_format_info info, uint64_t modifier, + unsigned plane); +enum mali_afrc_block_size GENX(pan_afrc_block_size)(uint64_t modifier, + unsigned index); +#endif + #ifdef __cplusplus } /* extern C */ #endif