2 * Copyright © 2016 Red Hat.
3 * Copyright © 2016 Bas Nieuwenhuizen
5 * based on amdgpu winsys.
6 * Copyright © 2011 Marek Olšák <maraeo@gmail.com>
7 * Copyright © 2015 Advanced Micro Devices, Inc.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31 #include "radv_private.h"
32 #include "addrlib/addrinterface.h"
33 #include "util/bitset.h"
34 #include "radv_amdgpu_winsys.h"
35 #include "radv_amdgpu_surface.h"
38 #include "ac_surface.h"
40 static int radv_amdgpu_surface_sanity(const struct ac_surf_info
*surf_info
,
41 const struct radeon_surf
*surf
)
43 unsigned type
= RADEON_SURF_GET(surf
->flags
, TYPE
);
45 if (!(surf
->flags
& RADEON_SURF_HAS_TILE_MODE_INDEX
))
48 /* all dimension must be at least 1 ! */
49 if (!surf_info
->width
|| !surf_info
->height
|| !surf_info
->depth
||
50 !surf_info
->array_size
)
53 if (!surf
->blk_w
|| !surf
->blk_h
)
56 switch (surf_info
->samples
) {
67 case RADEON_SURF_TYPE_1D
:
68 if (surf_info
->height
> 1)
71 case RADEON_SURF_TYPE_2D
:
72 case RADEON_SURF_TYPE_CUBEMAP
:
73 if (surf_info
->depth
> 1 || surf_info
->array_size
> 1)
76 case RADEON_SURF_TYPE_3D
:
77 if (surf_info
->array_size
> 1)
80 case RADEON_SURF_TYPE_1D_ARRAY
:
81 if (surf_info
->height
> 1)
84 case RADEON_SURF_TYPE_2D_ARRAY
:
85 if (surf_info
->depth
> 1)
94 static int radv_compute_level(ADDR_HANDLE addrlib
,
95 const struct ac_surf_info
*surf_info
,
96 struct radeon_surf
*surf
, bool is_stencil
,
97 unsigned level
, unsigned type
, bool compressed
,
98 ADDR_COMPUTE_SURFACE_INFO_INPUT
*AddrSurfInfoIn
,
99 ADDR_COMPUTE_SURFACE_INFO_OUTPUT
*AddrSurfInfoOut
,
100 ADDR_COMPUTE_DCCINFO_INPUT
*AddrDccIn
,
101 ADDR_COMPUTE_DCCINFO_OUTPUT
*AddrDccOut
)
103 struct legacy_surf_level
*surf_level
;
104 ADDR_E_RETURNCODE ret
;
106 AddrSurfInfoIn
->mipLevel
= level
;
107 AddrSurfInfoIn
->width
= u_minify(surf_info
->width
, level
);
108 AddrSurfInfoIn
->height
= u_minify(surf_info
->height
, level
);
110 if (type
== RADEON_SURF_TYPE_3D
)
111 AddrSurfInfoIn
->numSlices
= u_minify(surf_info
->depth
, level
);
112 else if (type
== RADEON_SURF_TYPE_CUBEMAP
)
113 AddrSurfInfoIn
->numSlices
= 6;
115 AddrSurfInfoIn
->numSlices
= surf_info
->array_size
;
118 /* Set the base level pitch. This is needed for calculation
119 * of non-zero levels. */
121 AddrSurfInfoIn
->basePitch
= surf
->u
.legacy
.stencil_level
[0].nblk_x
;
123 AddrSurfInfoIn
->basePitch
= surf
->u
.legacy
.level
[0].nblk_x
;
125 /* Convert blocks to pixels for compressed formats. */
127 AddrSurfInfoIn
->basePitch
*= surf
->blk_w
;
130 ret
= AddrComputeSurfaceInfo(addrlib
,
136 surf_level
= is_stencil
? &surf
->u
.legacy
.stencil_level
[level
] : &surf
->u
.legacy
.level
[level
];
137 surf_level
->offset
= align64(surf
->surf_size
, AddrSurfInfoOut
->baseAlign
);
138 surf_level
->slice_size
= AddrSurfInfoOut
->sliceSize
;
139 surf_level
->nblk_x
= AddrSurfInfoOut
->pitch
;
140 surf_level
->nblk_y
= AddrSurfInfoOut
->height
;
142 switch (AddrSurfInfoOut
->tileMode
) {
143 case ADDR_TM_LINEAR_ALIGNED
:
144 surf_level
->mode
= RADEON_SURF_MODE_LINEAR_ALIGNED
;
146 case ADDR_TM_1D_TILED_THIN1
:
147 surf_level
->mode
= RADEON_SURF_MODE_1D
;
149 case ADDR_TM_2D_TILED_THIN1
:
150 surf_level
->mode
= RADEON_SURF_MODE_2D
;
157 surf
->u
.legacy
.stencil_tiling_index
[level
] = AddrSurfInfoOut
->tileIndex
;
159 surf
->u
.legacy
.tiling_index
[level
] = AddrSurfInfoOut
->tileIndex
;
161 surf
->surf_size
= surf_level
->offset
+ AddrSurfInfoOut
->surfSize
;
163 /* Clear DCC fields at the beginning. */
164 surf_level
->dcc_offset
= 0;
166 /* The previous level's flag tells us if we can use DCC for this level. */
167 if (AddrSurfInfoIn
->flags
.dccCompatible
&&
168 (level
== 0 || AddrDccOut
->subLvlCompressible
)) {
169 AddrDccIn
->colorSurfSize
= AddrSurfInfoOut
->surfSize
;
170 AddrDccIn
->tileMode
= AddrSurfInfoOut
->tileMode
;
171 AddrDccIn
->tileInfo
= *AddrSurfInfoOut
->pTileInfo
;
172 AddrDccIn
->tileIndex
= AddrSurfInfoOut
->tileIndex
;
173 AddrDccIn
->macroModeIndex
= AddrSurfInfoOut
->macroModeIndex
;
175 ret
= AddrComputeDccInfo(addrlib
,
179 if (ret
== ADDR_OK
) {
180 surf_level
->dcc_offset
= surf
->dcc_size
;
181 surf_level
->dcc_fast_clear_size
= AddrDccOut
->dccFastClearSize
;
182 surf
->num_dcc_levels
= level
+ 1;
183 surf
->dcc_size
= surf_level
->dcc_offset
+ AddrDccOut
->dccRamSize
;
184 surf
->dcc_alignment
= MAX2(surf
->dcc_alignment
, AddrDccOut
->dccRamBaseAlign
);
188 if (!is_stencil
&& AddrSurfInfoIn
->flags
.depth
&&
189 surf_level
->mode
== RADEON_SURF_MODE_2D
&& level
== 0) {
190 ADDR_COMPUTE_HTILE_INFO_INPUT AddrHtileIn
= {0};
191 ADDR_COMPUTE_HTILE_INFO_OUTPUT AddrHtileOut
= {0};
192 AddrHtileIn
.flags
.tcCompatible
= AddrSurfInfoIn
->flags
.tcCompatible
;
193 AddrHtileIn
.pitch
= AddrSurfInfoOut
->pitch
;
194 AddrHtileIn
.height
= AddrSurfInfoOut
->height
;
195 AddrHtileIn
.numSlices
= AddrSurfInfoOut
->depth
;
196 AddrHtileIn
.blockWidth
= ADDR_HTILE_BLOCKSIZE_8
;
197 AddrHtileIn
.blockHeight
= ADDR_HTILE_BLOCKSIZE_8
;
198 AddrHtileIn
.pTileInfo
= AddrSurfInfoOut
->pTileInfo
;
199 AddrHtileIn
.tileIndex
= AddrSurfInfoOut
->tileIndex
;
200 AddrHtileIn
.macroModeIndex
= AddrSurfInfoOut
->macroModeIndex
;
202 ret
= AddrComputeHtileInfo(addrlib
,
206 if (ret
== ADDR_OK
) {
207 surf
->htile_size
= AddrHtileOut
.htileBytes
;
208 surf
->htile_slice_size
= AddrHtileOut
.sliceSize
;
209 surf
->htile_alignment
= AddrHtileOut
.baseAlign
;
215 static void radv_set_micro_tile_mode(struct radeon_surf
*surf
,
216 struct radeon_info
*info
)
218 uint32_t tile_mode
= info
->si_tile_mode_array
[surf
->u
.legacy
.tiling_index
[0]];
220 if (info
->chip_class
>= CIK
)
221 surf
->micro_tile_mode
= G_009910_MICRO_TILE_MODE_NEW(tile_mode
);
223 surf
->micro_tile_mode
= G_009910_MICRO_TILE_MODE(tile_mode
);
226 static unsigned cik_get_macro_tile_index(struct radeon_surf
*surf
)
228 unsigned index
, tileb
;
230 tileb
= 8 * 8 * surf
->bpe
;
231 tileb
= MIN2(surf
->u
.legacy
.tile_split
, tileb
);
233 for (index
= 0; tileb
> 64; index
++)
240 static int radv_amdgpu_winsys_surface_init(struct radeon_winsys
*_ws
,
241 const struct ac_surf_info
*surf_info
,
242 struct radeon_surf
*surf
)
244 struct radv_amdgpu_winsys
*ws
= radv_amdgpu_winsys(_ws
);
245 unsigned level
, mode
, type
;
247 ADDR_COMPUTE_SURFACE_INFO_INPUT AddrSurfInfoIn
= {0};
248 ADDR_COMPUTE_SURFACE_INFO_OUTPUT AddrSurfInfoOut
= {0};
249 ADDR_COMPUTE_DCCINFO_INPUT AddrDccIn
= {0};
250 ADDR_COMPUTE_DCCINFO_OUTPUT AddrDccOut
= {0};
251 ADDR_TILEINFO AddrTileInfoIn
= {0};
252 ADDR_TILEINFO AddrTileInfoOut
= {0};
254 uint32_t last_level
= surf_info
->levels
- 1;
256 r
= radv_amdgpu_surface_sanity(surf_info
, surf
);
260 AddrSurfInfoIn
.size
= sizeof(ADDR_COMPUTE_SURFACE_INFO_INPUT
);
261 AddrSurfInfoOut
.size
= sizeof(ADDR_COMPUTE_SURFACE_INFO_OUTPUT
);
262 AddrDccIn
.size
= sizeof(ADDR_COMPUTE_DCCINFO_INPUT
);
263 AddrDccOut
.size
= sizeof(ADDR_COMPUTE_DCCINFO_OUTPUT
);
264 AddrSurfInfoOut
.pTileInfo
= &AddrTileInfoOut
;
266 type
= RADEON_SURF_GET(surf
->flags
, TYPE
);
267 mode
= RADEON_SURF_GET(surf
->flags
, MODE
);
268 compressed
= surf
->blk_w
== 4 && surf
->blk_h
== 4;
270 /* MSAA and FMASK require 2D tiling. */
271 if (surf_info
->samples
> 1 ||
272 (surf
->flags
& RADEON_SURF_FMASK
))
273 mode
= RADEON_SURF_MODE_2D
;
275 /* DB doesn't support linear layouts. */
276 if (surf
->flags
& (RADEON_SURF_Z_OR_SBUFFER
) &&
277 mode
< RADEON_SURF_MODE_1D
)
278 mode
= RADEON_SURF_MODE_1D
;
280 /* Set the requested tiling mode. */
282 case RADEON_SURF_MODE_LINEAR_ALIGNED
:
283 AddrSurfInfoIn
.tileMode
= ADDR_TM_LINEAR_ALIGNED
;
285 case RADEON_SURF_MODE_1D
:
286 AddrSurfInfoIn
.tileMode
= ADDR_TM_1D_TILED_THIN1
;
288 case RADEON_SURF_MODE_2D
:
289 AddrSurfInfoIn
.tileMode
= ADDR_TM_2D_TILED_THIN1
;
295 /* The format must be set correctly for the allocation of compressed
296 * textures to work. In other cases, setting the bpp is sufficient. */
300 AddrSurfInfoIn
.format
= ADDR_FMT_BC1
;
303 AddrSurfInfoIn
.format
= ADDR_FMT_BC3
;
309 AddrDccIn
.bpp
= AddrSurfInfoIn
.bpp
= surf
->bpe
* 8;
312 AddrDccIn
.numSamples
= AddrSurfInfoIn
.numSamples
= surf_info
->samples
;
313 AddrSurfInfoIn
.tileIndex
= -1;
315 /* Set the micro tile type. */
316 if (surf
->flags
& RADEON_SURF_SCANOUT
)
317 AddrSurfInfoIn
.tileType
= ADDR_DISPLAYABLE
;
318 else if (surf
->flags
& RADEON_SURF_Z_OR_SBUFFER
)
319 AddrSurfInfoIn
.tileType
= ADDR_DEPTH_SAMPLE_ORDER
;
321 AddrSurfInfoIn
.tileType
= ADDR_NON_DISPLAYABLE
;
323 AddrSurfInfoIn
.flags
.color
= !(surf
->flags
& RADEON_SURF_Z_OR_SBUFFER
);
324 AddrSurfInfoIn
.flags
.depth
= (surf
->flags
& RADEON_SURF_ZBUFFER
) != 0;
325 AddrSurfInfoIn
.flags
.cube
= type
== RADEON_SURF_TYPE_CUBEMAP
;
326 AddrSurfInfoIn
.flags
.display
= (surf
->flags
& RADEON_SURF_SCANOUT
) != 0;
327 AddrSurfInfoIn
.flags
.pow2Pad
= last_level
> 0;
328 AddrSurfInfoIn
.flags
.opt4Space
= 1;
331 * - If we add MSAA support, keep in mind that CB can't decompress 8bpp
333 * - Mipmapped array textures have low performance (discovered by a closed
336 AddrSurfInfoIn
.flags
.dccCompatible
= !(surf
->flags
& RADEON_SURF_Z_OR_SBUFFER
) &&
337 !(surf
->flags
& RADEON_SURF_DISABLE_DCC
) &&
338 !compressed
&& AddrDccIn
.numSamples
<= 1 &&
339 ((surf_info
->array_size
== 1 && surf_info
->depth
== 1) ||
342 AddrSurfInfoIn
.flags
.noStencil
= (surf
->flags
& RADEON_SURF_SBUFFER
) == 0;
343 AddrSurfInfoIn
.flags
.compressZ
= AddrSurfInfoIn
.flags
.depth
;
345 /* noStencil = 0 can result in a depth part that is incompatible with
346 * mipmapped texturing. So set noStencil = 1 when mipmaps are requested (in
347 * this case, we may end up setting stencil_adjusted).
349 * TODO: update addrlib to a newer version, remove this, and
350 * use flags.matchStencilTileCfg = 1 as an alternative fix.
353 AddrSurfInfoIn
.flags
.noStencil
= 1;
355 /* Set preferred macrotile parameters. This is usually required
356 * for shared resources. This is for 2D tiling only. */
357 if (AddrSurfInfoIn
.tileMode
>= ADDR_TM_2D_TILED_THIN1
&&
358 surf
->u
.legacy
.bankw
&& surf
->u
.legacy
.bankh
&& surf
->u
.legacy
.mtilea
&&
359 surf
->u
.legacy
.tile_split
) {
360 /* If any of these parameters are incorrect, the calculation
362 AddrTileInfoIn
.banks
= surf
->u
.legacy
.num_banks
;
363 AddrTileInfoIn
.bankWidth
= surf
->u
.legacy
.bankw
;
364 AddrTileInfoIn
.bankHeight
= surf
->u
.legacy
.bankh
;
365 AddrTileInfoIn
.macroAspectRatio
= surf
->u
.legacy
.mtilea
;
366 AddrTileInfoIn
.tileSplitBytes
= surf
->u
.legacy
.tile_split
;
367 AddrTileInfoIn
.pipeConfig
= surf
->u
.legacy
.pipe_config
+ 1; /* +1 compared to GB_TILE_MODE */
368 AddrSurfInfoIn
.flags
.opt4Space
= 0;
369 AddrSurfInfoIn
.pTileInfo
= &AddrTileInfoIn
;
371 /* If AddrSurfInfoIn.pTileInfo is set, Addrlib doesn't set
372 * the tile index, because we are expected to know it if
373 * we know the other parameters.
375 * This is something that can easily be fixed in Addrlib.
376 * For now, just figure it out here.
377 * Note that only 2D_TILE_THIN1 is handled here.
379 assert(!(surf
->flags
& RADEON_SURF_Z_OR_SBUFFER
));
380 assert(AddrSurfInfoIn
.tileMode
== ADDR_TM_2D_TILED_THIN1
);
382 if (ws
->info
.chip_class
== SI
) {
383 if (AddrSurfInfoIn
.tileType
== ADDR_DISPLAYABLE
) {
385 AddrSurfInfoIn
.tileIndex
= 11; /* 16bpp */
387 AddrSurfInfoIn
.tileIndex
= 12; /* 32bpp */
390 AddrSurfInfoIn
.tileIndex
= 14; /* 8bpp */
391 else if (surf
->bpe
== 2)
392 AddrSurfInfoIn
.tileIndex
= 15; /* 16bpp */
393 else if (surf
->bpe
== 4)
394 AddrSurfInfoIn
.tileIndex
= 16; /* 32bpp */
396 AddrSurfInfoIn
.tileIndex
= 17; /* 64bpp (and 128bpp) */
399 if (AddrSurfInfoIn
.tileType
== ADDR_DISPLAYABLE
)
400 AddrSurfInfoIn
.tileIndex
= 10; /* 2D displayable */
402 AddrSurfInfoIn
.tileIndex
= 14; /* 2D non-displayable */
403 AddrSurfInfoOut
.macroModeIndex
= cik_get_macro_tile_index(surf
);
408 surf
->num_dcc_levels
= 0;
410 surf
->dcc_alignment
= 1;
411 surf
->htile_size
= surf
->htile_slice_size
= 0;
412 surf
->htile_alignment
= 1;
414 /* Calculate texture layout information. */
415 for (level
= 0; level
<= last_level
; level
++) {
416 r
= radv_compute_level(ws
->addrlib
, surf_info
, surf
, false, level
, type
, compressed
,
417 &AddrSurfInfoIn
, &AddrSurfInfoOut
, &AddrDccIn
, &AddrDccOut
);
422 surf
->surf_alignment
= AddrSurfInfoOut
.baseAlign
;
423 surf
->u
.legacy
.pipe_config
= AddrSurfInfoOut
.pTileInfo
->pipeConfig
- 1;
424 radv_set_micro_tile_mode(surf
, &ws
->info
);
426 /* For 2D modes only. */
427 if (AddrSurfInfoOut
.tileMode
>= ADDR_TM_2D_TILED_THIN1
) {
428 surf
->u
.legacy
.bankw
= AddrSurfInfoOut
.pTileInfo
->bankWidth
;
429 surf
->u
.legacy
.bankh
= AddrSurfInfoOut
.pTileInfo
->bankHeight
;
430 surf
->u
.legacy
.mtilea
= AddrSurfInfoOut
.pTileInfo
->macroAspectRatio
;
431 surf
->u
.legacy
.tile_split
= AddrSurfInfoOut
.pTileInfo
->tileSplitBytes
;
432 surf
->u
.legacy
.num_banks
= AddrSurfInfoOut
.pTileInfo
->banks
;
433 surf
->u
.legacy
.macro_tile_index
= AddrSurfInfoOut
.macroModeIndex
;
435 surf
->u
.legacy
.macro_tile_index
= 0;
440 /* Calculate texture layout information for stencil. */
441 if (surf
->flags
& RADEON_SURF_SBUFFER
) {
442 AddrSurfInfoIn
.bpp
= 8;
443 AddrSurfInfoIn
.flags
.depth
= 0;
444 AddrSurfInfoIn
.flags
.stencil
= 1;
445 /* This will be ignored if AddrSurfInfoIn.pTileInfo is NULL. */
446 AddrTileInfoIn
.tileSplitBytes
= surf
->u
.legacy
.stencil_tile_split
;
448 for (level
= 0; level
<= last_level
; level
++) {
449 r
= radv_compute_level(ws
->addrlib
, surf_info
, surf
, true, level
, type
, compressed
,
450 &AddrSurfInfoIn
, &AddrSurfInfoOut
, &AddrDccIn
, &AddrDccOut
);
454 /* DB uses the depth pitch for both stencil and depth. */
455 if (surf
->u
.legacy
.stencil_level
[level
].nblk_x
!= surf
->u
.legacy
.level
[level
].nblk_x
)
456 surf
->u
.legacy
.stencil_adjusted
= true;
459 /* For 2D modes only. */
460 if (AddrSurfInfoOut
.tileMode
>= ADDR_TM_2D_TILED_THIN1
) {
461 surf
->u
.legacy
.stencil_tile_split
=
462 AddrSurfInfoOut
.pTileInfo
->tileSplitBytes
;
468 /* Recalculate the whole DCC miptree size including disabled levels.
469 * This is what addrlib does, but calling addrlib would be a lot more
473 if (surf
->dcc_size
&& last_level
> 0) {
474 surf
->dcc_size
= align64(surf
->bo_size
>> 8,
475 ws
->info
.pipe_interleave_bytes
*
476 ws
->info
.num_tile_pipes
);
482 static int radv_amdgpu_winsys_surface_best(struct radeon_winsys
*rws
,
483 struct radeon_surf
*surf
)
488 void radv_amdgpu_surface_init_functions(struct radv_amdgpu_winsys
*ws
)
490 ws
->base
.surface_init
= radv_amdgpu_winsys_surface_init
;
491 ws
->base
.surface_best
= radv_amdgpu_winsys_surface_best
;