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 
cik_get_macro_tile_index(struct radeon_surf * surf)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 
set_micro_tile_mode(struct radeon_surf * surf,struct radeon_info * info)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 
surf_level_winsys_to_drm(struct radeon_surface_level * level_drm,const struct legacy_surf_level * level_ws,unsigned bpe)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 
surf_level_drm_to_winsys(struct legacy_surf_level * level_ws,const struct radeon_surface_level * level_drm,unsigned bpe)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 
surf_winsys_to_drm(struct radeon_surface * surf_drm,const struct pipe_resource * tex,unsigned flags,unsigned bpe,enum radeon_surf_mode mode,const struct radeon_surf * surf_ws)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 
surf_drm_to_winsys(struct radeon_drm_winsys * ws,struct radeon_surf * surf_ws,const struct radeon_surface * surf_drm)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_RENDER;
221 }
222 
si_compute_cmask(const struct radeon_info * info,const struct ac_surf_config * config,struct radeon_surf * surf)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 
si_compute_htile(const struct radeon_info * info,struct radeon_surf * surf,unsigned num_layers)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 
radeon_winsys_surface_init(struct radeon_winsys * rws,const struct pipe_resource * tex,unsigned flags,unsigned bpe,enum radeon_surf_mode mode,struct radeon_surf * surf_ws)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 
radeon_surface_init_functions(struct radeon_drm_winsys * ws)462 void radeon_surface_init_functions(struct radeon_drm_winsys *ws)
463 {
464    ws->base.surface_init = radeon_winsys_surface_init;
465 }
466