2 * Copyright © 2014 Advanced Micro Devices, Inc.
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:
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.
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
27 #include "radeon_drm_winsys.h"
28 #include "util/format/u_format.h"
29 #include <radeon_surface.h>
31 static unsigned cik_get_macro_tile_index(struct radeon_surf
*surf
)
33 unsigned index
, tileb
;
35 tileb
= 8 * 8 * surf
->bpe
;
36 tileb
= MIN2(surf
->u
.legacy
.tile_split
, tileb
);
38 for (index
= 0; tileb
> 64; index
++)
45 #define G_009910_MICRO_TILE_MODE(x) (((x) >> 0) & 0x03)
46 #define G_009910_MICRO_TILE_MODE_NEW(x) (((x) >> 22) & 0x07)
48 static void set_micro_tile_mode(struct radeon_surf
*surf
,
49 struct radeon_info
*info
)
53 if (info
->chip_class
< GFX6
) {
54 surf
->micro_tile_mode
= 0;
58 tile_mode
= info
->si_tile_mode_array
[surf
->u
.legacy
.tiling_index
[0]];
60 if (info
->chip_class
>= GFX7
)
61 surf
->micro_tile_mode
= G_009910_MICRO_TILE_MODE_NEW(tile_mode
);
63 surf
->micro_tile_mode
= G_009910_MICRO_TILE_MODE(tile_mode
);
66 static void surf_level_winsys_to_drm(struct radeon_surface_level
*level_drm
,
67 const struct legacy_surf_level
*level_ws
,
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
;
78 static void surf_level_drm_to_winsys(struct legacy_surf_level
*level_ws
,
79 const struct radeon_surface_level
*level_drm
,
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
);
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
)
98 memset(surf_drm
, 0, sizeof(*surf_drm
));
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
);
106 surf_drm
->array_size
= 1;
107 surf_drm
->last_level
= tex
->last_level
;
109 surf_drm
->nsamples
= tex
->nr_samples
? tex
->nr_samples
: 1;
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
;
118 switch (tex
->target
) {
119 case PIPE_TEXTURE_1D
:
120 surf_drm
->flags
|= RADEON_SURF_SET(RADEON_SURF_TYPE_1D
, TYPE
);
122 case PIPE_TEXTURE_RECT
:
123 case PIPE_TEXTURE_2D
:
124 surf_drm
->flags
|= RADEON_SURF_SET(RADEON_SURF_TYPE_2D
, TYPE
);
126 case PIPE_TEXTURE_3D
:
127 surf_drm
->flags
|= RADEON_SURF_SET(RADEON_SURF_TYPE_3D
, TYPE
);
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
;
133 case PIPE_TEXTURE_CUBE_ARRAY
: /* cube array layout like 2d array */
134 assert(tex
->array_size
% 6 == 0);
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
;
140 case PIPE_TEXTURE_CUBE
:
141 surf_drm
->flags
|= RADEON_SURF_SET(RADEON_SURF_TYPE_CUBEMAP
, TYPE
);
148 surf_drm
->bo_size
= surf_ws
->surf_size
;
149 surf_drm
->bo_alignment
= surf_ws
->surf_alignment
;
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
;
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
);
160 surf_drm
->tiling_index
[i
] = surf_ws
->u
.legacy
.tiling_index
[i
];
163 if (flags
& RADEON_SURF_SBUFFER
) {
164 surf_drm
->stencil_tile_split
= surf_ws
->u
.legacy
.stencil_tile_split
;
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
],
170 surf_drm
->stencil_tiling_index
[i
] = surf_ws
->u
.legacy
.stencil_tiling_index
[i
];
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
)
181 memset(surf_ws
, 0, sizeof(*surf_ws
));
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
;
190 surf_ws
->surf_size
= surf_drm
->bo_size
;
191 surf_ws
->surf_alignment
= surf_drm
->bo_alignment
;
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
;
198 surf_ws
->u
.legacy
.macro_tile_index
= cik_get_macro_tile_index(surf_ws
);
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
];
206 if (surf_ws
->flags
& RADEON_SURF_SBUFFER
) {
207 surf_ws
->u
.legacy
.stencil_tile_split
= surf_drm
->stencil_tile_split
;
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
],
213 surf_ws
->u
.legacy
.stencil_tiling_index
[i
] = surf_drm
->stencil_tiling_index
[i
];
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
;
223 static void si_compute_cmask(const struct radeon_info
*info
,
224 const struct ac_surf_config
*config
,
225 struct radeon_surf
*surf
)
227 unsigned pipe_interleave_bytes
= info
->pipe_interleave_bytes
;
228 unsigned num_pipes
= info
->num_tile_pipes
;
229 unsigned cl_width
, cl_height
;
231 if (surf
->flags
& RADEON_SURF_Z_OR_SBUFFER
)
234 assert(info
->chip_class
<= GFX8
);
249 case 16: /* Hawaii */
258 unsigned base_align
= num_pipes
* pipe_interleave_bytes
;
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);
264 /* Each element of CMASK is a nibble. */
265 unsigned slice_bytes
= slice_elements
/ 2;
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;
273 num_layers
= config
->info
.depth
;
274 else if (config
->is_cube
)
277 num_layers
= config
->info
.array_size
;
279 surf
->cmask_alignment
= MAX2(256, base_align
);
280 surf
->cmask_size
= align(slice_bytes
, base_align
) * num_layers
;
283 static void si_compute_htile(const struct radeon_info
*info
,
284 struct radeon_surf
*surf
, unsigned num_layers
)
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
;
290 surf
->htile_size
= 0;
292 if (!(surf
->flags
& RADEON_SURF_Z_OR_SBUFFER
) ||
293 surf
->flags
& RADEON_SURF_NO_HTILE
)
296 if (surf
->u
.legacy
.level
[0].mode
== RADEON_SURF_MODE_1D
&&
297 !info
->htile_cmask_support_1d_tiling
)
300 /* Overalign HTILE on P2 configs to work around GPU hangs in
301 * piglit/depthstencil-render-miplevels 585.
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.
307 if (info
->chip_class
>= GFX7
&& num_pipes
< 4)
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);
339 slice_elements
= (width
* height
) / (8 * 8);
340 slice_bytes
= slice_elements
* 4;
342 pipe_interleave_bytes
= info
->pipe_interleave_bytes
;
343 base_align
= num_pipes
* pipe_interleave_bytes
;
345 surf
->htile_alignment
= base_align
;
346 surf
->htile_size
= num_layers
* align(slice_bytes
, base_align
);
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
)
355 struct radeon_drm_winsys
*ws
= (struct radeon_drm_winsys
*)rws
;
356 struct radeon_surface surf_drm
;
359 surf_winsys_to_drm(&surf_drm
, tex
, flags
, bpe
, mode
, surf_ws
);
361 if (!(flags
& (RADEON_SURF_IMPORTED
| RADEON_SURF_FMASK
))) {
362 r
= radeon_surface_best(ws
->surf_man
, &surf_drm
);
367 r
= radeon_surface_init(ws
->surf_man
, &surf_drm
);
371 surf_drm_to_winsys(ws
, surf_ws
, &surf_drm
);
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
;
382 templ
.nr_samples
= 1;
383 fmask_flags
= flags
| RADEON_SURF_FMASK
;
385 switch (tex
->nr_samples
) {
394 fprintf(stderr
, "radeon: Invalid sample count for FMASK allocation.\n");
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");
404 assert(fmask
.u
.legacy
.level
[0].mode
== RADEON_SURF_MODE_2D
);
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
;
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;
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
;
420 if (ws
->gen
== DRV_SI
&&
421 (tex
->nr_samples
<= 1 || surf_ws
->fmask_size
)) {
422 struct ac_surf_config config
;
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
);
432 si_compute_cmask(&ws
->info
, &config
, surf_ws
);
435 if (ws
->gen
== DRV_SI
) {
436 si_compute_htile(&ws
->info
, surf_ws
, util_num_layers(tex
, 0));
438 /* Determine the memory layout of multiple allocations in one buffer. */
439 surf_ws
->total_size
= surf_ws
->surf_size
;
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
;
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
;
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
;
462 void radeon_surface_init_functions(struct radeon_drm_winsys
*ws
)
464 ws
->base
.surface_init
= radeon_winsys_surface_init
;