1 /*
2 * Copyright 2022 Alyssa Rosenzweig
3 * SPDX-License-Identifier: MIT
4 *
5 */
6
7 #pragma once
8
9 #include "util/format/u_format.h"
10 #include "util/macros.h"
11 #include "util/u_math.h"
12
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16
17 #define AIL_CACHELINE 0x80
18 #define AIL_PAGESIZE 0x4000
19 #define AIL_MAX_MIP_LEVELS 16
20
21 enum ail_tiling {
22 /**
23 * Strided linear (raster order). Only allowed for 1D or 2D, without
24 * mipmapping, multisampling, block-compression, or arrays.
25 */
26 AIL_TILING_LINEAR,
27
28 /**
29 * Twiddled (Morton order). Always allowed.
30 */
31 AIL_TILING_TWIDDLED,
32
33 /**
34 * Twiddled (Morton order) with compression.
35 */
36 AIL_TILING_TWIDDLED_COMPRESSED,
37 };
38
39 /*
40 * Represents the dimensions of a single tile. Used to describe tiled layouts.
41 * Width and height are in units of elements, not pixels, to model compressed
42 * textures corrects.
43 *
44 * Invariant: width_el and height_el are powers of two.
45 */
46 struct ail_tile {
47 unsigned width_el, height_el;
48 };
49
50 /*
51 * An AGX image layout.
52 */
53 struct ail_layout {
54 /** Width, height, and depth in pixels at level 0 */
55 uint32_t width_px, height_px, depth_px;
56
57 /** Number of samples per pixel. 1 if multisampling is disabled. */
58 uint8_t sample_count_sa;
59
60 /** Number of miplevels. 1 if no mipmapping is used. */
61 uint8_t levels;
62
63 /** Should this image be mipmapped along the Z-axis in addition to the X- and
64 * Y-axes? This should be set for API-level 3D images, but not 2D arrays or
65 * cubes.
66 */
67 bool mipmapped_z;
68
69 /** Tiling mode used */
70 enum ail_tiling tiling;
71
72 /** Texture format */
73 enum pipe_format format;
74
75 /**
76 * If tiling is LINEAR, the number of bytes between adjacent rows of
77 * elements. Otherwise, this field is zero.
78 */
79 uint32_t linear_stride_B;
80
81 /**
82 * Stride between layers of an array texture, including a cube map. Layer i
83 * begins at offset (i * layer_stride_B) from the beginning of the texture.
84 *
85 * If depth_px = 1, the value of this field is UNDEFINED.
86 */
87 uint64_t layer_stride_B;
88
89 /**
90 * Whether the layer stride is aligned to the page size or not. The hardware
91 * needs this flag to compute the implicit layer stride.
92 */
93 bool page_aligned_layers;
94
95 /**
96 * Offsets of mip levels within a layer.
97 */
98 uint64_t level_offsets_B[AIL_MAX_MIP_LEVELS];
99
100 /**
101 * For the compressed buffer, offsets of mip levels within a layer.
102 */
103 uint64_t level_offsets_compressed_B[AIL_MAX_MIP_LEVELS];
104
105 /**
106 * If tiling is TWIDDLED, the tile size used for each mip level within a
107 * layer. Calculating tile sizes is the sole responsibility of
108 * ail_initialized_twiddled.
109 */
110 struct ail_tile tilesize_el[AIL_MAX_MIP_LEVELS];
111
112 /**
113 * If tiling is TWIDDLED, the stride in elements used for each mip level
114 * within a layer. Calculating level strides is the sole responsibility of
115 * ail_initialized_twiddled. This is necessary because compressed pixel
116 * formats may add extra stride padding.
117 */
118 uint32_t stride_el[AIL_MAX_MIP_LEVELS];
119
120 /* Offset of the start of the compression metadata buffer */
121 uint32_t metadata_offset_B;
122
123 /* Stride between subsequent layers in the compression metadata buffer */
124 uint64_t compression_layer_stride_B;
125
126 /* Size of entire texture */
127 uint64_t size_B;
128
129 /* Must the layout support writeable images? If false, the layout MUST NOT be
130 * used as a writeable image (either PBE or image atomics).
131 */
132 bool writeable_image;
133
134 /* Must the layout support rendering? If false, the layout MUST NOT be used
135 * for rendering, either PBE or ZLS.
136 */
137 bool renderable;
138 };
139
140 static inline uint32_t
ail_get_linear_stride_B(struct ail_layout * layout,ASSERTED uint8_t level)141 ail_get_linear_stride_B(struct ail_layout *layout, ASSERTED uint8_t level)
142 {
143 assert(layout->tiling == AIL_TILING_LINEAR && "Invalid usage");
144 assert(level == 0 && "Strided linear mipmapped textures are unsupported");
145
146 return layout->linear_stride_B;
147 }
148
149 /*
150 * For WSI purposes, we need to associate a stride with all layouts. In the
151 * hardware, only strided linear images have an associated stride, there is no
152 * natural stride associated with twiddled images. However, various clients
153 * assert that the stride is valid for the image if it were linear (even if it
154 * is in fact not linear). In those cases, by convention we use the minimum
155 * valid such stride.
156 */
157 static inline uint32_t
ail_get_wsi_stride_B(struct ail_layout * layout,unsigned level)158 ail_get_wsi_stride_B(struct ail_layout *layout, unsigned level)
159 {
160 assert(level == 0 && "Mipmaps cannot be shared as WSI");
161
162 if (layout->tiling == AIL_TILING_LINEAR)
163 return ail_get_linear_stride_B(layout, level);
164 else
165 return util_format_get_stride(layout->format, layout->width_px);
166 }
167
168 static inline uint32_t
ail_get_layer_offset_B(struct ail_layout * layout,unsigned z_px)169 ail_get_layer_offset_B(struct ail_layout *layout, unsigned z_px)
170 {
171 return z_px * layout->layer_stride_B;
172 }
173
174 static inline uint32_t
ail_get_level_offset_B(struct ail_layout * layout,unsigned level)175 ail_get_level_offset_B(struct ail_layout *layout, unsigned level)
176 {
177 return layout->level_offsets_B[level];
178 }
179
180 static inline uint32_t
ail_get_layer_level_B(struct ail_layout * layout,unsigned z_px,unsigned level)181 ail_get_layer_level_B(struct ail_layout *layout, unsigned z_px, unsigned level)
182 {
183 return ail_get_layer_offset_B(layout, z_px) +
184 ail_get_level_offset_B(layout, level);
185 }
186
187 static inline uint32_t
ail_get_linear_pixel_B(struct ail_layout * layout,ASSERTED unsigned level,uint32_t x_px,uint32_t y_px,uint32_t z_px)188 ail_get_linear_pixel_B(struct ail_layout *layout, ASSERTED unsigned level,
189 uint32_t x_px, uint32_t y_px, uint32_t z_px)
190 {
191 assert(level == 0 && "Strided linear mipmapped textures are unsupported");
192 assert(util_format_get_blockwidth(layout->format) == 1 &&
193 "Strided linear block formats unsupported");
194 assert(util_format_get_blockheight(layout->format) == 1 &&
195 "Strided linear block formats unsupported");
196 assert(layout->sample_count_sa == 1 &&
197 "Strided linear multisampling unsupported");
198
199 return ail_get_layer_offset_B(layout, z_px) +
200 (y_px * ail_get_linear_stride_B(layout, level)) +
201 (x_px * util_format_get_blocksize(layout->format));
202 }
203
204 static inline unsigned
ail_effective_width_sa(unsigned width_px,unsigned sample_count_sa)205 ail_effective_width_sa(unsigned width_px, unsigned sample_count_sa)
206 {
207 return width_px * (sample_count_sa == 4 ? 2 : 1);
208 }
209
210 static inline unsigned
ail_effective_height_sa(unsigned height_px,unsigned sample_count_sa)211 ail_effective_height_sa(unsigned height_px, unsigned sample_count_sa)
212 {
213 return height_px * (sample_count_sa >= 2 ? 2 : 1);
214 }
215
216 static inline bool
ail_can_compress(unsigned w_px,unsigned h_px,unsigned sample_count_sa)217 ail_can_compress(unsigned w_px, unsigned h_px, unsigned sample_count_sa)
218 {
219 assert(sample_count_sa == 1 || sample_count_sa == 2 || sample_count_sa == 4);
220
221 /* Small textures cannot be compressed */
222 return ail_effective_width_sa(w_px, sample_count_sa) >= 16 &&
223 ail_effective_height_sa(h_px, sample_count_sa) >= 16;
224 }
225
226 static inline bool
ail_is_compressed(struct ail_layout * layout)227 ail_is_compressed(struct ail_layout *layout)
228 {
229 return layout->tiling == AIL_TILING_TWIDDLED_COMPRESSED;
230 }
231
232 /*
233 * Even when the base mip level is compressed, high levels of the miptree
234 * (smaller than 16 pixels on either axis) are not compressed as it would be
235 * pointless. This queries this case.
236 */
237 static inline bool
ail_is_level_compressed(struct ail_layout * layout,unsigned level)238 ail_is_level_compressed(struct ail_layout *layout, unsigned level)
239 {
240 unsigned width_sa = ALIGN(
241 ail_effective_width_sa(layout->width_px, layout->sample_count_sa), 16);
242
243 unsigned height_sa = ALIGN(
244 ail_effective_height_sa(layout->height_px, layout->sample_count_sa), 16);
245
246 return ail_is_compressed(layout) &&
247 u_minify(MAX2(width_sa, height_sa), level) >= 16;
248 }
249
250 static inline bool
ail_is_level_twiddled_uncompressed(struct ail_layout * layout,unsigned level)251 ail_is_level_twiddled_uncompressed(struct ail_layout *layout, unsigned level)
252 {
253 switch (layout->tiling) {
254 case AIL_TILING_TWIDDLED:
255 return true;
256 case AIL_TILING_TWIDDLED_COMPRESSED:
257 return !ail_is_level_compressed(layout, level);
258 default:
259 return false;
260 }
261 }
262
263 void ail_make_miptree(struct ail_layout *layout);
264
265 void ail_detile(void *_tiled, void *_linear, struct ail_layout *tiled_layout,
266 unsigned level, unsigned linear_pitch_B, unsigned sx_px,
267 unsigned sy_px, unsigned width_px, unsigned height_px);
268
269 void ail_tile(void *_tiled, void *_linear, struct ail_layout *tiled_layout,
270 unsigned level, unsigned linear_pitch_B, unsigned sx_px,
271 unsigned sy_px, unsigned width_px, unsigned height_px);
272
273 #ifdef __cplusplus
274 } /* extern C */
275 #endif
276