• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019-2022 Collabora, Ltd.
3  * Copyright (C) 2018-2019 Alyssa Rosenzweig
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  */
25 
26 #include "util/log.h"
27 #include "util/macros.h"
28 #include "util/u_math.h"
29 #include "pan_texture.h"
30 
31 /*
32  * List of supported modifiers, in descending order of preference. AFBC is
33  * faster than u-interleaved tiling which is faster than linear. Within AFBC,
34  * enabling the YUV-like transform is typically a win where possible.
35  * AFRC is only used if explicitely asked for (only for RGB formats).
36  */
37 uint64_t pan_best_modifiers[PAN_MODIFIER_COUNT] = {
38    DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
39                            AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_SPLIT),
40    DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
41                            AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_SPLIT |
42                            AFBC_FORMAT_MOD_YTR),
43 
44    DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
45                            AFBC_FORMAT_MOD_TILED | AFBC_FORMAT_MOD_SC |
46                            AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_YTR),
47 
48    DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
49                            AFBC_FORMAT_MOD_TILED | AFBC_FORMAT_MOD_SC |
50                            AFBC_FORMAT_MOD_SPARSE),
51 
52    DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
53                            AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_YTR),
54 
55    DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
56                            AFBC_FORMAT_MOD_SPARSE),
57 
58    DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,
59    DRM_FORMAT_MOD_LINEAR,
60 
61    DRM_FORMAT_MOD_ARM_AFRC(
62       AFRC_FORMAT_MOD_CU_SIZE_P0(AFRC_FORMAT_MOD_CU_SIZE_16)),
63    DRM_FORMAT_MOD_ARM_AFRC(
64       AFRC_FORMAT_MOD_CU_SIZE_P0(AFRC_FORMAT_MOD_CU_SIZE_24)),
65    DRM_FORMAT_MOD_ARM_AFRC(
66       AFRC_FORMAT_MOD_CU_SIZE_P0(AFRC_FORMAT_MOD_CU_SIZE_32)),
67    DRM_FORMAT_MOD_ARM_AFRC(
68       AFRC_FORMAT_MOD_CU_SIZE_P0(AFRC_FORMAT_MOD_CU_SIZE_16) |
69       AFRC_FORMAT_MOD_LAYOUT_SCAN),
70    DRM_FORMAT_MOD_ARM_AFRC(
71       AFRC_FORMAT_MOD_CU_SIZE_P0(AFRC_FORMAT_MOD_CU_SIZE_24) |
72       AFRC_FORMAT_MOD_LAYOUT_SCAN),
73    DRM_FORMAT_MOD_ARM_AFRC(
74       AFRC_FORMAT_MOD_CU_SIZE_P0(AFRC_FORMAT_MOD_CU_SIZE_32) |
75       AFRC_FORMAT_MOD_LAYOUT_SCAN),
76 };
77 
78 /* Table of AFBC superblock sizes */
79 static const struct pan_block_size afbc_superblock_sizes[] = {
80    [AFBC_FORMAT_MOD_BLOCK_SIZE_16x16] = {16, 16},
81    [AFBC_FORMAT_MOD_BLOCK_SIZE_32x8] = {32, 8},
82    [AFBC_FORMAT_MOD_BLOCK_SIZE_64x4] = {64, 4},
83 };
84 
85 /*
86  * Given an AFBC modifier, return the superblock size.
87  *
88  * We do not yet have any use cases for multiplanar YCBCr formats with different
89  * superblock sizes on the luma and chroma planes. These formats are unsupported
90  * for now.
91  */
92 struct pan_block_size
panfrost_afbc_superblock_size(uint64_t modifier)93 panfrost_afbc_superblock_size(uint64_t modifier)
94 {
95    unsigned index = (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
96 
97    assert(drm_is_afbc(modifier));
98    assert(index < ARRAY_SIZE(afbc_superblock_sizes));
99 
100    return afbc_superblock_sizes[index];
101 }
102 
103 /*
104  * Given an AFBC modifier, return the render size.
105  */
106 struct pan_block_size
panfrost_afbc_renderblock_size(uint64_t modifier)107 panfrost_afbc_renderblock_size(uint64_t modifier)
108 {
109    unsigned index = (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
110 
111    assert(drm_is_afbc(modifier));
112    assert(index < ARRAY_SIZE(afbc_superblock_sizes));
113 
114    struct pan_block_size blk_size = afbc_superblock_sizes[index];
115 
116   /* The GPU needs to render 16x16 tiles. For wide tiles, that means we
117    * have to extend the render region to have a height of 16 pixels.
118    */
119    blk_size.height = ALIGN_POT(blk_size.height, 16);
120    return blk_size;
121 }
122 
123 /*
124  * Given an AFBC modifier, return the width of the superblock.
125  */
126 unsigned
panfrost_afbc_superblock_width(uint64_t modifier)127 panfrost_afbc_superblock_width(uint64_t modifier)
128 {
129    return panfrost_afbc_superblock_size(modifier).width;
130 }
131 
132 /*
133  * Given an AFBC modifier, return the height of the superblock.
134  */
135 unsigned
panfrost_afbc_superblock_height(uint64_t modifier)136 panfrost_afbc_superblock_height(uint64_t modifier)
137 {
138    return panfrost_afbc_superblock_size(modifier).height;
139 }
140 
141 /*
142  * Given an AFBC modifier, return if "wide blocks" are used. Wide blocks are
143  * defined as superblocks wider than 16 pixels, the minimum (and default) super
144  * block width.
145  */
146 bool
panfrost_afbc_is_wide(uint64_t modifier)147 panfrost_afbc_is_wide(uint64_t modifier)
148 {
149    return panfrost_afbc_superblock_width(modifier) > 16;
150 }
151 
152 /*
153  * Given an AFBC modifier, return the subblock size (subdivision of a
154  * superblock). This is always 4x4 for now as we only support one AFBC
155  * superblock layout.
156  */
157 struct pan_block_size
panfrost_afbc_subblock_size(uint64_t modifier)158 panfrost_afbc_subblock_size(uint64_t modifier)
159 {
160    return (struct pan_block_size){4, 4};
161 }
162 
163 /*
164  * Given an AFRC modifier, return whether the layout is optimized for scan
165  * order (vs rotation order).
166  */
167 bool
panfrost_afrc_is_scan(uint64_t modifier)168 panfrost_afrc_is_scan(uint64_t modifier)
169 {
170    return modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN;
171 }
172 
173 struct pan_block_size
panfrost_afrc_clump_size(enum pipe_format format,bool scan)174 panfrost_afrc_clump_size(enum pipe_format format, bool scan)
175 {
176    struct pan_afrc_format_info finfo = panfrost_afrc_get_format_info(format);
177 
178    switch (finfo.num_comps) {
179    case 1:
180       return scan ? (struct pan_block_size){16, 4}
181                   : (struct pan_block_size){8, 8};
182    case 2:
183       return (struct pan_block_size){8, 4};
184    case 3:
185    case 4:
186       return (struct pan_block_size){4, 4};
187    default:
188       assert(0);
189       return (struct pan_block_size){0, 0};
190    }
191 }
192 
193 static struct pan_block_size
panfrost_afrc_layout_size(uint64_t modifier)194 panfrost_afrc_layout_size(uint64_t modifier)
195 {
196    if (panfrost_afrc_is_scan(modifier))
197       return (struct pan_block_size){16, 4};
198    else
199       return (struct pan_block_size){8, 8};
200 }
201 
202 struct pan_block_size
panfrost_afrc_tile_size(enum pipe_format format,uint64_t modifier)203 panfrost_afrc_tile_size(enum pipe_format format, uint64_t modifier)
204 {
205    bool scan = panfrost_afrc_is_scan(modifier);
206    struct pan_block_size clump_sz = panfrost_afrc_clump_size(format, scan);
207    struct pan_block_size layout_sz = panfrost_afrc_layout_size(modifier);
208 
209    return (struct pan_block_size){clump_sz.width * layout_sz.width,
210                                   clump_sz.height * layout_sz.height};
211 }
212 
213 unsigned
panfrost_afrc_block_size_from_modifier(uint64_t modifier)214 panfrost_afrc_block_size_from_modifier(uint64_t modifier)
215 {
216    switch (modifier & AFRC_FORMAT_MOD_CU_SIZE_MASK) {
217    case AFRC_FORMAT_MOD_CU_SIZE_16:
218       return 16;
219    case AFRC_FORMAT_MOD_CU_SIZE_24:
220       return 24;
221    case AFRC_FORMAT_MOD_CU_SIZE_32:
222       return 32;
223    default:
224       unreachable("invalid coding unit size flag in modifier");
225    };
226 }
227 
228 static unsigned
panfrost_afrc_buffer_alignment_from_modifier(uint64_t modifier)229 panfrost_afrc_buffer_alignment_from_modifier(uint64_t modifier)
230 {
231    switch (modifier & AFRC_FORMAT_MOD_CU_SIZE_MASK) {
232    case AFRC_FORMAT_MOD_CU_SIZE_16:
233       return 1024;
234    case AFRC_FORMAT_MOD_CU_SIZE_24:
235       return 512;
236    case AFRC_FORMAT_MOD_CU_SIZE_32:
237       return 2048;
238    default:
239       unreachable("invalid coding unit size flag in modifier");
240    };
241 }
242 
243 /*
244  * Determine the number of bytes between rows of paging tiles in an AFRC image
245  */
246 uint32_t
pan_afrc_row_stride(enum pipe_format format,uint64_t modifier,uint32_t width)247 pan_afrc_row_stride(enum pipe_format format, uint64_t modifier, uint32_t width)
248 {
249    struct pan_block_size tile_size = panfrost_afrc_tile_size(format, modifier);
250    unsigned block_size = panfrost_afrc_block_size_from_modifier(modifier);
251 
252    return (width / tile_size.width) * block_size * AFRC_CLUMPS_PER_TILE;
253 }
254 
255 /*
256  * Given a format, determine the tile size used for u-interleaving. For formats
257  * that are already block compressed, this is 4x4. For all other formats, this
258  * is 16x16, hence the modifier name.
259  */
260 static inline struct pan_block_size
panfrost_u_interleaved_tile_size(enum pipe_format format)261 panfrost_u_interleaved_tile_size(enum pipe_format format)
262 {
263    if (util_format_is_compressed(format))
264       return (struct pan_block_size){4, 4};
265    else
266       return (struct pan_block_size){16, 16};
267 }
268 
269 /*
270  * Determine the block size used for interleaving. For u-interleaving, this is
271  * the tile size. For AFBC, this is the superblock size. For AFRC, this is the
272  * paging tile size. For linear textures, this is trivially 1x1.
273  */
274 struct pan_block_size
panfrost_block_size(uint64_t modifier,enum pipe_format format)275 panfrost_block_size(uint64_t modifier, enum pipe_format format)
276 {
277    if (modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED)
278       return panfrost_u_interleaved_tile_size(format);
279    else if (drm_is_afbc(modifier))
280       return panfrost_afbc_superblock_size(modifier);
281    else if (drm_is_afrc(modifier))
282       return panfrost_afrc_tile_size(format, modifier);
283    else
284       return (struct pan_block_size){1, 1};
285 }
286 
287 /* For non-AFBC and non-wide AFBC, the render block size matches
288  * the block size, but for wide AFBC, the GPU wants the block height
289  * to be 16 pixels high.
290  */
291 struct pan_block_size
panfrost_renderblock_size(uint64_t modifier,enum pipe_format format)292 panfrost_renderblock_size(uint64_t modifier, enum pipe_format format)
293 {
294    if (!drm_is_afbc(modifier))
295       return panfrost_block_size(modifier, format);
296 
297    return panfrost_afbc_renderblock_size(modifier);
298 }
299 
300 /*
301  * Determine the tile size used by AFBC. This tiles superblocks themselves.
302  * Current GPUs support either 8x8 tiling or no tiling (1x1)
303  */
304 static inline unsigned
pan_afbc_tile_size(uint64_t modifier)305 pan_afbc_tile_size(uint64_t modifier)
306 {
307    return (modifier & AFBC_FORMAT_MOD_TILED) ? 8 : 1;
308 }
309 
310 /*
311  * Determine the number of bytes between header rows for an AFBC image. For an
312  * image with linear headers, this is simply the number of header blocks
313  * (=superblocks) per row times the numbers of bytes per header block. For an
314  * image with tiled headers, this is multipled by the number of rows of
315  * header blocks are in a tile together.
316  */
317 uint32_t
pan_afbc_row_stride(uint64_t modifier,uint32_t width)318 pan_afbc_row_stride(uint64_t modifier, uint32_t width)
319 {
320    unsigned block_width = panfrost_afbc_superblock_width(modifier);
321 
322    return (width / block_width) * pan_afbc_tile_size(modifier) *
323           AFBC_HEADER_BYTES_PER_TILE;
324 }
325 
326 /*
327  * Determine the number of header blocks between header rows. This is equal to
328  * the number of bytes between header rows divided by the bytes per blocks of a
329  * header tile. This is also divided by the tile size to give a "line stride" in
330  * blocks, rather than a real row stride. This is required by Bifrost.
331  */
332 uint32_t
pan_afbc_stride_blocks(uint64_t modifier,uint32_t row_stride_bytes)333 pan_afbc_stride_blocks(uint64_t modifier, uint32_t row_stride_bytes)
334 {
335    return row_stride_bytes /
336           (AFBC_HEADER_BYTES_PER_TILE * pan_afbc_tile_size(modifier));
337 }
338 
339 /*
340  * Determine the required alignment for the slice offset of an image. For
341  * now, this is always aligned on 64-byte boundaries. */
342 uint32_t
pan_slice_align(uint64_t modifier)343 pan_slice_align(uint64_t modifier)
344 {
345    return 64;
346 }
347 
348 /*
349  * Determine the required alignment for the body offset of an AFBC image. For
350  * now, this depends only on whether tiling is in use. These minimum alignments
351  * are required on all current GPUs.
352  */
353 uint32_t
pan_afbc_body_align(unsigned arch,uint64_t modifier)354 pan_afbc_body_align(unsigned arch, uint64_t modifier)
355 {
356    if (modifier & AFBC_FORMAT_MOD_TILED)
357       return 4096;
358 
359    if (arch >= 6)
360       return 128;
361 
362    return 64;
363 }
364 
365 static inline unsigned
format_minimum_alignment(unsigned arch,enum pipe_format format,uint64_t mod)366 format_minimum_alignment(unsigned arch, enum pipe_format format, uint64_t mod)
367 {
368    if (drm_is_afbc(mod))
369       return 16;
370 
371    if (drm_is_afrc(mod))
372       return panfrost_afrc_buffer_alignment_from_modifier(mod);
373 
374    if (arch < 7)
375       return 64;
376 
377    switch (format) {
378    /* For v7+, NV12/NV21/I420 have a looser alignment requirement of 16 bytes */
379    case PIPE_FORMAT_R8_G8B8_420_UNORM:
380    case PIPE_FORMAT_G8_B8R8_420_UNORM:
381    case PIPE_FORMAT_R8_G8_B8_420_UNORM:
382    case PIPE_FORMAT_R8_B8_G8_420_UNORM:
383    case PIPE_FORMAT_R8_G8B8_422_UNORM:
384    case PIPE_FORMAT_R8_B8G8_422_UNORM:
385       return 16;
386    /* the 10 bit formats have even looser alignment */
387    case PIPE_FORMAT_R10_G10B10_420_UNORM:
388    case PIPE_FORMAT_R10_G10B10_422_UNORM:
389       return 1;
390    default:
391       return 64;
392    }
393 }
394 
395 /*
396  * Computes sizes for checksumming, which is 8 bytes per 16x16 tile.
397  * Checksumming is believed to be a CRC variant (CRC64 based on the size?).
398  * This feature is also known as "transaction elimination".
399  * CRC values are prefetched by 32x32 regions so size needs to be aligned.
400  */
401 
402 #define CHECKSUM_TILE_WIDTH        16
403 #define CHECKSUM_TILE_HEIGHT       16
404 #define CHECKSUM_REGION_SIZE       32
405 #define CHECKSUM_X_TILE_PER_REGION (CHECKSUM_REGION_SIZE / CHECKSUM_TILE_WIDTH)
406 #define CHECKSUM_Y_TILE_PER_REGION (CHECKSUM_REGION_SIZE / CHECKSUM_TILE_HEIGHT)
407 #define CHECKSUM_BYTES_PER_TILE    8
408 
409 unsigned
panfrost_compute_checksum_size(struct pan_image_slice_layout * slice,unsigned width,unsigned height)410 panfrost_compute_checksum_size(struct pan_image_slice_layout *slice,
411                                unsigned width, unsigned height)
412 {
413    unsigned tile_count_x =
414       CHECKSUM_X_TILE_PER_REGION * DIV_ROUND_UP(width, CHECKSUM_REGION_SIZE);
415    unsigned tile_count_y =
416       CHECKSUM_Y_TILE_PER_REGION * DIV_ROUND_UP(height, CHECKSUM_REGION_SIZE);
417 
418    slice->crc.stride = tile_count_x * CHECKSUM_BYTES_PER_TILE;
419 
420    return slice->crc.stride * tile_count_y;
421 }
422 
423 unsigned
panfrost_get_layer_stride(const struct pan_image_layout * layout,unsigned level)424 panfrost_get_layer_stride(const struct pan_image_layout *layout, unsigned level)
425 {
426    if (layout->dim != MALI_TEXTURE_DIMENSION_3D)
427       return layout->array_stride;
428    else if (drm_is_afbc(layout->modifier))
429       return layout->slices[level].afbc.surface_stride;
430    else
431       return layout->slices[level].surface_stride;
432 }
433 
434 unsigned
panfrost_get_legacy_stride(const struct pan_image_layout * layout,unsigned level)435 panfrost_get_legacy_stride(const struct pan_image_layout *layout,
436                            unsigned level)
437 {
438    unsigned row_stride = layout->slices[level].row_stride;
439    struct pan_block_size block_size =
440       panfrost_renderblock_size(layout->modifier, layout->format);
441 
442    if (drm_is_afbc(layout->modifier)) {
443       unsigned width = u_minify(layout->width, level);
444       unsigned alignment =
445          block_size.width * pan_afbc_tile_size(layout->modifier);
446 
447       width = ALIGN_POT(width, alignment);
448       return width * util_format_get_blocksize(layout->format);
449    } else if (drm_is_afrc(layout->modifier)) {
450       struct pan_block_size tile_size =
451          panfrost_afrc_tile_size(layout->format, layout->modifier);
452 
453       return row_stride / tile_size.height;
454    } else {
455       return row_stride / block_size.height;
456    }
457 }
458 
459 unsigned
panfrost_from_legacy_stride(unsigned legacy_stride,enum pipe_format format,uint64_t modifier)460 panfrost_from_legacy_stride(unsigned legacy_stride, enum pipe_format format,
461                             uint64_t modifier)
462 {
463    struct pan_block_size block_size =
464       panfrost_renderblock_size(modifier, format);
465 
466    if (drm_is_afbc(modifier)) {
467       unsigned width = legacy_stride / util_format_get_blocksize(format);
468 
469       return pan_afbc_row_stride(modifier, width);
470    } else if (drm_is_afrc(modifier)) {
471       struct pan_block_size tile_size =
472          panfrost_afrc_tile_size(format, modifier);
473 
474       return legacy_stride * tile_size.height;
475    } else {
476       return legacy_stride * block_size.height;
477    }
478 }
479 
480 /* Computes the offset into a texture at a particular level/face. Add to
481  * the base address of a texture to get the address to that level/face */
482 
483 unsigned
panfrost_texture_offset(const struct pan_image_layout * layout,unsigned level,unsigned array_idx,unsigned surface_idx)484 panfrost_texture_offset(const struct pan_image_layout *layout, unsigned level,
485                         unsigned array_idx, unsigned surface_idx)
486 {
487    return layout->slices[level].offset + (array_idx * layout->array_stride) +
488           (surface_idx * layout->slices[level].surface_stride);
489 }
490 
491 bool
pan_image_layout_init(unsigned arch,struct pan_image_layout * layout,const struct pan_image_explicit_layout * explicit_layout)492 pan_image_layout_init(unsigned arch, struct pan_image_layout *layout,
493                       const struct pan_image_explicit_layout *explicit_layout)
494 {
495    /* Explicit stride only work with non-mipmap, non-array, single-sample
496     * 2D image without CRC.
497     */
498    if (explicit_layout &&
499        (layout->depth > 1 || layout->nr_samples > 1 || layout->array_size > 1 ||
500         layout->dim != MALI_TEXTURE_DIMENSION_2D || layout->nr_slices > 1 ||
501         layout->crc))
502       return false;
503 
504    bool afbc = drm_is_afbc(layout->modifier);
505    bool afrc = drm_is_afrc(layout->modifier);
506    int align_req =
507       format_minimum_alignment(arch, layout->format, layout->modifier);
508 
509    /* Mandate alignment */
510    if (explicit_layout) {
511       bool rejected = false;
512 
513       int align_mask = align_req - 1;
514 
515       if (arch >= 7) {
516          rejected = ((explicit_layout->offset & align_mask) ||
517                      (explicit_layout->row_stride & align_mask));
518       } else {
519          rejected = (explicit_layout->offset & align_mask);
520       }
521 
522       if (rejected) {
523          mesa_loge(
524             "panfrost: rejecting image due to unsupported offset or stride "
525             "alignment.\n");
526          return false;
527       }
528    }
529 
530    unsigned fmt_blocksize = util_format_get_blocksize(layout->format);
531 
532    /* MSAA is implemented as a 3D texture with z corresponding to the
533     * sample #, horrifyingly enough */
534 
535    assert(layout->depth == 1 || layout->nr_samples == 1);
536 
537    bool linear = layout->modifier == DRM_FORMAT_MOD_LINEAR;
538    bool is_3d = layout->dim == MALI_TEXTURE_DIMENSION_3D;
539 
540    uint64_t offset = explicit_layout ? explicit_layout->offset : 0;
541    struct pan_block_size renderblk_size =
542       panfrost_renderblock_size(layout->modifier, layout->format);
543    struct pan_block_size block_size =
544       panfrost_block_size(layout->modifier, layout->format);
545 
546    unsigned width = layout->width;
547    unsigned height = layout->height;
548    unsigned depth = layout->depth;
549 
550    unsigned align_w = renderblk_size.width;
551    unsigned align_h = renderblk_size.height;
552 
553    /* For tiled AFBC, align to tiles of superblocks (this can be large) */
554    if (afbc) {
555       align_w *= pan_afbc_tile_size(layout->modifier);
556       align_h *= pan_afbc_tile_size(layout->modifier);
557    }
558 
559    for (unsigned l = 0; l < layout->nr_slices; ++l) {
560       struct pan_image_slice_layout *slice = &layout->slices[l];
561 
562       unsigned effective_width =
563          ALIGN_POT(util_format_get_nblocksx(layout->format, width), align_w);
564       unsigned effective_height =
565          ALIGN_POT(util_format_get_nblocksy(layout->format, height), align_h);
566       unsigned row_stride;
567 
568       /* Align levels to cache-line as a performance improvement for
569        * linear/tiled and as a requirement for AFBC */
570 
571       offset = ALIGN_POT(offset, pan_slice_align(layout->modifier));
572 
573       slice->offset = offset;
574 
575       if (afrc) {
576          row_stride = pan_afrc_row_stride(layout->format, layout->modifier,
577                                           effective_width);
578       } else {
579          row_stride = fmt_blocksize * effective_width * block_size.height;
580       }
581 
582       /* On v7+ row_stride and offset alignment requirement are equal */
583       if (arch >= 7) {
584          row_stride = ALIGN_POT(row_stride, align_req);
585       }
586 
587       if (explicit_layout && !afbc && !afrc) {
588          /* Make sure the explicit stride is valid */
589          if (explicit_layout->row_stride < row_stride) {
590             mesa_loge("panfrost: rejecting image due to invalid row stride.\n");
591             return false;
592          }
593 
594          row_stride = explicit_layout->row_stride;
595       } else if (linear) {
596          /* Keep lines alignment on 64 byte for performance */
597          row_stride = ALIGN_POT(row_stride, 64);
598       }
599 
600       uint64_t slice_one_size =
601          (uint64_t)row_stride * (effective_height / block_size.height);
602 
603       /* Compute AFBC sizes if necessary */
604       if (afbc) {
605          slice->row_stride =
606             pan_afbc_row_stride(layout->modifier, effective_width);
607          slice->afbc.stride = effective_width / block_size.width;
608          slice->afbc.nr_blocks =
609             slice->afbc.stride * (effective_height / block_size.height);
610          slice->afbc.header_size =
611             ALIGN_POT(slice->afbc.nr_blocks * AFBC_HEADER_BYTES_PER_TILE,
612                       pan_afbc_body_align(arch, layout->modifier));
613 
614          if (explicit_layout &&
615              explicit_layout->row_stride < slice->row_stride) {
616             mesa_loge("panfrost: rejecting image due to invalid row stride.\n");
617             return false;
618          }
619 
620          /* AFBC body size */
621          slice->afbc.body_size = slice_one_size;
622 
623          /* 3D AFBC resources have all headers placed at the
624           * beginning instead of having them split per depth
625           * level
626           */
627          if (is_3d) {
628             slice->afbc.surface_stride = slice->afbc.header_size;
629             slice->afbc.header_size *= depth;
630             slice->afbc.body_size *= depth;
631             offset += slice->afbc.header_size;
632          } else {
633             slice_one_size += slice->afbc.header_size;
634             slice->afbc.surface_stride = slice_one_size;
635          }
636       } else {
637          slice->row_stride = row_stride;
638       }
639 
640       uint64_t slice_full_size = slice_one_size * depth * layout->nr_samples;
641 
642       slice->surface_stride = slice_one_size;
643 
644       /* Compute AFBC sizes if necessary */
645 
646       offset += slice_full_size;
647       slice->size = slice_full_size;
648 
649       /* Add a checksum region if necessary */
650       if (layout->crc) {
651          slice->crc.size = panfrost_compute_checksum_size(slice, width, height);
652 
653          slice->crc.offset = offset;
654          offset += slice->crc.size;
655          slice->size += slice->crc.size;
656       }
657 
658       width = u_minify(width, 1);
659       height = u_minify(height, 1);
660       depth = u_minify(depth, 1);
661    }
662 
663    /* Arrays and cubemaps have the entire miptree duplicated */
664    layout->array_stride = ALIGN_POT(offset, 64);
665    if (explicit_layout)
666       layout->data_size = offset;
667    else
668       layout->data_size = ALIGN_POT(
669          (uint64_t)layout->array_stride * (uint64_t)layout->array_size, 4096);
670 
671    return true;
672 }
673 
674 void
pan_iview_get_surface(const struct pan_image_view * iview,unsigned level,unsigned layer,unsigned sample,struct pan_surface * surf)675 pan_iview_get_surface(const struct pan_image_view *iview, unsigned level,
676                       unsigned layer, unsigned sample, struct pan_surface *surf)
677 {
678    const struct util_format_description *fdesc =
679       util_format_description(iview->format);
680 
681 
682    /* In case of multiplanar depth/stencil, the stencil is always on
683     * plane 1. Combined depth/stencil only has one plane, so depth
684     * will be on plane 0 in either case.
685     */
686    const struct pan_image *image = util_format_has_stencil(fdesc)
687       ? pan_image_view_get_s_plane(iview)
688       : pan_image_view_get_plane(iview, 0);
689 
690    level += iview->first_level;
691    assert(level < image->layout.nr_slices);
692 
693    layer += iview->first_layer;
694 
695    bool is_3d = image->layout.dim == MALI_TEXTURE_DIMENSION_3D;
696    const struct pan_image_slice_layout *slice = &image->layout.slices[level];
697    uint64_t base = image->data.base + image->data.offset;
698 
699    if (drm_is_afbc(image->layout.modifier)) {
700       assert(!sample);
701 
702       if (is_3d) {
703          ASSERTED unsigned depth = u_minify(image->layout.depth, level);
704          assert(layer < depth);
705          surf->afbc.header =
706             base + slice->offset + (layer * slice->afbc.surface_stride);
707          surf->afbc.body = base + slice->offset + slice->afbc.header_size +
708                            (slice->surface_stride * layer);
709       } else {
710          assert(layer < image->layout.array_size);
711          surf->afbc.header =
712             base + panfrost_texture_offset(&image->layout, level, layer, 0);
713          surf->afbc.body = surf->afbc.header + slice->afbc.header_size;
714       }
715    } else {
716       unsigned array_idx = is_3d ? 0 : layer;
717       unsigned surface_idx = is_3d ? layer : sample;
718 
719       surf->data = base + panfrost_texture_offset(&image->layout, level,
720                                                   array_idx, surface_idx);
721    }
722 }
723