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