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