Alyssa Rosenzweig | 5ddf7ad | 2020-02-18 12:07:47 -0500 | [diff] [blame] | 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" |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 29 | #include "util/u_math.h" |
Alyssa Rosenzweig | 5ddf7ad | 2020-02-18 12:07:47 -0500 | [diff] [blame] | 30 | #include "pan_texture.h" |
Boris Brezillon | fefb3e9 | 2020-09-23 11:08:02 +0200 | [diff] [blame] | 31 | #include "panfrost-quirks.h" |
Alyssa Rosenzweig | 5ddf7ad | 2020-02-18 12:07:47 -0500 | [diff] [blame] | 32 | |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 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 |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 38 | * in those cases, rather than monkeypatching at drawtime. A texture descriptor |
| 39 | * consists of a 32-byte header followed by pointers. |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 40 | */ |
| 41 | |
Alyssa Rosenzweig | 348d374 | 2020-07-20 18:03:56 -0400 | [diff] [blame] | 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 | |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 60 | /* Map modifiers to mali_texture_layout for packing in a texture descriptor */ |
| 61 | |
| 62 | static enum mali_texture_layout |
| 63 | panfrost_modifier_to_layout(uint64_t modifier) |
| 64 | { |
| 65 | if (drm_is_afbc(modifier)) |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 66 | return MALI_TEXTURE_LAYOUT_AFBC; |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 67 | else if (modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 68 | return MALI_TEXTURE_LAYOUT_TILED; |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 69 | else if (modifier == DRM_FORMAT_MOD_LINEAR) |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 70 | return MALI_TEXTURE_LAYOUT_LINEAR; |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 71 | else |
| 72 | unreachable("Invalid modifer"); |
| 73 | } |
| 74 | |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 75 | /* Check if we need to set a custom stride by computing the "expected" |
| 76 | * stride and comparing it to what the user actually wants. Only applies |
| 77 | * to linear textures, since tiled/compressed textures have strict |
| 78 | * alignment requirements for their strides as it is */ |
| 79 | |
| 80 | static bool |
| 81 | panfrost_needs_explicit_stride( |
| 82 | struct panfrost_slice *slices, |
| 83 | uint16_t width, |
| 84 | unsigned first_level, unsigned last_level, |
| 85 | unsigned bytes_per_pixel) |
| 86 | { |
| 87 | for (unsigned l = first_level; l <= last_level; ++l) { |
| 88 | unsigned actual = slices[l].stride; |
| 89 | unsigned expected = u_minify(width, l) * bytes_per_pixel; |
| 90 | |
| 91 | if (actual != expected) |
| 92 | return true; |
| 93 | } |
| 94 | |
| 95 | return false; |
| 96 | } |
| 97 | |
| 98 | /* A Scalable Texture Compression (ASTC) corresponds to just a few texture type |
| 99 | * in the hardware, but in fact can be parametrized to have various widths and |
| 100 | * heights for the so-called "stretch factor". It turns out these parameters |
| 101 | * are stuffed in the bottom bits of the payload pointers. This functions |
| 102 | * computes these magic stuffing constants based on the ASTC format in use. The |
| 103 | * constant in a given dimension is 3-bits, and two are stored side-by-side for |
| 104 | * each active dimension. |
| 105 | */ |
| 106 | |
| 107 | static unsigned |
| 108 | panfrost_astc_stretch(unsigned dim) |
| 109 | { |
| 110 | assert(dim >= 4 && dim <= 12); |
| 111 | return MIN2(dim, 11) - 4; |
| 112 | } |
| 113 | |
Icecream95 | 99446c9 | 2020-06-02 14:14:12 +1200 | [diff] [blame] | 114 | /* Texture addresses are tagged with information about compressed formats. |
| 115 | * AFBC uses a bit for whether the colorspace transform is enabled (RGB and |
| 116 | * RGBA only). |
| 117 | * For ASTC, this is a "stretch factor" encoding the block size. */ |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 118 | |
| 119 | static unsigned |
| 120 | panfrost_compression_tag( |
| 121 | const struct util_format_description *desc, |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 122 | enum mali_format format, uint64_t modifier) |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 123 | { |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 124 | if (drm_is_afbc(modifier)) |
| 125 | return (modifier & AFBC_FORMAT_MOD_YTR) ? 1 : 0; |
Alyssa Rosenzweig | d5a9cd1 | 2020-07-10 10:17:44 -0400 | [diff] [blame] | 126 | else if (format == MALI_ASTC_2D_LDR || format == MALI_ASTC_2D_HDR) |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 127 | return (panfrost_astc_stretch(desc->block.height) << 3) | |
| 128 | panfrost_astc_stretch(desc->block.width); |
| 129 | else |
| 130 | return 0; |
| 131 | } |
| 132 | |
| 133 | |
| 134 | /* Cubemaps have 6 faces as "layers" in between each actual layer. We |
| 135 | * need to fix this up. TODO: logic wrong in the asserted out cases ... |
| 136 | * can they happen, perhaps from cubemap arrays? */ |
| 137 | |
| 138 | static void |
| 139 | panfrost_adjust_cube_dimensions( |
| 140 | unsigned *first_face, unsigned *last_face, |
| 141 | unsigned *first_layer, unsigned *last_layer) |
| 142 | { |
| 143 | *first_face = *first_layer % 6; |
| 144 | *last_face = *last_layer % 6; |
| 145 | *first_layer /= 6; |
| 146 | *last_layer /= 6; |
| 147 | |
| 148 | assert((*first_layer == *last_layer) || (*first_face == 0 && *last_face == 5)); |
| 149 | } |
| 150 | |
| 151 | /* Following the texture descriptor is a number of pointers. How many? */ |
| 152 | |
| 153 | static unsigned |
| 154 | panfrost_texture_num_elements( |
| 155 | unsigned first_level, unsigned last_level, |
| 156 | unsigned first_layer, unsigned last_layer, |
Alyssa Rosenzweig | 6088891 | 2020-07-15 11:39:08 -0400 | [diff] [blame] | 157 | unsigned nr_samples, |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 158 | bool is_cube, bool manual_stride) |
| 159 | { |
| 160 | unsigned first_face = 0, last_face = 0; |
| 161 | |
| 162 | if (is_cube) { |
| 163 | panfrost_adjust_cube_dimensions(&first_face, &last_face, |
| 164 | &first_layer, &last_layer); |
| 165 | } |
| 166 | |
| 167 | unsigned levels = 1 + last_level - first_level; |
| 168 | unsigned layers = 1 + last_layer - first_layer; |
| 169 | unsigned faces = 1 + last_face - first_face; |
Alyssa Rosenzweig | 6088891 | 2020-07-15 11:39:08 -0400 | [diff] [blame] | 170 | unsigned num_elements = levels * layers * faces * MAX2(nr_samples, 1); |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 171 | |
| 172 | if (manual_stride) |
| 173 | num_elements *= 2; |
| 174 | |
| 175 | return num_elements; |
| 176 | } |
| 177 | |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 178 | /* Conservative estimate of the size of the texture payload a priori. |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 179 | * Average case, size equal to the actual size. Worst case, off by 2x (if |
| 180 | * a manual stride is not needed on a linear texture). Returned value |
| 181 | * must be greater than or equal to the actual size, so it's safe to use |
| 182 | * as an allocation amount */ |
| 183 | |
| 184 | unsigned |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 185 | panfrost_estimate_texture_payload_size( |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 186 | unsigned first_level, unsigned last_level, |
| 187 | unsigned first_layer, unsigned last_layer, |
Alyssa Rosenzweig | 6088891 | 2020-07-15 11:39:08 -0400 | [diff] [blame] | 188 | unsigned nr_samples, |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 189 | enum mali_texture_dimension dim, uint64_t modifier) |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 190 | { |
| 191 | /* Assume worst case */ |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 192 | unsigned manual_stride = (modifier == DRM_FORMAT_MOD_LINEAR); |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 193 | |
| 194 | unsigned elements = panfrost_texture_num_elements( |
| 195 | first_level, last_level, |
| 196 | first_layer, last_layer, |
Alyssa Rosenzweig | 6088891 | 2020-07-15 11:39:08 -0400 | [diff] [blame] | 197 | nr_samples, |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 198 | dim == MALI_TEXTURE_DIMENSION_CUBE, manual_stride); |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 199 | |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 200 | return sizeof(mali_ptr) * elements; |
| 201 | } |
| 202 | |
Alyssa Rosenzweig | 5363719 | 2020-10-08 18:35:17 -0400 | [diff] [blame] | 203 | /* If not explicitly, line stride is calculated for block-based formats as |
| 204 | * (ceil(width / block_width) * block_size). As a special case, this is left |
| 205 | * zero if there is only a single block vertically. So, we have a helper to |
| 206 | * extract the dimensions of a block-based format and use that to calculate the |
| 207 | * line stride as such. |
Alyssa Rosenzweig | bde19c0 | 2020-04-30 18:48:53 -0400 | [diff] [blame] | 208 | */ |
| 209 | |
| 210 | static unsigned |
Alyssa Rosenzweig | 8bb1d61 | 2020-10-08 18:34:48 -0400 | [diff] [blame] | 211 | panfrost_block_dim(uint64_t modifier, bool width, unsigned plane) |
| 212 | { |
| 213 | if (!drm_is_afbc(modifier)) { |
| 214 | assert(modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED); |
| 215 | return 16; |
| 216 | } |
| 217 | |
| 218 | switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) { |
| 219 | case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: |
| 220 | return 16; |
| 221 | case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: |
Vinson Lee | 85053c0 | 2020-10-15 16:14:16 -0700 | [diff] [blame] | 222 | return width ? 32 : 8; |
Alyssa Rosenzweig | 8bb1d61 | 2020-10-08 18:34:48 -0400 | [diff] [blame] | 223 | case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: |
| 224 | return width ? 64 : 4; |
| 225 | case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4: |
| 226 | return plane ? (width ? 64 : 4) : (width ? 32 : 8); |
| 227 | default: |
| 228 | unreachable("Invalid AFBC block size"); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | static unsigned |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 233 | panfrost_nonlinear_stride(uint64_t modifier, |
Alyssa Rosenzweig | f42eb33 | 2020-10-08 18:51:43 -0400 | [diff] [blame] | 234 | unsigned bytes_per_block, |
| 235 | unsigned pixels_per_block, |
Alyssa Rosenzweig | 92553b6 | 2020-06-15 12:42:40 -0400 | [diff] [blame] | 236 | unsigned width, |
Alyssa Rosenzweig | 5363719 | 2020-10-08 18:35:17 -0400 | [diff] [blame] | 237 | unsigned height, |
| 238 | bool plane) |
Alyssa Rosenzweig | bde19c0 | 2020-04-30 18:48:53 -0400 | [diff] [blame] | 239 | { |
Alyssa Rosenzweig | 5363719 | 2020-10-08 18:35:17 -0400 | [diff] [blame] | 240 | unsigned block_w = panfrost_block_dim(modifier, true, plane); |
| 241 | unsigned block_h = panfrost_block_dim(modifier, false, plane); |
Alyssa Rosenzweig | f42eb33 | 2020-10-08 18:51:43 -0400 | [diff] [blame] | 242 | |
| 243 | /* Calculate block size. Ensure the division happens only at the end to |
| 244 | * avoid rounding errors if bytes per block < pixels per block */ |
| 245 | |
| 246 | unsigned block_size = (block_w * block_h * bytes_per_block) |
| 247 | / pixels_per_block; |
Alyssa Rosenzweig | 5363719 | 2020-10-08 18:35:17 -0400 | [diff] [blame] | 248 | |
| 249 | if (height <= block_h) |
| 250 | return 0; |
| 251 | else |
| 252 | return DIV_ROUND_UP(width, block_w) * block_size; |
Alyssa Rosenzweig | bde19c0 | 2020-04-30 18:48:53 -0400 | [diff] [blame] | 253 | } |
| 254 | |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 255 | static void |
| 256 | panfrost_emit_texture_payload( |
| 257 | mali_ptr *payload, |
| 258 | const struct util_format_description *desc, |
| 259 | enum mali_format mali_format, |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 260 | enum mali_texture_dimension dim, |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 261 | uint64_t modifier, |
Alyssa Rosenzweig | 92553b6 | 2020-06-15 12:42:40 -0400 | [diff] [blame] | 262 | unsigned width, unsigned height, |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 263 | unsigned first_level, unsigned last_level, |
| 264 | unsigned first_layer, unsigned last_layer, |
Alyssa Rosenzweig | 41c06de | 2020-06-30 16:43:32 -0400 | [diff] [blame] | 265 | unsigned nr_samples, |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 266 | unsigned cube_stride, |
| 267 | bool manual_stride, |
| 268 | mali_ptr base, |
| 269 | struct panfrost_slice *slices) |
| 270 | { |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 271 | base |= panfrost_compression_tag(desc, mali_format, modifier); |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 272 | |
| 273 | /* Inject the addresses in, interleaving array indices, mip levels, |
| 274 | * cube faces, and strides in that order */ |
| 275 | |
| 276 | unsigned first_face = 0, last_face = 0, face_mult = 1; |
| 277 | |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 278 | if (dim == MALI_TEXTURE_DIMENSION_CUBE) { |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 279 | face_mult = 6; |
| 280 | panfrost_adjust_cube_dimensions(&first_face, &last_face, &first_layer, &last_layer); |
| 281 | } |
| 282 | |
Alyssa Rosenzweig | 937d368 | 2020-06-30 16:43:47 -0400 | [diff] [blame] | 283 | nr_samples = MAX2(nr_samples, 1); |
| 284 | |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 285 | unsigned idx = 0; |
| 286 | |
| 287 | for (unsigned w = first_layer; w <= last_layer; ++w) { |
| 288 | for (unsigned l = first_level; l <= last_level; ++l) { |
| 289 | for (unsigned f = first_face; f <= last_face; ++f) { |
Alyssa Rosenzweig | 937d368 | 2020-06-30 16:43:47 -0400 | [diff] [blame] | 290 | for (unsigned s = 0; s < nr_samples; ++s) { |
| 291 | payload[idx++] = base + panfrost_texture_offset( |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 292 | slices, dim == MALI_TEXTURE_DIMENSION_3D, |
Alyssa Rosenzweig | 937d368 | 2020-06-30 16:43:47 -0400 | [diff] [blame] | 293 | cube_stride, l, w * face_mult + f, s); |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 294 | |
Alyssa Rosenzweig | 937d368 | 2020-06-30 16:43:47 -0400 | [diff] [blame] | 295 | if (manual_stride) { |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 296 | payload[idx++] = (modifier == DRM_FORMAT_MOD_LINEAR) ? |
Alyssa Rosenzweig | 937d368 | 2020-06-30 16:43:47 -0400 | [diff] [blame] | 297 | slices[l].stride : |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 298 | panfrost_nonlinear_stride(modifier, |
Alyssa Rosenzweig | 937d368 | 2020-06-30 16:43:47 -0400 | [diff] [blame] | 299 | MAX2(desc->block.bits / 8, 1), |
Alyssa Rosenzweig | f42eb33 | 2020-10-08 18:51:43 -0400 | [diff] [blame] | 300 | desc->block.width * desc->block.height, |
Alyssa Rosenzweig | 937d368 | 2020-06-30 16:43:47 -0400 | [diff] [blame] | 301 | u_minify(width, l), |
Alyssa Rosenzweig | 5363719 | 2020-10-08 18:35:17 -0400 | [diff] [blame] | 302 | u_minify(height, l), false); |
Alyssa Rosenzweig | 937d368 | 2020-06-30 16:43:47 -0400 | [diff] [blame] | 303 | } |
Alyssa Rosenzweig | bde19c0 | 2020-04-30 18:48:53 -0400 | [diff] [blame] | 304 | } |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 305 | } |
| 306 | } |
| 307 | } |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 308 | } |
| 309 | |
Alyssa Rosenzweig | 816af26 | 2020-07-08 16:37:00 -0400 | [diff] [blame] | 310 | #define MALI_SWIZZLE_R001 \ |
Alyssa Rosenzweig | cdc3276 | 2020-08-12 16:46:07 -0400 | [diff] [blame] | 311 | (MALI_CHANNEL_R << 0) | \ |
| 312 | (MALI_CHANNEL_0 << 3) | \ |
| 313 | (MALI_CHANNEL_0 << 6) | \ |
| 314 | (MALI_CHANNEL_1 << 9) |
Alyssa Rosenzweig | 816af26 | 2020-07-08 16:37:00 -0400 | [diff] [blame] | 315 | |
Alyssa Rosenzweig | 4c89148 | 2020-07-03 13:01:16 -0400 | [diff] [blame] | 316 | #define MALI_SWIZZLE_A001 \ |
Alyssa Rosenzweig | cdc3276 | 2020-08-12 16:46:07 -0400 | [diff] [blame] | 317 | (MALI_CHANNEL_A << 0) | \ |
| 318 | (MALI_CHANNEL_0 << 3) | \ |
| 319 | (MALI_CHANNEL_0 << 6) | \ |
| 320 | (MALI_CHANNEL_1 << 9) |
Alyssa Rosenzweig | 4c89148 | 2020-07-03 13:01:16 -0400 | [diff] [blame] | 321 | |
Alyssa Rosenzweig | 816af26 | 2020-07-08 16:37:00 -0400 | [diff] [blame] | 322 | |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 323 | void |
| 324 | panfrost_new_texture( |
| 325 | void *out, |
| 326 | uint16_t width, uint16_t height, |
| 327 | uint16_t depth, uint16_t array_size, |
| 328 | enum pipe_format format, |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 329 | enum mali_texture_dimension dim, |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 330 | uint64_t modifier, |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 331 | unsigned first_level, unsigned last_level, |
| 332 | unsigned first_layer, unsigned last_layer, |
Alyssa Rosenzweig | 41c06de | 2020-06-30 16:43:32 -0400 | [diff] [blame] | 333 | unsigned nr_samples, |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 334 | unsigned cube_stride, |
| 335 | unsigned swizzle, |
| 336 | mali_ptr base, |
| 337 | struct panfrost_slice *slices) |
| 338 | { |
| 339 | const struct util_format_description *desc = |
| 340 | util_format_description(format); |
| 341 | |
| 342 | unsigned bytes_per_pixel = util_format_get_blocksize(format); |
| 343 | |
Alyssa Rosenzweig | 861e7dc | 2020-05-15 18:43:41 -0400 | [diff] [blame] | 344 | enum mali_format mali_format = panfrost_pipe_format_table[desc->format].hw; |
| 345 | assert(mali_format); |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 346 | |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 347 | bool manual_stride = (modifier == DRM_FORMAT_MOD_LINEAR) |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 348 | && panfrost_needs_explicit_stride(slices, width, |
| 349 | first_level, last_level, bytes_per_pixel); |
| 350 | |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 351 | unsigned format_swizzle = (format == PIPE_FORMAT_X24S8_UINT) ? |
Alyssa Rosenzweig | 4c89148 | 2020-07-03 13:01:16 -0400 | [diff] [blame] | 352 | MALI_SWIZZLE_A001 : |
Alyssa Rosenzweig | 816af26 | 2020-07-08 16:37:00 -0400 | [diff] [blame] | 353 | (format == PIPE_FORMAT_S8_UINT) ? |
| 354 | MALI_SWIZZLE_R001 : |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 355 | panfrost_translate_swizzle_4(desc->swizzle); |
| 356 | |
| 357 | bool srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB); |
| 358 | |
| 359 | pan_pack(out, MIDGARD_TEXTURE, cfg) { |
| 360 | cfg.width = u_minify(width, first_level); |
| 361 | cfg.height = u_minify(height, first_level); |
| 362 | cfg.depth = u_minify(depth, first_level); |
| 363 | cfg.array_size = array_size; |
| 364 | cfg.format = format_swizzle | (mali_format << 12) | (srgb << 20); |
| 365 | cfg.dimension = dim; |
| 366 | cfg.texel_ordering = panfrost_modifier_to_layout(modifier); |
| 367 | cfg.manual_stride = manual_stride; |
| 368 | cfg.levels = last_level - first_level; |
| 369 | cfg.swizzle = swizzle; |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 370 | }; |
| 371 | |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 372 | panfrost_emit_texture_payload( |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 373 | (mali_ptr *) (out + MALI_MIDGARD_TEXTURE_LENGTH), |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 374 | desc, |
| 375 | mali_format, |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 376 | dim, |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 377 | modifier, |
Alyssa Rosenzweig | 92553b6 | 2020-06-15 12:42:40 -0400 | [diff] [blame] | 378 | width, height, |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 379 | first_level, last_level, |
| 380 | first_layer, last_layer, |
Alyssa Rosenzweig | 41c06de | 2020-06-30 16:43:32 -0400 | [diff] [blame] | 381 | nr_samples, |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 382 | cube_stride, |
| 383 | manual_stride, |
| 384 | base, |
| 385 | slices); |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 386 | } |
| 387 | |
Tomeu Vizoso | e41894b | 2020-04-17 14:23:49 +0200 | [diff] [blame] | 388 | void |
| 389 | panfrost_new_texture_bifrost( |
Boris Brezillon | fefb3e9 | 2020-09-23 11:08:02 +0200 | [diff] [blame] | 390 | const struct panfrost_device *dev, |
Alyssa Rosenzweig | ad0b32c | 2020-08-06 18:12:28 -0400 | [diff] [blame] | 391 | struct mali_bifrost_texture_packed *out, |
Tomeu Vizoso | e41894b | 2020-04-17 14:23:49 +0200 | [diff] [blame] | 392 | uint16_t width, uint16_t height, |
| 393 | uint16_t depth, uint16_t array_size, |
| 394 | enum pipe_format format, |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 395 | enum mali_texture_dimension dim, |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 396 | uint64_t modifier, |
Tomeu Vizoso | e41894b | 2020-04-17 14:23:49 +0200 | [diff] [blame] | 397 | unsigned first_level, unsigned last_level, |
| 398 | unsigned first_layer, unsigned last_layer, |
Alyssa Rosenzweig | 41c06de | 2020-06-30 16:43:32 -0400 | [diff] [blame] | 399 | unsigned nr_samples, |
Tomeu Vizoso | e41894b | 2020-04-17 14:23:49 +0200 | [diff] [blame] | 400 | unsigned cube_stride, |
| 401 | unsigned swizzle, |
| 402 | mali_ptr base, |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 403 | struct panfrost_slice *slices, |
Boris Brezillon | 8892c9c | 2020-10-18 10:27:48 +0200 | [diff] [blame^] | 404 | const struct panfrost_ptr *payload) |
Tomeu Vizoso | e41894b | 2020-04-17 14:23:49 +0200 | [diff] [blame] | 405 | { |
| 406 | const struct util_format_description *desc = |
| 407 | util_format_description(format); |
| 408 | |
Alyssa Rosenzweig | 861e7dc | 2020-05-15 18:43:41 -0400 | [diff] [blame] | 409 | enum mali_format mali_format = panfrost_pipe_format_table[desc->format].hw; |
| 410 | assert(mali_format); |
Tomeu Vizoso | e41894b | 2020-04-17 14:23:49 +0200 | [diff] [blame] | 411 | |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 412 | panfrost_emit_texture_payload( |
Boris Brezillon | 8892c9c | 2020-10-18 10:27:48 +0200 | [diff] [blame^] | 413 | payload->cpu, |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 414 | desc, |
| 415 | mali_format, |
Alyssa Rosenzweig | f008a63 | 2020-08-11 17:27:36 -0400 | [diff] [blame] | 416 | dim, |
Alyssa Rosenzweig | 965537df | 2020-07-22 10:23:50 -0400 | [diff] [blame] | 417 | modifier, |
Alyssa Rosenzweig | 92553b6 | 2020-06-15 12:42:40 -0400 | [diff] [blame] | 418 | width, height, |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 419 | first_level, last_level, |
| 420 | first_layer, last_layer, |
Alyssa Rosenzweig | 41c06de | 2020-06-30 16:43:32 -0400 | [diff] [blame] | 421 | nr_samples, |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 422 | cube_stride, |
Alyssa Rosenzweig | bde19c0 | 2020-04-30 18:48:53 -0400 | [diff] [blame] | 423 | true, /* Stride explicit on Bifrost */ |
Alyssa Rosenzweig | a3d2936 | 2020-04-21 16:08:07 -0400 | [diff] [blame] | 424 | base, |
| 425 | slices); |
| 426 | |
Alyssa Rosenzweig | ad0b32c | 2020-08-06 18:12:28 -0400 | [diff] [blame] | 427 | bool srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB); |
| 428 | |
| 429 | pan_pack(out, BIFROST_TEXTURE, cfg) { |
| 430 | cfg.dimension = dim; |
| 431 | cfg.format = (mali_format << 12) | (srgb << 20); |
Boris Brezillon | fefb3e9 | 2020-09-23 11:08:02 +0200 | [diff] [blame] | 432 | if (dev->quirks & HAS_SWIZZLES) |
| 433 | cfg.format |= panfrost_get_default_swizzle(desc->nr_channels); |
| 434 | |
Alyssa Rosenzweig | ad0b32c | 2020-08-06 18:12:28 -0400 | [diff] [blame] | 435 | cfg.width = u_minify(width, first_level); |
| 436 | cfg.height = u_minify(height, first_level); |
| 437 | cfg.swizzle = swizzle; |
| 438 | cfg.texel_ordering = panfrost_modifier_to_layout(modifier); |
| 439 | cfg.levels = last_level - first_level; |
Boris Brezillon | 8892c9c | 2020-10-18 10:27:48 +0200 | [diff] [blame^] | 440 | cfg.surfaces = payload->gpu; |
Alyssa Rosenzweig | ad0b32c | 2020-08-06 18:12:28 -0400 | [diff] [blame] | 441 | |
Alyssa Rosenzweig | 239e4e8 | 2020-10-06 21:46:56 -0400 | [diff] [blame] | 442 | /* We specify API-level LOD clamps in the sampler descriptor |
| 443 | * and use these clamps simply for bounds checking */ |
| 444 | cfg.minimum_lod = FIXED_16(0, false); |
| 445 | cfg.maximum_lod = FIXED_16(cfg.levels, false); |
Alyssa Rosenzweig | ad0b32c | 2020-08-06 18:12:28 -0400 | [diff] [blame] | 446 | } |
Tomeu Vizoso | e41894b | 2020-04-17 14:23:49 +0200 | [diff] [blame] | 447 | } |
| 448 | |
Alyssa Rosenzweig | 5ddf7ad | 2020-02-18 12:07:47 -0500 | [diff] [blame] | 449 | /* Computes sizes for checksumming, which is 8 bytes per 16x16 tile. |
| 450 | * Checksumming is believed to be a CRC variant (CRC64 based on the size?). |
| 451 | * This feature is also known as "transaction elimination". */ |
| 452 | |
| 453 | #define CHECKSUM_TILE_WIDTH 16 |
| 454 | #define CHECKSUM_TILE_HEIGHT 16 |
| 455 | #define CHECKSUM_BYTES_PER_TILE 8 |
| 456 | |
| 457 | unsigned |
| 458 | panfrost_compute_checksum_size( |
| 459 | struct panfrost_slice *slice, |
| 460 | unsigned width, |
| 461 | unsigned height) |
| 462 | { |
| 463 | unsigned aligned_width = ALIGN_POT(width, CHECKSUM_TILE_WIDTH); |
| 464 | unsigned aligned_height = ALIGN_POT(height, CHECKSUM_TILE_HEIGHT); |
| 465 | |
| 466 | unsigned tile_count_x = aligned_width / CHECKSUM_TILE_WIDTH; |
| 467 | unsigned tile_count_y = aligned_height / CHECKSUM_TILE_HEIGHT; |
| 468 | |
| 469 | slice->checksum_stride = tile_count_x * CHECKSUM_BYTES_PER_TILE; |
| 470 | |
| 471 | return slice->checksum_stride * tile_count_y; |
| 472 | } |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 473 | |
| 474 | unsigned |
| 475 | panfrost_get_layer_stride(struct panfrost_slice *slices, bool is_3d, unsigned cube_stride, unsigned level) |
| 476 | { |
| 477 | return is_3d ? slices[level].size0 : cube_stride; |
| 478 | } |
| 479 | |
| 480 | /* Computes the offset into a texture at a particular level/face. Add to |
| 481 | * the base address of a texture to get the address to that level/face */ |
| 482 | |
| 483 | unsigned |
Alyssa Rosenzweig | 41c06de | 2020-06-30 16:43:32 -0400 | [diff] [blame] | 484 | panfrost_texture_offset(struct panfrost_slice *slices, bool is_3d, unsigned cube_stride, unsigned level, unsigned face, unsigned sample) |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 485 | { |
| 486 | unsigned layer_stride = panfrost_get_layer_stride(slices, is_3d, cube_stride, level); |
Alyssa Rosenzweig | 41c06de | 2020-06-30 16:43:32 -0400 | [diff] [blame] | 487 | return slices[level].offset + (face * layer_stride) + (sample * slices[level].size0); |
Alyssa Rosenzweig | b929565 | 2020-02-18 14:20:16 -0500 | [diff] [blame] | 488 | } |