1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #ifndef ILO_IMAGE_H
29 #define ILO_IMAGE_H
30
31 #include "genhw/genhw.h"
32
33 #include "ilo_core.h"
34 #include "ilo_dev.h"
35
36 /*
37 * From the Ivy Bridge PRM, volume 4 part 1, page 75:
38 *
39 * "(MIP Count / LOD) representing [1,15] MIP levels"
40 */
41 #define ILO_IMAGE_MAX_LEVEL_COUNT 15
42
43 enum ilo_image_aux_type {
44 ILO_IMAGE_AUX_NONE,
45 ILO_IMAGE_AUX_HIZ,
46 ILO_IMAGE_AUX_MCS,
47 };
48
49 enum ilo_image_walk_type {
50 /*
51 * LODs of each array layer are first packed together in MIPLAYOUT_BELOW.
52 * Array layers are then stacked together vertically.
53 *
54 * This can be used for mipmapped 2D textures.
55 */
56 ILO_IMAGE_WALK_LAYER,
57
58 /*
59 * Array layers of each LOD are first stacked together vertically and
60 * tightly. LODs are then packed together in MIPLAYOUT_BELOW with each LOD
61 * starting at page boundaries.
62 *
63 * This is usually used for non-mipmapped 2D textures, as multiple LODs are
64 * not supported natively.
65 */
66 ILO_IMAGE_WALK_LOD,
67
68 /*
69 * 3D slices of each LOD are first packed together horizontally and tightly
70 * with wrapping. LODs are then stacked together vertically and tightly.
71 *
72 * This is used for 3D textures.
73 */
74 ILO_IMAGE_WALK_3D,
75 };
76
77 struct ilo_image_info {
78 enum gen_surface_type type;
79
80 enum gen_surface_format format;
81 bool interleaved_stencil;
82 bool is_integer;
83 /* width, height and size of pixel blocks */
84 bool compressed;
85 unsigned block_width;
86 unsigned block_height;
87 unsigned block_size;
88
89 /* image size */
90 uint16_t width;
91 uint16_t height;
92 uint16_t depth;
93 uint16_t array_size;
94 uint8_t level_count;
95 uint8_t sample_count;
96
97 /* disable optional aux */
98 bool aux_disable;
99
100 /* tilings to consider, if any bit is set */
101 uint8_t valid_tilings;
102
103 /*
104 * prefer GEN6_TILING_NONE when the (estimated) image size exceeds the
105 * threshold; ignored when zero
106 */
107 uint32_t prefer_linear_threshold;
108
109 /* force a stride when non-zero */
110 uint32_t force_bo_stride;
111
112 bool bind_surface_sampler;
113 bool bind_surface_dp_render;
114 bool bind_surface_dp_typed;
115 bool bind_zs;
116 bool bind_scanout;
117 bool bind_cursor;
118 };
119
120 /*
121 * When the walk type is ILO_IMAGE_WALK_LAYER, there is only a slice in each
122 * LOD and this is used to describe LODs in the first array layer. Otherwise,
123 * there can be multiple slices in each LOD and this is used to describe the
124 * first slice in each LOD.
125 */
126 struct ilo_image_lod {
127 /* physical position in pixels */
128 unsigned x;
129 unsigned y;
130
131 /* physical size of a slice in pixels */
132 unsigned slice_width;
133 unsigned slice_height;
134 };
135
136 /**
137 * Texture layout.
138 */
139 struct ilo_image {
140 enum gen_surface_type type;
141
142 enum gen_surface_format format;
143 bool interleaved_stencil;
144
145 /* size, format, etc for programming hardware states */
146 unsigned width0;
147 unsigned height0;
148 unsigned depth0;
149 unsigned array_size;
150 unsigned level_count;
151 unsigned sample_count;
152
153 /*
154 * width, height, and size of pixel blocks for conversion between pixel
155 * positions and memory offsets
156 */
157 unsigned block_width;
158 unsigned block_height;
159 unsigned block_size;
160
161 enum ilo_image_walk_type walk;
162 bool interleaved_samples;
163
164 enum gen_surface_tiling tiling;
165
166 /* physical LOD slice alignments */
167 unsigned align_i;
168 unsigned align_j;
169
170 struct ilo_image_lod lods[ILO_IMAGE_MAX_LEVEL_COUNT];
171
172 /* physical layer height for ILO_IMAGE_WALK_LAYER */
173 unsigned walk_layer_height;
174
175 /* distance in bytes between two pixel block rows */
176 unsigned bo_stride;
177 /* number of pixel block rows */
178 unsigned bo_height;
179
180 bool scanout;
181
182 struct {
183 enum ilo_image_aux_type type;
184
185 /* bitmask of levels that can use aux */
186 unsigned enables;
187
188 /* LOD offsets for ILO_IMAGE_WALK_LOD */
189 unsigned walk_lod_offsets[ILO_IMAGE_MAX_LEVEL_COUNT];
190
191 unsigned walk_layer_height;
192 unsigned bo_stride;
193 unsigned bo_height;
194 } aux;
195 };
196
197 bool
198 ilo_image_init(struct ilo_image *img,
199 const struct ilo_dev *dev,
200 const struct ilo_image_info *info);
201
202 static inline bool
ilo_image_can_enable_aux(const struct ilo_image * img,unsigned level)203 ilo_image_can_enable_aux(const struct ilo_image *img, unsigned level)
204 {
205 return (img->aux.enables & (1 << level));
206 }
207
208 /**
209 * Convert from pixel position to 2D memory offset.
210 */
211 static inline void
ilo_image_pos_to_mem(const struct ilo_image * img,unsigned pos_x,unsigned pos_y,unsigned * mem_x,unsigned * mem_y)212 ilo_image_pos_to_mem(const struct ilo_image *img,
213 unsigned pos_x, unsigned pos_y,
214 unsigned *mem_x, unsigned *mem_y)
215 {
216 assert(pos_x % img->block_width == 0);
217 assert(pos_y % img->block_height == 0);
218
219 *mem_x = pos_x / img->block_width * img->block_size;
220 *mem_y = pos_y / img->block_height;
221 }
222
223 /**
224 * Convert from 2D memory offset to linear offset.
225 */
226 static inline unsigned
ilo_image_mem_to_linear(const struct ilo_image * img,unsigned mem_x,unsigned mem_y)227 ilo_image_mem_to_linear(const struct ilo_image *img,
228 unsigned mem_x, unsigned mem_y)
229 {
230 return mem_y * img->bo_stride + mem_x;
231 }
232
233 /**
234 * Convert from 2D memory offset to raw offset.
235 */
236 static inline unsigned
ilo_image_mem_to_raw(const struct ilo_image * img,unsigned mem_x,unsigned mem_y)237 ilo_image_mem_to_raw(const struct ilo_image *img,
238 unsigned mem_x, unsigned mem_y)
239 {
240 unsigned tile_w, tile_h;
241
242 switch (img->tiling) {
243 case GEN6_TILING_NONE:
244 tile_w = 1;
245 tile_h = 1;
246 break;
247 case GEN6_TILING_X:
248 tile_w = 512;
249 tile_h = 8;
250 break;
251 case GEN6_TILING_Y:
252 tile_w = 128;
253 tile_h = 32;
254 break;
255 case GEN8_TILING_W:
256 tile_w = 64;
257 tile_h = 64;
258 break;
259 default:
260 assert(!"unknown tiling");
261 tile_w = 1;
262 tile_h = 1;
263 break;
264 }
265
266 assert(mem_x % tile_w == 0);
267 assert(mem_y % tile_h == 0);
268
269 return mem_y * img->bo_stride + mem_x * tile_h;
270 }
271
272 /**
273 * Return the stride, in bytes, between slices within a level.
274 */
275 static inline unsigned
ilo_image_get_slice_stride(const struct ilo_image * img,unsigned level)276 ilo_image_get_slice_stride(const struct ilo_image *img, unsigned level)
277 {
278 unsigned h;
279
280 switch (img->walk) {
281 case ILO_IMAGE_WALK_LAYER:
282 h = img->walk_layer_height;
283 break;
284 case ILO_IMAGE_WALK_LOD:
285 h = img->lods[level].slice_height;
286 break;
287 case ILO_IMAGE_WALK_3D:
288 if (level == 0) {
289 h = img->lods[0].slice_height;
290 break;
291 }
292 /* fall through */
293 default:
294 assert(!"no single stride to walk across slices");
295 h = 0;
296 break;
297 }
298
299 assert(h % img->block_height == 0);
300
301 return (h / img->block_height) * img->bo_stride;
302 }
303
304 /**
305 * Return the physical size, in bytes, of a slice in a level.
306 */
307 static inline unsigned
ilo_image_get_slice_size(const struct ilo_image * img,unsigned level)308 ilo_image_get_slice_size(const struct ilo_image *img, unsigned level)
309 {
310 const unsigned w = img->lods[level].slice_width;
311 const unsigned h = img->lods[level].slice_height;
312
313 assert(w % img->block_width == 0);
314 assert(h % img->block_height == 0);
315
316 return (w / img->block_width * img->block_size) *
317 (h / img->block_height);
318 }
319
320 /**
321 * Return the pixel position of a slice.
322 */
323 static inline void
ilo_image_get_slice_pos(const struct ilo_image * img,unsigned level,unsigned slice,unsigned * x,unsigned * y)324 ilo_image_get_slice_pos(const struct ilo_image *img,
325 unsigned level, unsigned slice,
326 unsigned *x, unsigned *y)
327 {
328 switch (img->walk) {
329 case ILO_IMAGE_WALK_LAYER:
330 *x = img->lods[level].x;
331 *y = img->lods[level].y + img->walk_layer_height * slice;
332 break;
333 case ILO_IMAGE_WALK_LOD:
334 *x = img->lods[level].x;
335 *y = img->lods[level].y + img->lods[level].slice_height * slice;
336 break;
337 case ILO_IMAGE_WALK_3D:
338 {
339 /* slices are packed horizontally with wrapping */
340 const unsigned sx = slice & ((1 << level) - 1);
341 const unsigned sy = slice >> level;
342
343 assert(slice < u_minify(img->depth0, level));
344
345 *x = img->lods[level].x + img->lods[level].slice_width * sx;
346 *y = img->lods[level].y + img->lods[level].slice_height * sy;
347 }
348 break;
349 default:
350 assert(!"unknown img walk type");
351 *x = 0;
352 *y = 0;
353 break;
354 }
355
356 /* should not exceed the bo size */
357 assert(*y + img->lods[level].slice_height <=
358 img->bo_height * img->block_height);
359 }
360
361 #endif /* ILO_IMAGE_H */
362