util: Move gallium's PIPE_FORMAT utils to /util/format/
[mesa.git] / src / gallium / winsys / radeon / drm / radeon_drm_surface.c
1 /*
2 * Copyright © 2014 Advanced Micro Devices, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
17 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 */
26
27 #include "radeon_drm_winsys.h"
28 #include "util/format/u_format.h"
29 #include <radeon_surface.h>
30
31 static unsigned cik_get_macro_tile_index(struct radeon_surf *surf)
32 {
33 unsigned index, tileb;
34
35 tileb = 8 * 8 * surf->bpe;
36 tileb = MIN2(surf->u.legacy.tile_split, tileb);
37
38 for (index = 0; tileb > 64; index++)
39 tileb >>= 1;
40
41 assert(index < 16);
42 return index;
43 }
44
45 #define G_009910_MICRO_TILE_MODE(x) (((x) >> 0) & 0x03)
46 #define G_009910_MICRO_TILE_MODE_NEW(x) (((x) >> 22) & 0x07)
47
48 static void set_micro_tile_mode(struct radeon_surf *surf,
49 struct radeon_info *info)
50 {
51 uint32_t tile_mode;
52
53 if (info->chip_class < GFX6) {
54 surf->micro_tile_mode = 0;
55 return;
56 }
57
58 tile_mode = info->si_tile_mode_array[surf->u.legacy.tiling_index[0]];
59
60 if (info->chip_class >= GFX7)
61 surf->micro_tile_mode = G_009910_MICRO_TILE_MODE_NEW(tile_mode);
62 else
63 surf->micro_tile_mode = G_009910_MICRO_TILE_MODE(tile_mode);
64 }
65
66 static void surf_level_winsys_to_drm(struct radeon_surface_level *level_drm,
67 const struct legacy_surf_level *level_ws,
68 unsigned bpe)
69 {
70 level_drm->offset = level_ws->offset;
71 level_drm->slice_size = (uint64_t)level_ws->slice_size_dw * 4;
72 level_drm->nblk_x = level_ws->nblk_x;
73 level_drm->nblk_y = level_ws->nblk_y;
74 level_drm->pitch_bytes = level_ws->nblk_x * bpe;
75 level_drm->mode = level_ws->mode;
76 }
77
78 static void surf_level_drm_to_winsys(struct legacy_surf_level *level_ws,
79 const struct radeon_surface_level *level_drm,
80 unsigned bpe)
81 {
82 level_ws->offset = level_drm->offset;
83 level_ws->slice_size_dw = level_drm->slice_size / 4;
84 level_ws->nblk_x = level_drm->nblk_x;
85 level_ws->nblk_y = level_drm->nblk_y;
86 level_ws->mode = level_drm->mode;
87 assert(level_drm->nblk_x * bpe == level_drm->pitch_bytes);
88 }
89
90 static void surf_winsys_to_drm(struct radeon_surface *surf_drm,
91 const struct pipe_resource *tex,
92 unsigned flags, unsigned bpe,
93 enum radeon_surf_mode mode,
94 const struct radeon_surf *surf_ws)
95 {
96 int i;
97
98 memset(surf_drm, 0, sizeof(*surf_drm));
99
100 surf_drm->npix_x = tex->width0;
101 surf_drm->npix_y = tex->height0;
102 surf_drm->npix_z = tex->depth0;
103 surf_drm->blk_w = util_format_get_blockwidth(tex->format);
104 surf_drm->blk_h = util_format_get_blockheight(tex->format);
105 surf_drm->blk_d = 1;
106 surf_drm->array_size = 1;
107 surf_drm->last_level = tex->last_level;
108 surf_drm->bpe = bpe;
109 surf_drm->nsamples = tex->nr_samples ? tex->nr_samples : 1;
110
111 surf_drm->flags = flags;
112 surf_drm->flags = RADEON_SURF_CLR(surf_drm->flags, TYPE);
113 surf_drm->flags = RADEON_SURF_CLR(surf_drm->flags, MODE);
114 surf_drm->flags |= RADEON_SURF_SET(mode, MODE) |
115 RADEON_SURF_HAS_SBUFFER_MIPTREE |
116 RADEON_SURF_HAS_TILE_MODE_INDEX;
117
118 switch (tex->target) {
119 case PIPE_TEXTURE_1D:
120 surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE);
121 break;
122 case PIPE_TEXTURE_RECT:
123 case PIPE_TEXTURE_2D:
124 surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
125 break;
126 case PIPE_TEXTURE_3D:
127 surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE);
128 break;
129 case PIPE_TEXTURE_1D_ARRAY:
130 surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE);
131 surf_drm->array_size = tex->array_size;
132 break;
133 case PIPE_TEXTURE_CUBE_ARRAY: /* cube array layout like 2d array */
134 assert(tex->array_size % 6 == 0);
135 /* fall through */
136 case PIPE_TEXTURE_2D_ARRAY:
137 surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE);
138 surf_drm->array_size = tex->array_size;
139 break;
140 case PIPE_TEXTURE_CUBE:
141 surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_CUBEMAP, TYPE);
142 break;
143 case PIPE_BUFFER:
144 default:
145 assert(0);
146 }
147
148 surf_drm->bo_size = surf_ws->surf_size;
149 surf_drm->bo_alignment = surf_ws->surf_alignment;
150
151 surf_drm->bankw = surf_ws->u.legacy.bankw;
152 surf_drm->bankh = surf_ws->u.legacy.bankh;
153 surf_drm->mtilea = surf_ws->u.legacy.mtilea;
154 surf_drm->tile_split = surf_ws->u.legacy.tile_split;
155
156 for (i = 0; i <= surf_drm->last_level; i++) {
157 surf_level_winsys_to_drm(&surf_drm->level[i], &surf_ws->u.legacy.level[i],
158 bpe * surf_drm->nsamples);
159
160 surf_drm->tiling_index[i] = surf_ws->u.legacy.tiling_index[i];
161 }
162
163 if (flags & RADEON_SURF_SBUFFER) {
164 surf_drm->stencil_tile_split = surf_ws->u.legacy.stencil_tile_split;
165
166 for (i = 0; i <= surf_drm->last_level; i++) {
167 surf_level_winsys_to_drm(&surf_drm->stencil_level[i],
168 &surf_ws->u.legacy.stencil_level[i],
169 surf_drm->nsamples);
170 surf_drm->stencil_tiling_index[i] = surf_ws->u.legacy.stencil_tiling_index[i];
171 }
172 }
173 }
174
175 static void surf_drm_to_winsys(struct radeon_drm_winsys *ws,
176 struct radeon_surf *surf_ws,
177 const struct radeon_surface *surf_drm)
178 {
179 int i;
180
181 memset(surf_ws, 0, sizeof(*surf_ws));
182
183 surf_ws->blk_w = surf_drm->blk_w;
184 surf_ws->blk_h = surf_drm->blk_h;
185 surf_ws->bpe = surf_drm->bpe;
186 surf_ws->is_linear = surf_drm->level[0].mode <= RADEON_SURF_MODE_LINEAR_ALIGNED;
187 surf_ws->has_stencil = !!(surf_drm->flags & RADEON_SURF_SBUFFER);
188 surf_ws->flags = surf_drm->flags;
189
190 surf_ws->surf_size = surf_drm->bo_size;
191 surf_ws->surf_alignment = surf_drm->bo_alignment;
192
193 surf_ws->u.legacy.bankw = surf_drm->bankw;
194 surf_ws->u.legacy.bankh = surf_drm->bankh;
195 surf_ws->u.legacy.mtilea = surf_drm->mtilea;
196 surf_ws->u.legacy.tile_split = surf_drm->tile_split;
197
198 surf_ws->u.legacy.macro_tile_index = cik_get_macro_tile_index(surf_ws);
199
200 for (i = 0; i <= surf_drm->last_level; i++) {
201 surf_level_drm_to_winsys(&surf_ws->u.legacy.level[i], &surf_drm->level[i],
202 surf_drm->bpe * surf_drm->nsamples);
203 surf_ws->u.legacy.tiling_index[i] = surf_drm->tiling_index[i];
204 }
205
206 if (surf_ws->flags & RADEON_SURF_SBUFFER) {
207 surf_ws->u.legacy.stencil_tile_split = surf_drm->stencil_tile_split;
208
209 for (i = 0; i <= surf_drm->last_level; i++) {
210 surf_level_drm_to_winsys(&surf_ws->u.legacy.stencil_level[i],
211 &surf_drm->stencil_level[i],
212 surf_drm->nsamples);
213 surf_ws->u.legacy.stencil_tiling_index[i] = surf_drm->stencil_tiling_index[i];
214 }
215 }
216
217 set_micro_tile_mode(surf_ws, &ws->info);
218 surf_ws->is_displayable = surf_ws->is_linear ||
219 surf_ws->micro_tile_mode == RADEON_MICRO_MODE_DISPLAY ||
220 surf_ws->micro_tile_mode == RADEON_MICRO_MODE_ROTATED;
221 }
222
223 static void si_compute_cmask(const struct radeon_info *info,
224 const struct ac_surf_config *config,
225 struct radeon_surf *surf)
226 {
227 unsigned pipe_interleave_bytes = info->pipe_interleave_bytes;
228 unsigned num_pipes = info->num_tile_pipes;
229 unsigned cl_width, cl_height;
230
231 if (surf->flags & RADEON_SURF_Z_OR_SBUFFER)
232 return;
233
234 assert(info->chip_class <= GFX8);
235
236 switch (num_pipes) {
237 case 2:
238 cl_width = 32;
239 cl_height = 16;
240 break;
241 case 4:
242 cl_width = 32;
243 cl_height = 32;
244 break;
245 case 8:
246 cl_width = 64;
247 cl_height = 32;
248 break;
249 case 16: /* Hawaii */
250 cl_width = 64;
251 cl_height = 64;
252 break;
253 default:
254 assert(0);
255 return;
256 }
257
258 unsigned base_align = num_pipes * pipe_interleave_bytes;
259
260 unsigned width = align(surf->u.legacy.level[0].nblk_x, cl_width*8);
261 unsigned height = align(surf->u.legacy.level[0].nblk_y, cl_height*8);
262 unsigned slice_elements = (width * height) / (8*8);
263
264 /* Each element of CMASK is a nibble. */
265 unsigned slice_bytes = slice_elements / 2;
266
267 surf->u.legacy.cmask_slice_tile_max = (width * height) / (128*128);
268 if (surf->u.legacy.cmask_slice_tile_max)
269 surf->u.legacy.cmask_slice_tile_max -= 1;
270
271 unsigned num_layers;
272 if (config->is_3d)
273 num_layers = config->info.depth;
274 else if (config->is_cube)
275 num_layers = 6;
276 else
277 num_layers = config->info.array_size;
278
279 surf->cmask_alignment = MAX2(256, base_align);
280 surf->cmask_size = align(slice_bytes, base_align) * num_layers;
281 }
282
283 static void si_compute_htile(const struct radeon_info *info,
284 struct radeon_surf *surf, unsigned num_layers)
285 {
286 unsigned cl_width, cl_height, width, height;
287 unsigned slice_elements, slice_bytes, pipe_interleave_bytes, base_align;
288 unsigned num_pipes = info->num_tile_pipes;
289
290 surf->htile_size = 0;
291
292 if (!(surf->flags & RADEON_SURF_Z_OR_SBUFFER) ||
293 surf->flags & RADEON_SURF_NO_HTILE)
294 return;
295
296 if (surf->u.legacy.level[0].mode == RADEON_SURF_MODE_1D &&
297 !info->htile_cmask_support_1d_tiling)
298 return;
299
300 /* Overalign HTILE on P2 configs to work around GPU hangs in
301 * piglit/depthstencil-render-miplevels 585.
302 *
303 * This has been confirmed to help Kabini & Stoney, where the hangs
304 * are always reproducible. I think I have seen the test hang
305 * on Carrizo too, though it was very rare there.
306 */
307 if (info->chip_class >= GFX7 && num_pipes < 4)
308 num_pipes = 4;
309
310 switch (num_pipes) {
311 case 1:
312 cl_width = 32;
313 cl_height = 16;
314 break;
315 case 2:
316 cl_width = 32;
317 cl_height = 32;
318 break;
319 case 4:
320 cl_width = 64;
321 cl_height = 32;
322 break;
323 case 8:
324 cl_width = 64;
325 cl_height = 64;
326 break;
327 case 16:
328 cl_width = 128;
329 cl_height = 64;
330 break;
331 default:
332 assert(0);
333 return;
334 }
335
336 width = align(surf->u.legacy.level[0].nblk_x, cl_width * 8);
337 height = align(surf->u.legacy.level[0].nblk_y, cl_height * 8);
338
339 slice_elements = (width * height) / (8 * 8);
340 slice_bytes = slice_elements * 4;
341
342 pipe_interleave_bytes = info->pipe_interleave_bytes;
343 base_align = num_pipes * pipe_interleave_bytes;
344
345 surf->htile_alignment = base_align;
346 surf->htile_size = num_layers * align(slice_bytes, base_align);
347 }
348
349 static int radeon_winsys_surface_init(struct radeon_winsys *rws,
350 const struct pipe_resource *tex,
351 unsigned flags, unsigned bpe,
352 enum radeon_surf_mode mode,
353 struct radeon_surf *surf_ws)
354 {
355 struct radeon_drm_winsys *ws = (struct radeon_drm_winsys*)rws;
356 struct radeon_surface surf_drm;
357 int r;
358
359 surf_winsys_to_drm(&surf_drm, tex, flags, bpe, mode, surf_ws);
360
361 if (!(flags & (RADEON_SURF_IMPORTED | RADEON_SURF_FMASK))) {
362 r = radeon_surface_best(ws->surf_man, &surf_drm);
363 if (r)
364 return r;
365 }
366
367 r = radeon_surface_init(ws->surf_man, &surf_drm);
368 if (r)
369 return r;
370
371 surf_drm_to_winsys(ws, surf_ws, &surf_drm);
372
373 /* Compute FMASK. */
374 if (ws->gen == DRV_SI &&
375 tex->nr_samples >= 2 &&
376 !(flags & (RADEON_SURF_Z_OR_SBUFFER | RADEON_SURF_FMASK | RADEON_SURF_NO_FMASK))) {
377 /* FMASK is allocated like an ordinary texture. */
378 struct pipe_resource templ = *tex;
379 struct radeon_surf fmask = {};
380 unsigned fmask_flags, bpe;
381
382 templ.nr_samples = 1;
383 fmask_flags = flags | RADEON_SURF_FMASK;
384
385 switch (tex->nr_samples) {
386 case 2:
387 case 4:
388 bpe = 1;
389 break;
390 case 8:
391 bpe = 4;
392 break;
393 default:
394 fprintf(stderr, "radeon: Invalid sample count for FMASK allocation.\n");
395 return -1;
396 }
397
398 if (radeon_winsys_surface_init(rws, &templ, fmask_flags, bpe,
399 RADEON_SURF_MODE_2D, &fmask)) {
400 fprintf(stderr, "Got error in surface_init while allocating FMASK.\n");
401 return -1;
402 }
403
404 assert(fmask.u.legacy.level[0].mode == RADEON_SURF_MODE_2D);
405
406 surf_ws->fmask_size = fmask.surf_size;
407 surf_ws->fmask_alignment = MAX2(256, fmask.surf_alignment);
408 surf_ws->fmask_tile_swizzle = fmask.tile_swizzle;
409
410 surf_ws->u.legacy.fmask.slice_tile_max =
411 (fmask.u.legacy.level[0].nblk_x * fmask.u.legacy.level[0].nblk_y) / 64;
412 if (surf_ws->u.legacy.fmask.slice_tile_max)
413 surf_ws->u.legacy.fmask.slice_tile_max -= 1;
414
415 surf_ws->u.legacy.fmask.tiling_index = fmask.u.legacy.tiling_index[0];
416 surf_ws->u.legacy.fmask.bankh = fmask.u.legacy.bankh;
417 surf_ws->u.legacy.fmask.pitch_in_pixels = fmask.u.legacy.level[0].nblk_x;
418 }
419
420 if (ws->gen == DRV_SI &&
421 (tex->nr_samples <= 1 || surf_ws->fmask_size)) {
422 struct ac_surf_config config;
423
424 /* Only these fields need to be set for the CMASK computation. */
425 config.info.width = tex->width0;
426 config.info.height = tex->height0;
427 config.info.depth = tex->depth0;
428 config.info.array_size = tex->array_size;
429 config.is_3d = !!(tex->target == PIPE_TEXTURE_3D);
430 config.is_cube = !!(tex->target == PIPE_TEXTURE_CUBE);
431
432 si_compute_cmask(&ws->info, &config, surf_ws);
433 }
434
435 if (ws->gen == DRV_SI) {
436 si_compute_htile(&ws->info, surf_ws, util_num_layers(tex, 0));
437
438 /* Determine the memory layout of multiple allocations in one buffer. */
439 surf_ws->total_size = surf_ws->surf_size;
440
441 if (surf_ws->htile_size) {
442 surf_ws->htile_offset = align64(surf_ws->total_size, surf_ws->htile_alignment);
443 surf_ws->total_size = surf_ws->htile_offset + surf_ws->htile_size;
444 }
445
446 if (surf_ws->fmask_size) {
447 assert(tex->nr_samples >= 2);
448 surf_ws->fmask_offset = align64(surf_ws->total_size, surf_ws->fmask_alignment);
449 surf_ws->total_size = surf_ws->fmask_offset + surf_ws->fmask_size;
450 }
451
452 /* Single-sample CMASK is in a separate buffer. */
453 if (surf_ws->cmask_size && tex->nr_samples >= 2) {
454 surf_ws->cmask_offset = align64(surf_ws->total_size, surf_ws->cmask_alignment);
455 surf_ws->total_size = surf_ws->cmask_offset + surf_ws->cmask_size;
456 }
457 }
458
459 return 0;
460 }
461
462 void radeon_surface_init_functions(struct radeon_drm_winsys *ws)
463 {
464 ws->base.surface_init = radeon_winsys_surface_init;
465 }