Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/panfrost/lib/pan_texture.c
4560 views
1
/*
2
* Copyright (C) 2008 VMware, Inc.
3
* Copyright (C) 2014 Broadcom
4
* Copyright (C) 2018-2019 Alyssa Rosenzweig
5
* Copyright (C) 2019-2020 Collabora, Ltd.
6
*
7
* Permission is hereby granted, free of charge, to any person obtaining a
8
* copy of this software and associated documentation files (the "Software"),
9
* to deal in the Software without restriction, including without limitation
10
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
* and/or sell copies of the Software, and to permit persons to whom the
12
* Software is furnished to do so, subject to the following conditions:
13
*
14
* The above copyright notice and this permission notice (including the next
15
* paragraph) shall be included in all copies or substantial portions of the
16
* Software.
17
*
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
* SOFTWARE.
25
*
26
*/
27
28
#include "util/macros.h"
29
#include "util/u_math.h"
30
#include "pan_texture.h"
31
#include "panfrost-quirks.h"
32
33
/* Generates a texture descriptor. Ideally, descriptors are immutable after the
34
* texture is created, so we can keep these hanging around in GPU memory in a
35
* dedicated BO and not have to worry. In practice there are some minor gotchas
36
* with this (the driver sometimes will change the format of a texture on the
37
* fly for compression) but it's fast enough to just regenerate the descriptor
38
* in those cases, rather than monkeypatching at drawtime. A texture descriptor
39
* consists of a 32-byte header followed by pointers.
40
*/
41
42
/* List of supported modifiers, in descending order of preference. AFBC is
43
* faster than u-interleaved tiling which is faster than linear. Within AFBC,
44
* enabling the YUV-like transform is typically a win where possible. */
45
46
uint64_t pan_best_modifiers[PAN_MODIFIER_COUNT] = {
47
DRM_FORMAT_MOD_ARM_AFBC(
48
AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
49
AFBC_FORMAT_MOD_SPARSE |
50
AFBC_FORMAT_MOD_YTR),
51
52
DRM_FORMAT_MOD_ARM_AFBC(
53
AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
54
AFBC_FORMAT_MOD_SPARSE),
55
56
DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,
57
DRM_FORMAT_MOD_LINEAR
58
};
59
60
/* Check if we need to set a custom stride by computing the "expected"
61
* stride and comparing it to what the user actually wants. Only applies
62
* to linear textures, since tiled/compressed textures have strict
63
* alignment requirements for their strides as it is */
64
65
static bool
66
panfrost_needs_explicit_stride(const struct panfrost_device *dev,
67
const struct pan_image_view *iview)
68
{
69
/* Stride is explicit on Bifrost */
70
if (pan_is_bifrost(dev))
71
return true;
72
73
if (iview->image->layout.modifier != DRM_FORMAT_MOD_LINEAR)
74
return false;
75
76
unsigned bytes_per_block = util_format_get_blocksize(iview->format);
77
unsigned block_w = util_format_get_blockwidth(iview->format);
78
79
for (unsigned l = iview->first_level; l <= iview->last_level; ++l) {
80
unsigned actual = iview->image->layout.slices[l].line_stride;
81
unsigned expected =
82
DIV_ROUND_UP(u_minify(iview->image->layout.width, l), block_w) *
83
bytes_per_block;
84
85
if (actual != expected)
86
return true;
87
}
88
89
return false;
90
}
91
92
/* A Scalable Texture Compression (ASTC) corresponds to just a few texture type
93
* in the hardware, but in fact can be parametrized to have various widths and
94
* heights for the so-called "stretch factor". It turns out these parameters
95
* are stuffed in the bottom bits of the payload pointers. This functions
96
* computes these magic stuffing constants based on the ASTC format in use. The
97
* constant in a given dimension is 3-bits, and two are stored side-by-side for
98
* each active dimension.
99
*/
100
101
static unsigned
102
panfrost_astc_stretch(unsigned dim)
103
{
104
assert(dim >= 4 && dim <= 12);
105
return MIN2(dim, 11) - 4;
106
}
107
108
/* Texture addresses are tagged with information about compressed formats.
109
* AFBC uses a bit for whether the colorspace transform is enabled (RGB and
110
* RGBA only).
111
* For ASTC, this is a "stretch factor" encoding the block size. */
112
113
static unsigned
114
panfrost_compression_tag(const struct panfrost_device *dev,
115
const struct util_format_description *desc,
116
enum mali_texture_dimension dim,
117
uint64_t modifier)
118
{
119
if (drm_is_afbc(modifier)) {
120
unsigned flags = (modifier & AFBC_FORMAT_MOD_YTR) ?
121
MALI_AFBC_SURFACE_FLAG_YTR : 0;
122
123
if (!pan_is_bifrost(dev))
124
return flags;
125
126
/* Prefetch enable */
127
flags |= MALI_AFBC_SURFACE_FLAG_PREFETCH;
128
129
/* Wide blocks (> 16x16) */
130
if (panfrost_block_dim(modifier, true, 0) > 16)
131
flags |= MALI_AFBC_SURFACE_FLAG_WIDE_BLOCK;
132
133
/* Used to make sure AFBC headers don't point outside the AFBC
134
* body. HW is using the AFBC surface stride to do this check,
135
* which doesn't work for 3D textures because the surface
136
* stride does not cover the body. Only supported on v7+.
137
*/
138
if (dev->arch >= 7 && dim != MALI_TEXTURE_DIMENSION_3D)
139
flags |= MALI_AFBC_SURFACE_FLAG_CHECK_PAYLOAD_RANGE;
140
141
return flags;
142
} else if (desc->layout == UTIL_FORMAT_LAYOUT_ASTC) {
143
return (panfrost_astc_stretch(desc->block.height) << 3) |
144
panfrost_astc_stretch(desc->block.width);
145
} else {
146
return 0;
147
}
148
}
149
150
151
/* Cubemaps have 6 faces as "layers" in between each actual layer. We
152
* need to fix this up. TODO: logic wrong in the asserted out cases ...
153
* can they happen, perhaps from cubemap arrays? */
154
155
static void
156
panfrost_adjust_cube_dimensions(
157
unsigned *first_face, unsigned *last_face,
158
unsigned *first_layer, unsigned *last_layer)
159
{
160
*first_face = *first_layer % 6;
161
*last_face = *last_layer % 6;
162
*first_layer /= 6;
163
*last_layer /= 6;
164
165
assert((*first_layer == *last_layer) || (*first_face == 0 && *last_face == 5));
166
}
167
168
/* Following the texture descriptor is a number of pointers. How many? */
169
170
static unsigned
171
panfrost_texture_num_elements(
172
unsigned first_level, unsigned last_level,
173
unsigned first_layer, unsigned last_layer,
174
unsigned nr_samples,
175
bool is_cube, bool manual_stride)
176
{
177
unsigned first_face = 0, last_face = 0;
178
179
if (is_cube) {
180
panfrost_adjust_cube_dimensions(&first_face, &last_face,
181
&first_layer, &last_layer);
182
}
183
184
unsigned levels = 1 + last_level - first_level;
185
unsigned layers = 1 + last_layer - first_layer;
186
unsigned faces = 1 + last_face - first_face;
187
unsigned num_elements = levels * layers * faces * MAX2(nr_samples, 1);
188
189
if (manual_stride)
190
num_elements *= 2;
191
192
return num_elements;
193
}
194
195
/* Conservative estimate of the size of the texture payload a priori.
196
* Average case, size equal to the actual size. Worst case, off by 2x (if
197
* a manual stride is not needed on a linear texture). Returned value
198
* must be greater than or equal to the actual size, so it's safe to use
199
* as an allocation amount */
200
201
unsigned
202
panfrost_estimate_texture_payload_size(const struct panfrost_device *dev,
203
const struct pan_image_view *iview)
204
{
205
/* Assume worst case */
206
unsigned manual_stride = pan_is_bifrost(dev) ||
207
(iview->image->layout.modifier == DRM_FORMAT_MOD_LINEAR);
208
209
unsigned elements =
210
panfrost_texture_num_elements(iview->first_level, iview->last_level,
211
iview->first_layer, iview->last_layer,
212
iview->image->layout.nr_samples,
213
iview->dim == MALI_TEXTURE_DIMENSION_CUBE,
214
manual_stride);
215
216
return sizeof(mali_ptr) * elements;
217
}
218
219
/* If not explicitly, line stride is calculated for block-based formats as
220
* (ceil(width / block_width) * block_size). As a special case, this is left
221
* zero if there is only a single block vertically. So, we have a helper to
222
* extract the dimensions of a block-based format and use that to calculate the
223
* line stride as such.
224
*/
225
226
unsigned
227
panfrost_block_dim(uint64_t modifier, bool width, unsigned plane)
228
{
229
if (!drm_is_afbc(modifier)) {
230
assert(modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED);
231
return 16;
232
}
233
234
switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
235
case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
236
return 16;
237
case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
238
return width ? 32 : 8;
239
case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
240
return width ? 64 : 4;
241
case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
242
return plane ? (width ? 64 : 4) : (width ? 32 : 8);
243
default:
244
unreachable("Invalid AFBC block size");
245
}
246
}
247
248
static void
249
panfrost_get_surface_strides(const struct panfrost_device *dev,
250
const struct pan_image_layout *layout,
251
unsigned l,
252
int32_t *row_stride, int32_t *surf_stride)
253
{
254
const struct pan_image_slice_layout *slice = &layout->slices[l];
255
256
if (drm_is_afbc(layout->modifier)) {
257
/* Pre v7 don't have a row stride field. This field is
258
* repurposed as a Y offset which we don't use */
259
*row_stride = dev->arch < 7 ? 0 : slice->afbc.row_stride;
260
*surf_stride = slice->afbc.surface_stride;
261
} else {
262
*row_stride = slice->row_stride;
263
*surf_stride = slice->surface_stride;
264
}
265
}
266
267
static mali_ptr
268
panfrost_get_surface_pointer(const struct pan_image_layout *layout,
269
enum mali_texture_dimension dim,
270
mali_ptr base,
271
unsigned l, unsigned w, unsigned f, unsigned s)
272
{
273
unsigned face_mult = dim == MALI_TEXTURE_DIMENSION_CUBE ? 6 : 1;
274
unsigned offset;
275
276
if (layout->dim == MALI_TEXTURE_DIMENSION_3D) {
277
assert(!f && !s);
278
offset = layout->slices[l].offset +
279
(w * panfrost_get_layer_stride(layout, l));
280
} else {
281
offset = panfrost_texture_offset(layout, l, (w * face_mult) + f, s);
282
}
283
284
return base + offset;
285
}
286
287
struct panfrost_surface_iter {
288
unsigned layer, last_layer;
289
unsigned level, first_level, last_level;
290
unsigned face, first_face, last_face;
291
unsigned sample, first_sample, last_sample;
292
};
293
294
static void
295
panfrost_surface_iter_begin(struct panfrost_surface_iter *iter,
296
unsigned first_layer, unsigned last_layer,
297
unsigned first_level, unsigned last_level,
298
unsigned first_face, unsigned last_face,
299
unsigned nr_samples)
300
{
301
iter->layer = first_layer;
302
iter->last_layer = last_layer;
303
iter->level = iter->first_level = first_level;
304
iter->last_level = last_level;
305
iter->face = iter->first_face = first_face;
306
iter->last_face = last_face;
307
iter->sample = iter->first_sample = 0;
308
iter->last_sample = nr_samples - 1;
309
}
310
311
static bool
312
panfrost_surface_iter_end(const struct panfrost_surface_iter *iter)
313
{
314
return iter->layer > iter->last_layer;
315
}
316
317
static void
318
panfrost_surface_iter_next(const struct panfrost_device *dev,
319
struct panfrost_surface_iter *iter)
320
{
321
#define INC_TEST(field) \
322
do { \
323
if (iter->field++ < iter->last_ ## field) \
324
return; \
325
iter->field = iter->first_ ## field; \
326
} while (0)
327
328
/* Ordering is different on v7: inner loop is iterating on levels */
329
if (dev->arch >= 7)
330
INC_TEST(level);
331
332
INC_TEST(sample);
333
INC_TEST(face);
334
335
if (dev->arch < 7)
336
INC_TEST(level);
337
338
iter->layer++;
339
340
#undef INC_TEST
341
}
342
343
static void
344
panfrost_emit_texture_payload(const struct panfrost_device *dev,
345
const struct pan_image_view *iview,
346
enum pipe_format format,
347
bool manual_stride,
348
void *payload)
349
{
350
const struct pan_image_layout *layout = &iview->image->layout;
351
const struct util_format_description *desc =
352
util_format_description(format);
353
354
mali_ptr base = iview->image->data.bo->ptr.gpu + iview->image->data.offset;
355
356
if (iview->buf.size) {
357
assert (iview->dim == MALI_TEXTURE_DIMENSION_1D);
358
base += iview->buf.offset;
359
}
360
361
/* panfrost_compression_tag() wants the dimension of the resource, not the
362
* one of the image view (those might differ).
363
*/
364
base |= panfrost_compression_tag(dev, desc, layout->dim, layout->modifier);
365
366
/* Inject the addresses in, interleaving array indices, mip levels,
367
* cube faces, and strides in that order */
368
369
unsigned first_layer = iview->first_layer, last_layer = iview->last_layer;
370
unsigned nr_samples = layout->nr_samples;
371
unsigned first_face = 0, last_face = 0;
372
373
if (iview->dim == MALI_TEXTURE_DIMENSION_CUBE) {
374
panfrost_adjust_cube_dimensions(&first_face, &last_face,
375
&first_layer, &last_layer);
376
}
377
378
struct panfrost_surface_iter iter;
379
380
for (panfrost_surface_iter_begin(&iter, first_layer, last_layer,
381
iview->first_level, iview->last_level,
382
first_face, last_face, nr_samples);
383
!panfrost_surface_iter_end(&iter);
384
panfrost_surface_iter_next(dev, &iter)) {
385
mali_ptr pointer =
386
panfrost_get_surface_pointer(layout, iview->dim, base,
387
iter.level, iter.layer,
388
iter.face, iter.sample);
389
390
if (!manual_stride) {
391
pan_pack(payload, SURFACE, cfg) {
392
cfg.pointer = pointer;
393
}
394
payload += MALI_SURFACE_LENGTH;
395
} else {
396
pan_pack(payload, SURFACE_WITH_STRIDE, cfg) {
397
cfg.pointer = pointer;
398
panfrost_get_surface_strides(dev, layout, iter.level,
399
&cfg.row_stride,
400
&cfg.surface_stride);
401
}
402
payload += MALI_SURFACE_WITH_STRIDE_LENGTH;
403
}
404
}
405
}
406
407
void
408
panfrost_new_texture(const struct panfrost_device *dev,
409
const struct pan_image_view *iview,
410
void *out, const struct panfrost_ptr *payload)
411
{
412
const struct pan_image_layout *layout = &iview->image->layout;
413
enum pipe_format format = iview->format;
414
unsigned swizzle;
415
416
if (dev->arch == 7 && util_format_is_depth_or_stencil(format)) {
417
/* v7 doesn't have an _RRRR component order, combine the
418
* user swizzle with a .XXXX swizzle to emulate that.
419
*/
420
static const unsigned char replicate_x[4] = {
421
PIPE_SWIZZLE_X, PIPE_SWIZZLE_X,
422
PIPE_SWIZZLE_X, PIPE_SWIZZLE_X,
423
};
424
unsigned char patched_swizzle[4];
425
426
util_format_compose_swizzles(replicate_x,
427
iview->swizzle,
428
patched_swizzle);
429
swizzle = panfrost_translate_swizzle_4(patched_swizzle);
430
} else {
431
swizzle = panfrost_translate_swizzle_4(iview->swizzle);
432
}
433
434
bool manual_stride =
435
panfrost_needs_explicit_stride(dev, iview);
436
437
panfrost_emit_texture_payload(dev, iview, format,
438
manual_stride,
439
payload->cpu);
440
441
unsigned array_size = iview->last_layer - iview->first_layer + 1;
442
443
if (iview->dim == MALI_TEXTURE_DIMENSION_CUBE) {
444
assert(iview->first_layer % 6 == 0);
445
assert(iview->last_layer % 6 == 5);
446
array_size /= 6;
447
}
448
449
unsigned width;
450
451
if (iview->buf.size) {
452
assert(iview->dim == MALI_TEXTURE_DIMENSION_1D);
453
assert(!iview->first_level && !iview->last_level);
454
assert(!iview->first_layer && !iview->last_layer);
455
assert(layout->nr_samples == 1);
456
assert(layout->height == 1 && layout->depth == 1);
457
assert(iview->buf.offset + iview->buf.size <= layout->width);
458
width = iview->buf.size;
459
} else {
460
width = u_minify(layout->width, iview->first_level);
461
}
462
463
if (pan_is_bifrost(dev)) {
464
pan_pack(out, BIFROST_TEXTURE, cfg) {
465
cfg.dimension = iview->dim;
466
cfg.format = dev->formats[format].hw;
467
cfg.width = width;
468
cfg.height = u_minify(layout->height, iview->first_level);
469
if (iview->dim == MALI_TEXTURE_DIMENSION_3D)
470
cfg.depth = u_minify(layout->depth, iview->first_level);
471
else
472
cfg.sample_count = layout->nr_samples;
473
cfg.swizzle = swizzle;
474
cfg.texel_ordering =
475
panfrost_modifier_to_layout(layout->modifier);
476
cfg.levels = iview->last_level - iview->first_level + 1;
477
cfg.array_size = array_size;
478
cfg.surfaces = payload->gpu;
479
480
/* We specify API-level LOD clamps in the sampler descriptor
481
* and use these clamps simply for bounds checking */
482
cfg.minimum_lod = FIXED_16(0, false);
483
cfg.maximum_lod = FIXED_16(cfg.levels - 1, false);
484
}
485
} else {
486
pan_pack(out, MIDGARD_TEXTURE, cfg) {
487
cfg.width = width;
488
cfg.height = u_minify(layout->height, iview->first_level);
489
if (iview->dim == MALI_TEXTURE_DIMENSION_3D)
490
cfg.depth = u_minify(layout->depth, iview->first_level);
491
else
492
cfg.sample_count = layout->nr_samples;
493
cfg.array_size = array_size;
494
cfg.format = panfrost_pipe_format_v6[format].hw;
495
cfg.dimension = iview->dim;
496
cfg.texel_ordering =
497
panfrost_modifier_to_layout(layout->modifier);
498
cfg.manual_stride = manual_stride;
499
cfg.levels = iview->last_level - iview->first_level + 1;
500
cfg.swizzle = swizzle;
501
};
502
}
503
}
504
505
/* Computes sizes for checksumming, which is 8 bytes per 16x16 tile.
506
* Checksumming is believed to be a CRC variant (CRC64 based on the size?).
507
* This feature is also known as "transaction elimination". */
508
509
#define CHECKSUM_TILE_WIDTH 16
510
#define CHECKSUM_TILE_HEIGHT 16
511
#define CHECKSUM_BYTES_PER_TILE 8
512
513
unsigned
514
panfrost_compute_checksum_size(
515
struct pan_image_slice_layout *slice,
516
unsigned width,
517
unsigned height)
518
{
519
unsigned tile_count_x = DIV_ROUND_UP(width, CHECKSUM_TILE_WIDTH);
520
unsigned tile_count_y = DIV_ROUND_UP(height, CHECKSUM_TILE_HEIGHT);
521
522
slice->crc.stride = tile_count_x * CHECKSUM_BYTES_PER_TILE;
523
524
return slice->crc.stride * tile_count_y;
525
}
526
527
unsigned
528
panfrost_get_layer_stride(const struct pan_image_layout *layout,
529
unsigned level)
530
{
531
if (layout->dim != MALI_TEXTURE_DIMENSION_3D)
532
return layout->array_stride;
533
else if (drm_is_afbc(layout->modifier))
534
return layout->slices[level].afbc.surface_stride;
535
else
536
return layout->slices[level].surface_stride;
537
}
538
539
/* Computes the offset into a texture at a particular level/face. Add to
540
* the base address of a texture to get the address to that level/face */
541
542
unsigned
543
panfrost_texture_offset(const struct pan_image_layout *layout,
544
unsigned level, unsigned array_idx,
545
unsigned surface_idx)
546
{
547
return layout->slices[level].offset +
548
(array_idx * layout->array_stride) +
549
(surface_idx * layout->slices[level].surface_stride);
550
}
551
552
bool
553
pan_image_layout_init(const struct panfrost_device *dev,
554
struct pan_image_layout *layout,
555
uint64_t modifier,
556
enum pipe_format format,
557
enum mali_texture_dimension dim,
558
unsigned width, unsigned height, unsigned depth,
559
unsigned array_size, unsigned nr_samples,
560
unsigned nr_slices, enum pan_image_crc_mode crc_mode,
561
const struct pan_image_explicit_layout *explicit_layout)
562
{
563
/* Explicit stride only work with non-mipmap, non-array; single-sample
564
* 2D image, and in-band CRC can't be used.
565
*/
566
if (explicit_layout &&
567
(depth > 1 || nr_samples > 1 || array_size > 1 ||
568
dim != MALI_TEXTURE_DIMENSION_2D || nr_slices > 1 ||
569
crc_mode == PAN_IMAGE_CRC_INBAND))
570
return false;
571
572
/* Mandate 64 byte alignement */
573
if (explicit_layout && (explicit_layout->offset & 63))
574
return false;
575
576
layout->crc_mode = crc_mode;
577
layout->modifier = modifier;
578
layout->format = format;
579
layout->dim = dim;
580
layout->width = width;
581
layout->height = height;
582
layout->depth = depth;
583
layout->array_size = array_size;
584
layout->nr_samples = nr_samples;
585
layout->nr_slices = nr_slices;
586
587
unsigned bytes_per_pixel = util_format_get_blocksize(format);
588
589
/* MSAA is implemented as a 3D texture with z corresponding to the
590
* sample #, horrifyingly enough */
591
592
assert(depth == 1 || nr_samples == 1);
593
594
bool afbc = drm_is_afbc(layout->modifier);
595
bool tiled = layout->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
596
bool linear = layout->modifier == DRM_FORMAT_MOD_LINEAR;
597
bool should_align = tiled || afbc;
598
bool is_3d = layout->dim == MALI_TEXTURE_DIMENSION_3D;
599
600
unsigned oob_crc_offset = 0;
601
unsigned offset = explicit_layout ? explicit_layout->offset : 0;
602
unsigned tile_h = 1, tile_w = 1, tile_shift = 0;
603
604
if (tiled || afbc) {
605
tile_w = panfrost_block_dim(layout->modifier, true, 0);
606
tile_h = panfrost_block_dim(layout->modifier, false, 0);
607
if (util_format_is_compressed(format))
608
tile_shift = 2;
609
}
610
611
for (unsigned l = 0; l < nr_slices; ++l) {
612
struct pan_image_slice_layout *slice = &layout->slices[l];
613
614
unsigned effective_width = width;
615
unsigned effective_height = height;
616
unsigned effective_depth = depth;
617
618
if (should_align) {
619
effective_width = ALIGN_POT(effective_width, tile_w) >> tile_shift;
620
effective_height = ALIGN_POT(effective_height, tile_h);
621
622
/* We don't need to align depth */
623
}
624
625
/* Align levels to cache-line as a performance improvement for
626
* linear/tiled and as a requirement for AFBC */
627
628
offset = ALIGN_POT(offset, 64);
629
630
slice->offset = offset;
631
632
/* Compute the would-be stride */
633
unsigned stride = bytes_per_pixel * effective_width;
634
635
if (explicit_layout) {
636
/* Make sure the explicit stride is valid */
637
if (explicit_layout->line_stride < stride)
638
return false;
639
640
stride = explicit_layout->line_stride;
641
} else if (linear) {
642
/* Keep lines alignment on 64 byte for performance */
643
stride = ALIGN_POT(stride, 64);
644
}
645
646
slice->line_stride = stride;
647
slice->row_stride = stride * (tile_h >> tile_shift);
648
649
unsigned slice_one_size = slice->line_stride * effective_height;
650
651
/* Compute AFBC sizes if necessary */
652
if (afbc) {
653
slice->afbc.header_size =
654
panfrost_afbc_header_size(width, height);
655
656
/* Stride between two rows of AFBC headers */
657
slice->afbc.row_stride =
658
(effective_width / tile_w) *
659
AFBC_HEADER_BYTES_PER_TILE;
660
661
/* AFBC body size */
662
slice->afbc.body_size = slice_one_size;
663
664
/* 3D AFBC resources have all headers placed at the
665
* beginning instead of having them split per depth
666
* level
667
*/
668
if (is_3d) {
669
slice->afbc.surface_stride =
670
slice->afbc.header_size;
671
slice->afbc.header_size *= effective_depth;
672
slice->afbc.body_size *= effective_depth;
673
offset += slice->afbc.header_size;
674
} else {
675
slice_one_size += slice->afbc.header_size;
676
slice->afbc.surface_stride = slice_one_size;
677
}
678
}
679
680
unsigned slice_full_size =
681
slice_one_size * effective_depth * nr_samples;
682
683
slice->surface_stride = slice_one_size;
684
685
/* Compute AFBC sizes if necessary */
686
687
offset += slice_full_size;
688
slice->size = slice_full_size;
689
690
/* Add a checksum region if necessary */
691
if (crc_mode != PAN_IMAGE_CRC_NONE) {
692
slice->crc.size =
693
panfrost_compute_checksum_size(slice, width, height);
694
695
if (crc_mode == PAN_IMAGE_CRC_INBAND) {
696
slice->crc.offset = offset;
697
offset += slice->crc.size;
698
slice->size += slice->crc.size;
699
} else {
700
slice->crc.offset = oob_crc_offset;
701
oob_crc_offset += slice->crc.size;
702
}
703
}
704
705
width = u_minify(width, 1);
706
height = u_minify(height, 1);
707
depth = u_minify(depth, 1);
708
}
709
710
/* Arrays and cubemaps have the entire miptree duplicated */
711
layout->array_stride = ALIGN_POT(offset, 64);
712
if (explicit_layout)
713
layout->data_size = offset;
714
else
715
layout->data_size = ALIGN_POT(layout->array_stride * array_size, 4096);
716
layout->crc_size = oob_crc_offset;
717
718
return true;
719
}
720
721
void
722
pan_iview_get_surface(const struct pan_image_view *iview,
723
unsigned level, unsigned layer, unsigned sample,
724
struct pan_surface *surf)
725
{
726
level += iview->first_level;
727
assert(level < iview->image->layout.nr_slices);
728
729
layer += iview->first_layer;
730
731
bool is_3d = iview->image->layout.dim == MALI_TEXTURE_DIMENSION_3D;
732
const struct pan_image_slice_layout *slice = &iview->image->layout.slices[level];
733
mali_ptr base = iview->image->data.bo->ptr.gpu + iview->image->data.offset;
734
735
if (drm_is_afbc(iview->image->layout.modifier)) {
736
assert(!sample);
737
738
if (is_3d) {
739
ASSERTED unsigned depth = u_minify(iview->image->layout.depth, level);
740
assert(layer < depth);
741
surf->afbc.header = base + slice->offset +
742
(layer * slice->afbc.surface_stride);
743
surf->afbc.body = base + slice->offset +
744
slice->afbc.header_size +
745
(slice->surface_stride * layer);
746
} else {
747
assert(layer < iview->image->layout.array_size);
748
surf->afbc.header = base +
749
panfrost_texture_offset(&iview->image->layout,
750
level, layer, 0);
751
surf->afbc.body = surf->afbc.header + slice->afbc.header_size;
752
}
753
} else {
754
unsigned array_idx = is_3d ? 0 : layer;
755
unsigned surface_idx = is_3d ? layer : sample;
756
757
surf->data = base +
758
panfrost_texture_offset(&iview->image->layout, level,
759
array_idx, surface_idx);
760
}
761
}
762
763