1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2008 VMware, Inc. 3bf215546Sopenharmony_ci * Copyright (C) 2014 Broadcom 4bf215546Sopenharmony_ci * Copyright (C) 2018-2019 Alyssa Rosenzweig 5bf215546Sopenharmony_ci * Copyright (C) 2019-2020 Collabora, Ltd. 6bf215546Sopenharmony_ci * 7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 8bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 9bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 10bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 12bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 15bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 16bf215546Sopenharmony_ci * Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24bf215546Sopenharmony_ci * SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci */ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "util/macros.h" 29bf215546Sopenharmony_ci#include "util/u_math.h" 30bf215546Sopenharmony_ci#include "pan_texture.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#if PAN_ARCH >= 5 33bf215546Sopenharmony_ci/* 34bf215546Sopenharmony_ci * Arm Scalable Texture Compression (ASTC) corresponds to just a few formats. 35bf215546Sopenharmony_ci * The block dimension is not part of the format. Instead, it is encoded as a 36bf215546Sopenharmony_ci * 6-bit tag on the payload pointer. Map the block size for a single dimension. 37bf215546Sopenharmony_ci */ 38bf215546Sopenharmony_cistatic inline enum mali_astc_2d_dimension 39bf215546Sopenharmony_cipanfrost_astc_dim_2d(unsigned dim) 40bf215546Sopenharmony_ci{ 41bf215546Sopenharmony_ci switch (dim) { 42bf215546Sopenharmony_ci case 4: return MALI_ASTC_2D_DIMENSION_4; 43bf215546Sopenharmony_ci case 5: return MALI_ASTC_2D_DIMENSION_5; 44bf215546Sopenharmony_ci case 6: return MALI_ASTC_2D_DIMENSION_6; 45bf215546Sopenharmony_ci case 8: return MALI_ASTC_2D_DIMENSION_8; 46bf215546Sopenharmony_ci case 10: return MALI_ASTC_2D_DIMENSION_10; 47bf215546Sopenharmony_ci case 12: return MALI_ASTC_2D_DIMENSION_12; 48bf215546Sopenharmony_ci default: unreachable("Invalid ASTC dimension"); 49bf215546Sopenharmony_ci } 50bf215546Sopenharmony_ci} 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_cistatic inline enum mali_astc_3d_dimension 53bf215546Sopenharmony_cipanfrost_astc_dim_3d(unsigned dim) 54bf215546Sopenharmony_ci{ 55bf215546Sopenharmony_ci switch (dim) { 56bf215546Sopenharmony_ci case 3: return MALI_ASTC_3D_DIMENSION_3; 57bf215546Sopenharmony_ci case 4: return MALI_ASTC_3D_DIMENSION_4; 58bf215546Sopenharmony_ci case 5: return MALI_ASTC_3D_DIMENSION_5; 59bf215546Sopenharmony_ci case 6: return MALI_ASTC_3D_DIMENSION_6; 60bf215546Sopenharmony_ci default: unreachable("Invalid ASTC dimension"); 61bf215546Sopenharmony_ci } 62bf215546Sopenharmony_ci} 63bf215546Sopenharmony_ci#endif 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci/* Texture addresses are tagged with information about compressed formats. 66bf215546Sopenharmony_ci * AFBC uses a bit for whether the colorspace transform is enabled (RGB and 67bf215546Sopenharmony_ci * RGBA only). 68bf215546Sopenharmony_ci * For ASTC, this is a "stretch factor" encoding the block size. */ 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_cistatic unsigned 71bf215546Sopenharmony_cipanfrost_compression_tag(const struct util_format_description *desc, 72bf215546Sopenharmony_ci enum mali_texture_dimension dim, 73bf215546Sopenharmony_ci uint64_t modifier) 74bf215546Sopenharmony_ci{ 75bf215546Sopenharmony_ci#if PAN_ARCH >= 5 && PAN_ARCH <= 8 76bf215546Sopenharmony_ci if (drm_is_afbc(modifier)) { 77bf215546Sopenharmony_ci unsigned flags = (modifier & AFBC_FORMAT_MOD_YTR) ? 78bf215546Sopenharmony_ci MALI_AFBC_SURFACE_FLAG_YTR : 0; 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci#if PAN_ARCH >= 6 81bf215546Sopenharmony_ci /* Prefetch enable */ 82bf215546Sopenharmony_ci flags |= MALI_AFBC_SURFACE_FLAG_PREFETCH; 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci if (panfrost_afbc_is_wide(modifier)) 85bf215546Sopenharmony_ci flags |= MALI_AFBC_SURFACE_FLAG_WIDE_BLOCK; 86bf215546Sopenharmony_ci#endif 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci#if PAN_ARCH >= 7 89bf215546Sopenharmony_ci /* Tiled headers */ 90bf215546Sopenharmony_ci if (modifier & AFBC_FORMAT_MOD_TILED) 91bf215546Sopenharmony_ci flags |= MALI_AFBC_SURFACE_FLAG_TILED_HEADER; 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci /* Used to make sure AFBC headers don't point outside the AFBC 94bf215546Sopenharmony_ci * body. HW is using the AFBC surface stride to do this check, 95bf215546Sopenharmony_ci * which doesn't work for 3D textures because the surface 96bf215546Sopenharmony_ci * stride does not cover the body. Only supported on v7+. 97bf215546Sopenharmony_ci */ 98bf215546Sopenharmony_ci if (dim != MALI_TEXTURE_DIMENSION_3D) 99bf215546Sopenharmony_ci flags |= MALI_AFBC_SURFACE_FLAG_CHECK_PAYLOAD_RANGE; 100bf215546Sopenharmony_ci#endif 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci return flags; 103bf215546Sopenharmony_ci } else if (desc->layout == UTIL_FORMAT_LAYOUT_ASTC) { 104bf215546Sopenharmony_ci if (desc->block.depth > 1) { 105bf215546Sopenharmony_ci return (panfrost_astc_dim_3d(desc->block.depth) << 4) | 106bf215546Sopenharmony_ci (panfrost_astc_dim_3d(desc->block.height) << 2) | 107bf215546Sopenharmony_ci panfrost_astc_dim_3d(desc->block.width); 108bf215546Sopenharmony_ci } else { 109bf215546Sopenharmony_ci return (panfrost_astc_dim_2d(desc->block.height) << 3) | 110bf215546Sopenharmony_ci panfrost_astc_dim_2d(desc->block.width); 111bf215546Sopenharmony_ci } 112bf215546Sopenharmony_ci } 113bf215546Sopenharmony_ci#endif 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci /* Tags are not otherwise used */ 116bf215546Sopenharmony_ci return 0; 117bf215546Sopenharmony_ci} 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci/* Cubemaps have 6 faces as "layers" in between each actual layer. We 120bf215546Sopenharmony_ci * need to fix this up. TODO: logic wrong in the asserted out cases ... 121bf215546Sopenharmony_ci * can they happen, perhaps from cubemap arrays? */ 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_cistatic void 124bf215546Sopenharmony_cipanfrost_adjust_cube_dimensions( 125bf215546Sopenharmony_ci unsigned *first_face, unsigned *last_face, 126bf215546Sopenharmony_ci unsigned *first_layer, unsigned *last_layer) 127bf215546Sopenharmony_ci{ 128bf215546Sopenharmony_ci *first_face = *first_layer % 6; 129bf215546Sopenharmony_ci *last_face = *last_layer % 6; 130bf215546Sopenharmony_ci *first_layer /= 6; 131bf215546Sopenharmony_ci *last_layer /= 6; 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci assert((*first_layer == *last_layer) || (*first_face == 0 && *last_face == 5)); 134bf215546Sopenharmony_ci} 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci/* Following the texture descriptor is a number of descriptors. How many? */ 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_cistatic unsigned 139bf215546Sopenharmony_cipanfrost_texture_num_elements( 140bf215546Sopenharmony_ci unsigned first_level, unsigned last_level, 141bf215546Sopenharmony_ci unsigned first_layer, unsigned last_layer, 142bf215546Sopenharmony_ci unsigned nr_samples, bool is_cube) 143bf215546Sopenharmony_ci{ 144bf215546Sopenharmony_ci unsigned first_face = 0, last_face = 0; 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci if (is_cube) { 147bf215546Sopenharmony_ci panfrost_adjust_cube_dimensions(&first_face, &last_face, 148bf215546Sopenharmony_ci &first_layer, &last_layer); 149bf215546Sopenharmony_ci } 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci unsigned levels = 1 + last_level - first_level; 152bf215546Sopenharmony_ci unsigned layers = 1 + last_layer - first_layer; 153bf215546Sopenharmony_ci unsigned faces = 1 + last_face - first_face; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci return levels * layers * faces * MAX2(nr_samples, 1); 156bf215546Sopenharmony_ci} 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci/* Conservative estimate of the size of the texture payload a priori. 159bf215546Sopenharmony_ci * Average case, size equal to the actual size. Worst case, off by 2x (if 160bf215546Sopenharmony_ci * a manual stride is not needed on a linear texture). Returned value 161bf215546Sopenharmony_ci * must be greater than or equal to the actual size, so it's safe to use 162bf215546Sopenharmony_ci * as an allocation amount */ 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ciunsigned 165bf215546Sopenharmony_ciGENX(panfrost_estimate_texture_payload_size)(const struct pan_image_view *iview) 166bf215546Sopenharmony_ci{ 167bf215546Sopenharmony_ci#if PAN_ARCH >= 9 168bf215546Sopenharmony_ci size_t element_size = pan_size(PLANE); 169bf215546Sopenharmony_ci#else 170bf215546Sopenharmony_ci /* Assume worst case. Overestimates on Midgard, but that's ok. */ 171bf215546Sopenharmony_ci size_t element_size = pan_size(SURFACE_WITH_STRIDE); 172bf215546Sopenharmony_ci#endif 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci unsigned elements = 175bf215546Sopenharmony_ci panfrost_texture_num_elements(iview->first_level, iview->last_level, 176bf215546Sopenharmony_ci iview->first_layer, iview->last_layer, 177bf215546Sopenharmony_ci iview->image->layout.nr_samples, 178bf215546Sopenharmony_ci iview->dim == MALI_TEXTURE_DIMENSION_CUBE); 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci return element_size * elements; 181bf215546Sopenharmony_ci} 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_cistruct panfrost_surface_iter { 184bf215546Sopenharmony_ci unsigned layer, last_layer; 185bf215546Sopenharmony_ci unsigned level, first_level, last_level; 186bf215546Sopenharmony_ci unsigned face, first_face, last_face; 187bf215546Sopenharmony_ci unsigned sample, first_sample, last_sample; 188bf215546Sopenharmony_ci}; 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_cistatic void 191bf215546Sopenharmony_cipanfrost_surface_iter_begin(struct panfrost_surface_iter *iter, 192bf215546Sopenharmony_ci unsigned first_layer, unsigned last_layer, 193bf215546Sopenharmony_ci unsigned first_level, unsigned last_level, 194bf215546Sopenharmony_ci unsigned first_face, unsigned last_face, 195bf215546Sopenharmony_ci unsigned nr_samples) 196bf215546Sopenharmony_ci{ 197bf215546Sopenharmony_ci iter->layer = first_layer; 198bf215546Sopenharmony_ci iter->last_layer = last_layer; 199bf215546Sopenharmony_ci iter->level = iter->first_level = first_level; 200bf215546Sopenharmony_ci iter->last_level = last_level; 201bf215546Sopenharmony_ci iter->face = iter->first_face = first_face; 202bf215546Sopenharmony_ci iter->last_face = last_face; 203bf215546Sopenharmony_ci iter->sample = iter->first_sample = 0; 204bf215546Sopenharmony_ci iter->last_sample = nr_samples - 1; 205bf215546Sopenharmony_ci} 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_cistatic bool 208bf215546Sopenharmony_cipanfrost_surface_iter_end(const struct panfrost_surface_iter *iter) 209bf215546Sopenharmony_ci{ 210bf215546Sopenharmony_ci return iter->layer > iter->last_layer; 211bf215546Sopenharmony_ci} 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_cistatic void 214bf215546Sopenharmony_cipanfrost_surface_iter_next(struct panfrost_surface_iter *iter) 215bf215546Sopenharmony_ci{ 216bf215546Sopenharmony_ci#define INC_TEST(field) \ 217bf215546Sopenharmony_ci do { \ 218bf215546Sopenharmony_ci if (iter->field++ < iter->last_ ## field) \ 219bf215546Sopenharmony_ci return; \ 220bf215546Sopenharmony_ci iter->field = iter->first_ ## field; \ 221bf215546Sopenharmony_ci } while (0) 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci /* Ordering is different on v7: inner loop is iterating on levels */ 224bf215546Sopenharmony_ci if (PAN_ARCH >= 7) 225bf215546Sopenharmony_ci INC_TEST(level); 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci INC_TEST(sample); 228bf215546Sopenharmony_ci INC_TEST(face); 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci if (PAN_ARCH < 7) 231bf215546Sopenharmony_ci INC_TEST(level); 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci iter->layer++; 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci#undef INC_TEST 236bf215546Sopenharmony_ci} 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_cistatic void 239bf215546Sopenharmony_cipanfrost_get_surface_strides(const struct pan_image_layout *layout, 240bf215546Sopenharmony_ci unsigned l, 241bf215546Sopenharmony_ci int32_t *row_stride, int32_t *surf_stride) 242bf215546Sopenharmony_ci{ 243bf215546Sopenharmony_ci const struct pan_image_slice_layout *slice = &layout->slices[l]; 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci if (drm_is_afbc(layout->modifier)) { 246bf215546Sopenharmony_ci /* Pre v7 don't have a row stride field. This field is 247bf215546Sopenharmony_ci * repurposed as a Y offset which we don't use */ 248bf215546Sopenharmony_ci *row_stride = PAN_ARCH < 7 ? 0 : slice->row_stride; 249bf215546Sopenharmony_ci *surf_stride = slice->afbc.surface_stride; 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci /* Row stride alignment requirement does not apply to AFBC */ 252bf215546Sopenharmony_ci } else { 253bf215546Sopenharmony_ci *row_stride = slice->row_stride; 254bf215546Sopenharmony_ci *surf_stride = slice->surface_stride; 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci /* Particular for linear, the row stride must be aligned */ 257bf215546Sopenharmony_ci assert(pan_is_stride_aligned(layout->format, *row_stride)); 258bf215546Sopenharmony_ci } 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci /* All surface strides are aligned, required for linear */ 261bf215546Sopenharmony_ci assert(pan_is_stride_aligned(layout->format, *surf_stride)); 262bf215546Sopenharmony_ci} 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_cistatic mali_ptr 265bf215546Sopenharmony_cipanfrost_get_surface_pointer(const struct pan_image_layout *layout, 266bf215546Sopenharmony_ci enum mali_texture_dimension dim, 267bf215546Sopenharmony_ci mali_ptr base, 268bf215546Sopenharmony_ci unsigned l, unsigned w, unsigned f, unsigned s) 269bf215546Sopenharmony_ci{ 270bf215546Sopenharmony_ci unsigned face_mult = dim == MALI_TEXTURE_DIMENSION_CUBE ? 6 : 1; 271bf215546Sopenharmony_ci unsigned offset; 272bf215546Sopenharmony_ci 273bf215546Sopenharmony_ci if (layout->dim == MALI_TEXTURE_DIMENSION_3D) { 274bf215546Sopenharmony_ci assert(!f && !s); 275bf215546Sopenharmony_ci offset = layout->slices[l].offset + 276bf215546Sopenharmony_ci (w * panfrost_get_layer_stride(layout, l)); 277bf215546Sopenharmony_ci } else { 278bf215546Sopenharmony_ci offset = panfrost_texture_offset(layout, l, (w * face_mult) + f, s); 279bf215546Sopenharmony_ci } 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci return base + offset; 282bf215546Sopenharmony_ci} 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci#if PAN_ARCH >= 9 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci#define CLUMP_FMT(pipe, mali) [PIPE_FORMAT_ ## pipe] = MALI_CLUMP_FORMAT_ ## mali 287bf215546Sopenharmony_cistatic enum mali_clump_format special_clump_formats[PIPE_FORMAT_COUNT] = { 288bf215546Sopenharmony_ci CLUMP_FMT(X32_S8X24_UINT, X32S8X24), 289bf215546Sopenharmony_ci CLUMP_FMT(X24S8_UINT, X24S8), 290bf215546Sopenharmony_ci CLUMP_FMT(S8X24_UINT, S8X24), 291bf215546Sopenharmony_ci CLUMP_FMT(S8_UINT, S8), 292bf215546Sopenharmony_ci CLUMP_FMT(L4A4_UNORM, L4A4), 293bf215546Sopenharmony_ci CLUMP_FMT(L8A8_UNORM, L8A8), 294bf215546Sopenharmony_ci CLUMP_FMT(L8A8_UINT, L8A8), 295bf215546Sopenharmony_ci CLUMP_FMT(L8A8_SINT, L8A8), 296bf215546Sopenharmony_ci CLUMP_FMT(A8_UNORM, A8), 297bf215546Sopenharmony_ci CLUMP_FMT(A8_UINT, A8), 298bf215546Sopenharmony_ci CLUMP_FMT(A8_SINT, A8), 299bf215546Sopenharmony_ci CLUMP_FMT(ETC1_RGB8, ETC2_RGB8), 300bf215546Sopenharmony_ci CLUMP_FMT(ETC2_RGB8, ETC2_RGB8), 301bf215546Sopenharmony_ci CLUMP_FMT(ETC2_SRGB8, ETC2_RGB8), 302bf215546Sopenharmony_ci CLUMP_FMT(ETC2_RGB8A1, ETC2_RGB8A1), 303bf215546Sopenharmony_ci CLUMP_FMT(ETC2_SRGB8A1, ETC2_RGB8A1), 304bf215546Sopenharmony_ci CLUMP_FMT(ETC2_RGBA8, ETC2_RGBA8), 305bf215546Sopenharmony_ci CLUMP_FMT(ETC2_SRGBA8, ETC2_RGBA8), 306bf215546Sopenharmony_ci CLUMP_FMT(ETC2_R11_UNORM, ETC2_R11_UNORM), 307bf215546Sopenharmony_ci CLUMP_FMT(ETC2_R11_SNORM, ETC2_R11_SNORM), 308bf215546Sopenharmony_ci CLUMP_FMT(ETC2_RG11_UNORM, ETC2_RG11_UNORM), 309bf215546Sopenharmony_ci CLUMP_FMT(ETC2_RG11_SNORM, ETC2_RG11_SNORM), 310bf215546Sopenharmony_ci CLUMP_FMT(DXT1_RGB, BC1_UNORM), 311bf215546Sopenharmony_ci CLUMP_FMT(DXT1_RGBA, BC1_UNORM), 312bf215546Sopenharmony_ci CLUMP_FMT(DXT1_SRGB, BC1_UNORM), 313bf215546Sopenharmony_ci CLUMP_FMT(DXT1_SRGBA, BC1_UNORM), 314bf215546Sopenharmony_ci CLUMP_FMT(DXT3_RGBA, BC2_UNORM), 315bf215546Sopenharmony_ci CLUMP_FMT(DXT3_SRGBA, BC2_UNORM), 316bf215546Sopenharmony_ci CLUMP_FMT(DXT5_RGBA, BC3_UNORM), 317bf215546Sopenharmony_ci CLUMP_FMT(DXT5_SRGBA, BC3_UNORM), 318bf215546Sopenharmony_ci CLUMP_FMT(RGTC1_UNORM, BC4_UNORM), 319bf215546Sopenharmony_ci CLUMP_FMT(RGTC1_SNORM, BC4_SNORM), 320bf215546Sopenharmony_ci CLUMP_FMT(RGTC2_UNORM, BC5_UNORM), 321bf215546Sopenharmony_ci CLUMP_FMT(RGTC2_SNORM, BC5_SNORM), 322bf215546Sopenharmony_ci CLUMP_FMT(BPTC_RGB_FLOAT, BC6H_SF16), 323bf215546Sopenharmony_ci CLUMP_FMT(BPTC_RGB_UFLOAT, BC6H_UF16), 324bf215546Sopenharmony_ci CLUMP_FMT(BPTC_RGBA_UNORM, BC7_UNORM), 325bf215546Sopenharmony_ci CLUMP_FMT(BPTC_SRGBA, BC7_UNORM), 326bf215546Sopenharmony_ci}; 327bf215546Sopenharmony_ci#undef CLUMP_FMT 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_cistatic enum mali_clump_format 330bf215546Sopenharmony_cipanfrost_clump_format(enum pipe_format format) 331bf215546Sopenharmony_ci{ 332bf215546Sopenharmony_ci /* First, try a special clump format. Note that the 0 encoding is for a 333bf215546Sopenharmony_ci * raw clump format, which will never be in the special table. 334bf215546Sopenharmony_ci */ 335bf215546Sopenharmony_ci if (special_clump_formats[format]) 336bf215546Sopenharmony_ci return special_clump_formats[format]; 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci /* Else, it's a raw format. Raw formats must not be compressed. */ 339bf215546Sopenharmony_ci assert(!util_format_is_compressed(format)); 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci /* Select the appropriate raw format. */ 342bf215546Sopenharmony_ci switch (util_format_get_blocksize(format)) { 343bf215546Sopenharmony_ci case 1: return MALI_CLUMP_FORMAT_RAW8; 344bf215546Sopenharmony_ci case 2: return MALI_CLUMP_FORMAT_RAW16; 345bf215546Sopenharmony_ci case 3: return MALI_CLUMP_FORMAT_RAW24; 346bf215546Sopenharmony_ci case 4: return MALI_CLUMP_FORMAT_RAW32; 347bf215546Sopenharmony_ci case 6: return MALI_CLUMP_FORMAT_RAW48; 348bf215546Sopenharmony_ci case 8: return MALI_CLUMP_FORMAT_RAW64; 349bf215546Sopenharmony_ci case 12: return MALI_CLUMP_FORMAT_RAW96; 350bf215546Sopenharmony_ci case 16: return MALI_CLUMP_FORMAT_RAW128; 351bf215546Sopenharmony_ci default: unreachable("Invalid bpp"); 352bf215546Sopenharmony_ci } 353bf215546Sopenharmony_ci} 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_cistatic enum mali_afbc_superblock_size 356bf215546Sopenharmony_citranslate_superblock_size(uint64_t modifier) 357bf215546Sopenharmony_ci{ 358bf215546Sopenharmony_ci assert(drm_is_afbc(modifier)); 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_ci switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) { 361bf215546Sopenharmony_ci case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: 362bf215546Sopenharmony_ci return MALI_AFBC_SUPERBLOCK_SIZE_16X16; 363bf215546Sopenharmony_ci case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: 364bf215546Sopenharmony_ci return MALI_AFBC_SUPERBLOCK_SIZE_32X8; 365bf215546Sopenharmony_ci case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: 366bf215546Sopenharmony_ci return MALI_AFBC_SUPERBLOCK_SIZE_64X4; 367bf215546Sopenharmony_ci default: 368bf215546Sopenharmony_ci unreachable("Invalid superblock size"); 369bf215546Sopenharmony_ci } 370bf215546Sopenharmony_ci} 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_cistatic void 373bf215546Sopenharmony_cipanfrost_emit_plane(const struct pan_image_layout *layout, 374bf215546Sopenharmony_ci enum pipe_format format, 375bf215546Sopenharmony_ci mali_ptr pointer, 376bf215546Sopenharmony_ci unsigned level, 377bf215546Sopenharmony_ci void *payload) 378bf215546Sopenharmony_ci{ 379bf215546Sopenharmony_ci const struct util_format_description *desc = 380bf215546Sopenharmony_ci util_format_description(layout->format); 381bf215546Sopenharmony_ci 382bf215546Sopenharmony_ci int32_t row_stride, surface_stride; 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci panfrost_get_surface_strides(layout, level, &row_stride, &surface_stride); 385bf215546Sopenharmony_ci assert(row_stride >= 0 && surface_stride >= 0 && "negative stride"); 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ci bool afbc = drm_is_afbc(layout->modifier); 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci pan_pack(payload, PLANE, cfg) { 390bf215546Sopenharmony_ci cfg.pointer = pointer; 391bf215546Sopenharmony_ci cfg.row_stride = row_stride; 392bf215546Sopenharmony_ci cfg.size = layout->data_size - layout->slices[level].offset; 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci cfg.slice_stride = layout->nr_samples ? 395bf215546Sopenharmony_ci layout->slices[level].surface_stride : 396bf215546Sopenharmony_ci panfrost_get_layer_stride(layout, level); 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci if (desc->layout == UTIL_FORMAT_LAYOUT_ASTC) { 399bf215546Sopenharmony_ci assert(!afbc); 400bf215546Sopenharmony_ci 401bf215546Sopenharmony_ci if (desc->block.depth > 1) { 402bf215546Sopenharmony_ci cfg.plane_type = MALI_PLANE_TYPE_ASTC_3D; 403bf215546Sopenharmony_ci cfg.astc._3d.block_width = panfrost_astc_dim_3d(desc->block.width); 404bf215546Sopenharmony_ci cfg.astc._3d.block_height = panfrost_astc_dim_3d(desc->block.height); 405bf215546Sopenharmony_ci cfg.astc._3d.block_depth = panfrost_astc_dim_3d(desc->block.depth); 406bf215546Sopenharmony_ci } else { 407bf215546Sopenharmony_ci cfg.plane_type = MALI_PLANE_TYPE_ASTC_2D; 408bf215546Sopenharmony_ci cfg.astc._2d.block_width = panfrost_astc_dim_2d(desc->block.width); 409bf215546Sopenharmony_ci cfg.astc._2d.block_height = panfrost_astc_dim_2d(desc->block.height); 410bf215546Sopenharmony_ci } 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci bool srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB); 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ci /* Mesa does not advertise _HDR formats yet */ 415bf215546Sopenharmony_ci cfg.astc.decode_hdr = false; 416bf215546Sopenharmony_ci 417bf215546Sopenharmony_ci /* sRGB formats decode to RGBA8 sRGB, which is narrow. 418bf215546Sopenharmony_ci * 419bf215546Sopenharmony_ci * Non-sRGB formats decode to RGBA16F which is wide. 420bf215546Sopenharmony_ci * With a future extension, we could decode non-sRGB 421bf215546Sopenharmony_ci * formats narrowly too, but this isn't wired up in Mesa 422bf215546Sopenharmony_ci * yet. 423bf215546Sopenharmony_ci */ 424bf215546Sopenharmony_ci cfg.astc.decode_wide = !srgb; 425bf215546Sopenharmony_ci } else if (afbc) { 426bf215546Sopenharmony_ci cfg.plane_type = MALI_PLANE_TYPE_AFBC; 427bf215546Sopenharmony_ci cfg.afbc.superblock_size = translate_superblock_size(layout->modifier); 428bf215546Sopenharmony_ci cfg.afbc.ytr = (layout->modifier & AFBC_FORMAT_MOD_YTR); 429bf215546Sopenharmony_ci cfg.afbc.tiled_header = (layout->modifier & AFBC_FORMAT_MOD_TILED); 430bf215546Sopenharmony_ci cfg.afbc.prefetch = true; 431bf215546Sopenharmony_ci cfg.afbc.compression_mode = pan_afbc_compression_mode(format); 432bf215546Sopenharmony_ci cfg.afbc.header_stride = layout->slices[level].afbc.header_size; 433bf215546Sopenharmony_ci } else { 434bf215546Sopenharmony_ci cfg.plane_type = MALI_PLANE_TYPE_GENERIC; 435bf215546Sopenharmony_ci cfg.clump_format = panfrost_clump_format(format); 436bf215546Sopenharmony_ci } 437bf215546Sopenharmony_ci 438bf215546Sopenharmony_ci if (!afbc && layout->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) 439bf215546Sopenharmony_ci cfg.clump_ordering = MALI_CLUMP_ORDERING_TILED_U_INTERLEAVED; 440bf215546Sopenharmony_ci else if (!afbc) 441bf215546Sopenharmony_ci cfg.clump_ordering = MALI_CLUMP_ORDERING_LINEAR; 442bf215546Sopenharmony_ci } 443bf215546Sopenharmony_ci} 444bf215546Sopenharmony_ci#endif 445bf215546Sopenharmony_ci 446bf215546Sopenharmony_cistatic void 447bf215546Sopenharmony_cipanfrost_emit_texture_payload(const struct pan_image_view *iview, 448bf215546Sopenharmony_ci enum pipe_format format, 449bf215546Sopenharmony_ci void *payload) 450bf215546Sopenharmony_ci{ 451bf215546Sopenharmony_ci const struct pan_image_layout *layout = &iview->image->layout; 452bf215546Sopenharmony_ci ASSERTED const struct util_format_description *desc = 453bf215546Sopenharmony_ci util_format_description(format); 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci mali_ptr base = iview->image->data.bo->ptr.gpu + iview->image->data.offset; 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci if (iview->buf.size) { 458bf215546Sopenharmony_ci assert (iview->dim == MALI_TEXTURE_DIMENSION_1D); 459bf215546Sopenharmony_ci base += iview->buf.offset; 460bf215546Sopenharmony_ci } 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_ci /* panfrost_compression_tag() wants the dimension of the resource, not the 463bf215546Sopenharmony_ci * one of the image view (those might differ). 464bf215546Sopenharmony_ci */ 465bf215546Sopenharmony_ci base |= panfrost_compression_tag(desc, layout->dim, layout->modifier); 466bf215546Sopenharmony_ci 467bf215546Sopenharmony_ci /* v4 does not support compression */ 468bf215546Sopenharmony_ci assert(PAN_ARCH >= 5 || !drm_is_afbc(layout->modifier)); 469bf215546Sopenharmony_ci assert(PAN_ARCH >= 5 || desc->layout != UTIL_FORMAT_LAYOUT_ASTC); 470bf215546Sopenharmony_ci 471bf215546Sopenharmony_ci /* Inject the addresses in, interleaving array indices, mip levels, 472bf215546Sopenharmony_ci * cube faces, and strides in that order. On Bifrost and older, each 473bf215546Sopenharmony_ci * sample had its own surface descriptor; on Valhall, they are fused 474bf215546Sopenharmony_ci * into a single plane descriptor. 475bf215546Sopenharmony_ci */ 476bf215546Sopenharmony_ci 477bf215546Sopenharmony_ci unsigned first_layer = iview->first_layer, last_layer = iview->last_layer; 478bf215546Sopenharmony_ci unsigned nr_samples = PAN_ARCH <= 7 ? layout->nr_samples : 1; 479bf215546Sopenharmony_ci unsigned first_face = 0, last_face = 0; 480bf215546Sopenharmony_ci 481bf215546Sopenharmony_ci if (iview->dim == MALI_TEXTURE_DIMENSION_CUBE) { 482bf215546Sopenharmony_ci panfrost_adjust_cube_dimensions(&first_face, &last_face, 483bf215546Sopenharmony_ci &first_layer, &last_layer); 484bf215546Sopenharmony_ci } 485bf215546Sopenharmony_ci 486bf215546Sopenharmony_ci struct panfrost_surface_iter iter; 487bf215546Sopenharmony_ci 488bf215546Sopenharmony_ci for (panfrost_surface_iter_begin(&iter, first_layer, last_layer, 489bf215546Sopenharmony_ci iview->first_level, iview->last_level, 490bf215546Sopenharmony_ci first_face, last_face, nr_samples); 491bf215546Sopenharmony_ci !panfrost_surface_iter_end(&iter); 492bf215546Sopenharmony_ci panfrost_surface_iter_next(&iter)) { 493bf215546Sopenharmony_ci mali_ptr pointer = 494bf215546Sopenharmony_ci panfrost_get_surface_pointer(layout, iview->dim, base, 495bf215546Sopenharmony_ci iter.level, iter.layer, 496bf215546Sopenharmony_ci iter.face, iter.sample); 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci#if PAN_ARCH >= 9 499bf215546Sopenharmony_ci panfrost_emit_plane(layout, format, pointer, iter.level, payload); 500bf215546Sopenharmony_ci payload += pan_size(PLANE); 501bf215546Sopenharmony_ci#else 502bf215546Sopenharmony_ci pan_pack(payload, SURFACE_WITH_STRIDE, cfg) { 503bf215546Sopenharmony_ci cfg.pointer = pointer; 504bf215546Sopenharmony_ci panfrost_get_surface_strides(layout, iter.level, 505bf215546Sopenharmony_ci &cfg.row_stride, 506bf215546Sopenharmony_ci &cfg.surface_stride); 507bf215546Sopenharmony_ci } 508bf215546Sopenharmony_ci payload += pan_size(SURFACE_WITH_STRIDE); 509bf215546Sopenharmony_ci#endif 510bf215546Sopenharmony_ci } 511bf215546Sopenharmony_ci} 512bf215546Sopenharmony_ci 513bf215546Sopenharmony_ci#if PAN_ARCH <= 7 514bf215546Sopenharmony_ci/* Map modifiers to mali_texture_layout for packing in a texture descriptor */ 515bf215546Sopenharmony_ci 516bf215546Sopenharmony_cistatic enum mali_texture_layout 517bf215546Sopenharmony_cipanfrost_modifier_to_layout(uint64_t modifier) 518bf215546Sopenharmony_ci{ 519bf215546Sopenharmony_ci if (drm_is_afbc(modifier)) 520bf215546Sopenharmony_ci return MALI_TEXTURE_LAYOUT_AFBC; 521bf215546Sopenharmony_ci else if (modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) 522bf215546Sopenharmony_ci return MALI_TEXTURE_LAYOUT_TILED; 523bf215546Sopenharmony_ci else if (modifier == DRM_FORMAT_MOD_LINEAR) 524bf215546Sopenharmony_ci return MALI_TEXTURE_LAYOUT_LINEAR; 525bf215546Sopenharmony_ci else 526bf215546Sopenharmony_ci unreachable("Invalid modifer"); 527bf215546Sopenharmony_ci} 528bf215546Sopenharmony_ci#endif 529bf215546Sopenharmony_ci 530bf215546Sopenharmony_ci/* 531bf215546Sopenharmony_ci * Generates a texture descriptor. Ideally, descriptors are immutable after the 532bf215546Sopenharmony_ci * texture is created, so we can keep these hanging around in GPU memory in a 533bf215546Sopenharmony_ci * dedicated BO and not have to worry. In practice there are some minor gotchas 534bf215546Sopenharmony_ci * with this (the driver sometimes will change the format of a texture on the 535bf215546Sopenharmony_ci * fly for compression) but it's fast enough to just regenerate the descriptor 536bf215546Sopenharmony_ci * in those cases, rather than monkeypatching at drawtime. A texture descriptor 537bf215546Sopenharmony_ci * consists of a 32-byte header followed by pointers. 538bf215546Sopenharmony_ci */ 539bf215546Sopenharmony_civoid 540bf215546Sopenharmony_ciGENX(panfrost_new_texture)(const struct panfrost_device *dev, 541bf215546Sopenharmony_ci const struct pan_image_view *iview, 542bf215546Sopenharmony_ci void *out, const struct panfrost_ptr *payload) 543bf215546Sopenharmony_ci{ 544bf215546Sopenharmony_ci const struct pan_image_layout *layout = &iview->image->layout; 545bf215546Sopenharmony_ci enum pipe_format format = iview->format; 546bf215546Sopenharmony_ci unsigned swizzle; 547bf215546Sopenharmony_ci 548bf215546Sopenharmony_ci if (PAN_ARCH >= 7 && util_format_is_depth_or_stencil(format)) { 549bf215546Sopenharmony_ci /* v7+ doesn't have an _RRRR component order, combine the 550bf215546Sopenharmony_ci * user swizzle with a .XXXX swizzle to emulate that. 551bf215546Sopenharmony_ci */ 552bf215546Sopenharmony_ci static const unsigned char replicate_x[4] = { 553bf215546Sopenharmony_ci PIPE_SWIZZLE_X, PIPE_SWIZZLE_X, 554bf215546Sopenharmony_ci PIPE_SWIZZLE_X, PIPE_SWIZZLE_X, 555bf215546Sopenharmony_ci }; 556bf215546Sopenharmony_ci unsigned char patched_swizzle[4]; 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci util_format_compose_swizzles(replicate_x, 559bf215546Sopenharmony_ci iview->swizzle, 560bf215546Sopenharmony_ci patched_swizzle); 561bf215546Sopenharmony_ci swizzle = panfrost_translate_swizzle_4(patched_swizzle); 562bf215546Sopenharmony_ci } else { 563bf215546Sopenharmony_ci swizzle = panfrost_translate_swizzle_4(iview->swizzle); 564bf215546Sopenharmony_ci } 565bf215546Sopenharmony_ci 566bf215546Sopenharmony_ci panfrost_emit_texture_payload(iview, format, payload->cpu); 567bf215546Sopenharmony_ci 568bf215546Sopenharmony_ci unsigned array_size = iview->last_layer - iview->first_layer + 1; 569bf215546Sopenharmony_ci 570bf215546Sopenharmony_ci if (iview->dim == MALI_TEXTURE_DIMENSION_CUBE) { 571bf215546Sopenharmony_ci assert(iview->first_layer % 6 == 0); 572bf215546Sopenharmony_ci assert(iview->last_layer % 6 == 5); 573bf215546Sopenharmony_ci array_size /= 6; 574bf215546Sopenharmony_ci } 575bf215546Sopenharmony_ci 576bf215546Sopenharmony_ci unsigned width; 577bf215546Sopenharmony_ci 578bf215546Sopenharmony_ci if (iview->buf.size) { 579bf215546Sopenharmony_ci assert(iview->dim == MALI_TEXTURE_DIMENSION_1D); 580bf215546Sopenharmony_ci assert(!iview->first_level && !iview->last_level); 581bf215546Sopenharmony_ci assert(!iview->first_layer && !iview->last_layer); 582bf215546Sopenharmony_ci assert(layout->nr_samples == 1); 583bf215546Sopenharmony_ci assert(layout->height == 1 && layout->depth == 1); 584bf215546Sopenharmony_ci assert(iview->buf.offset + iview->buf.size <= layout->width); 585bf215546Sopenharmony_ci width = iview->buf.size; 586bf215546Sopenharmony_ci } else { 587bf215546Sopenharmony_ci width = u_minify(layout->width, iview->first_level); 588bf215546Sopenharmony_ci } 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_ci pan_pack(out, TEXTURE, cfg) { 591bf215546Sopenharmony_ci cfg.dimension = iview->dim; 592bf215546Sopenharmony_ci cfg.format = dev->formats[format].hw; 593bf215546Sopenharmony_ci cfg.width = width; 594bf215546Sopenharmony_ci cfg.height = u_minify(layout->height, iview->first_level); 595bf215546Sopenharmony_ci if (iview->dim == MALI_TEXTURE_DIMENSION_3D) 596bf215546Sopenharmony_ci cfg.depth = u_minify(layout->depth, iview->first_level); 597bf215546Sopenharmony_ci else 598bf215546Sopenharmony_ci cfg.sample_count = layout->nr_samples; 599bf215546Sopenharmony_ci cfg.swizzle = swizzle; 600bf215546Sopenharmony_ci#if PAN_ARCH >= 9 601bf215546Sopenharmony_ci cfg.texel_interleave = 602bf215546Sopenharmony_ci (layout->modifier != DRM_FORMAT_MOD_LINEAR) || 603bf215546Sopenharmony_ci util_format_is_compressed(format); 604bf215546Sopenharmony_ci#else 605bf215546Sopenharmony_ci cfg.texel_ordering = 606bf215546Sopenharmony_ci panfrost_modifier_to_layout(layout->modifier); 607bf215546Sopenharmony_ci#endif 608bf215546Sopenharmony_ci cfg.levels = iview->last_level - iview->first_level + 1; 609bf215546Sopenharmony_ci cfg.array_size = array_size; 610bf215546Sopenharmony_ci 611bf215546Sopenharmony_ci#if PAN_ARCH >= 6 612bf215546Sopenharmony_ci cfg.surfaces = payload->gpu; 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci /* We specify API-level LOD clamps in the sampler descriptor 615bf215546Sopenharmony_ci * and use these clamps simply for bounds checking */ 616bf215546Sopenharmony_ci cfg.minimum_lod = FIXED_16(0, false); 617bf215546Sopenharmony_ci cfg.maximum_lod = FIXED_16(cfg.levels - 1, false); 618bf215546Sopenharmony_ci#else 619bf215546Sopenharmony_ci cfg.manual_stride = true; 620bf215546Sopenharmony_ci#endif 621bf215546Sopenharmony_ci } 622bf215546Sopenharmony_ci} 623