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