2 * Copyright © 2011 Red Hat All Rights Reserved.
3 * Copyright © 2014 Advanced Micro Devices, Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
18 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
23 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
29 * Marek Olšák <maraeo@gmail.com>
32 #include "amdgpu_winsys.h"
38 #ifndef NO_MACRO_ENTRIES
39 #define NO_MACRO_ENTRIES 16
42 #ifndef CIASICIDGFXENGINE_SOUTHERNISLAND
43 #define CIASICIDGFXENGINE_SOUTHERNISLAND 0x0000000A
47 static int amdgpu_surface_sanity(const struct radeon_surf
*surf
)
49 unsigned type
= RADEON_SURF_GET(surf
->flags
, TYPE
);
51 if (!(surf
->flags
& RADEON_SURF_HAS_TILE_MODE_INDEX
))
54 /* all dimension must be at least 1 ! */
55 if (!surf
->npix_x
|| !surf
->npix_y
|| !surf
->npix_z
||
59 if (!surf
->blk_w
|| !surf
->blk_h
|| !surf
->blk_d
)
62 switch (surf
->nsamples
) {
73 case RADEON_SURF_TYPE_1D
:
77 case RADEON_SURF_TYPE_2D
:
78 case RADEON_SURF_TYPE_CUBEMAP
:
79 if (surf
->npix_z
> 1 || surf
->array_size
> 1)
82 case RADEON_SURF_TYPE_3D
:
83 if (surf
->array_size
> 1)
86 case RADEON_SURF_TYPE_1D_ARRAY
:
90 case RADEON_SURF_TYPE_2D_ARRAY
:
100 static void *ADDR_API
allocSysMem(const ADDR_ALLOCSYSMEM_INPUT
* pInput
)
102 return malloc(pInput
->sizeInBytes
);
105 static ADDR_E_RETURNCODE ADDR_API
freeSysMem(const ADDR_FREESYSMEM_INPUT
* pInput
)
107 free(pInput
->pVirtAddr
);
111 ADDR_HANDLE
amdgpu_addr_create(struct amdgpu_winsys
*ws
)
113 ADDR_CREATE_INPUT addrCreateInput
= {0};
114 ADDR_CREATE_OUTPUT addrCreateOutput
= {0};
115 ADDR_REGISTER_VALUE regValue
= {0};
116 ADDR_CREATE_FLAGS createFlags
= {{0}};
117 ADDR_E_RETURNCODE addrRet
;
119 addrCreateInput
.size
= sizeof(ADDR_CREATE_INPUT
);
120 addrCreateOutput
.size
= sizeof(ADDR_CREATE_OUTPUT
);
122 regValue
.noOfBanks
= ws
->amdinfo
.mc_arb_ramcfg
& 0x3;
123 regValue
.gbAddrConfig
= ws
->amdinfo
.gb_addr_cfg
;
124 regValue
.noOfRanks
= (ws
->amdinfo
.mc_arb_ramcfg
& 0x4) >> 2;
126 regValue
.backendDisables
= ws
->amdinfo
.backend_disable
[0];
127 regValue
.pTileConfig
= ws
->amdinfo
.gb_tile_mode
;
128 regValue
.noOfEntries
= ARRAY_SIZE(ws
->amdinfo
.gb_tile_mode
);
129 regValue
.pMacroTileConfig
= ws
->amdinfo
.gb_macro_tile_mode
;
130 regValue
.noOfMacroEntries
= ARRAY_SIZE(ws
->amdinfo
.gb_macro_tile_mode
);
132 createFlags
.value
= 0;
133 createFlags
.useTileIndex
= 1;
134 createFlags
.degradeBaseLevel
= 1;
136 addrCreateInput
.chipEngine
= CIASICIDGFXENGINE_SOUTHERNISLAND
;
137 addrCreateInput
.chipFamily
= ws
->family
;
138 addrCreateInput
.chipRevision
= ws
->rev_id
;
139 addrCreateInput
.createFlags
= createFlags
;
140 addrCreateInput
.callbacks
.allocSysMem
= allocSysMem
;
141 addrCreateInput
.callbacks
.freeSysMem
= freeSysMem
;
142 addrCreateInput
.callbacks
.debugPrint
= 0;
143 addrCreateInput
.regValue
= regValue
;
145 addrRet
= AddrCreate(&addrCreateInput
, &addrCreateOutput
);
146 if (addrRet
!= ADDR_OK
)
149 return addrCreateOutput
.hLib
;
152 static int compute_level(struct amdgpu_winsys
*ws
,
153 struct radeon_surf
*surf
, bool is_stencil
,
154 unsigned level
, unsigned type
, bool compressed
,
155 ADDR_COMPUTE_SURFACE_INFO_INPUT
*AddrSurfInfoIn
,
156 ADDR_COMPUTE_SURFACE_INFO_OUTPUT
*AddrSurfInfoOut
,
157 ADDR_COMPUTE_DCCINFO_INPUT
*AddrDccIn
,
158 ADDR_COMPUTE_DCCINFO_OUTPUT
*AddrDccOut
)
160 struct radeon_surf_level
*surf_level
;
161 ADDR_E_RETURNCODE ret
;
163 AddrSurfInfoIn
->mipLevel
= level
;
164 AddrSurfInfoIn
->width
= u_minify(surf
->npix_x
, level
);
165 AddrSurfInfoIn
->height
= u_minify(surf
->npix_y
, level
);
167 if (type
== RADEON_SURF_TYPE_3D
)
168 AddrSurfInfoIn
->numSlices
= u_minify(surf
->npix_z
, level
);
169 else if (type
== RADEON_SURF_TYPE_CUBEMAP
)
170 AddrSurfInfoIn
->numSlices
= 6;
172 AddrSurfInfoIn
->numSlices
= surf
->array_size
;
175 /* Set the base level pitch. This is needed for calculation
176 * of non-zero levels. */
178 AddrSurfInfoIn
->basePitch
= surf
->stencil_level
[0].nblk_x
;
180 AddrSurfInfoIn
->basePitch
= surf
->level
[0].nblk_x
;
182 /* Convert blocks to pixels for compressed formats. */
184 AddrSurfInfoIn
->basePitch
*= surf
->blk_w
;
187 ret
= AddrComputeSurfaceInfo(ws
->addrlib
,
190 if (ret
!= ADDR_OK
) {
194 surf_level
= is_stencil
? &surf
->stencil_level
[level
] : &surf
->level
[level
];
195 surf_level
->offset
= align64(surf
->bo_size
, AddrSurfInfoOut
->baseAlign
);
196 surf_level
->slice_size
= AddrSurfInfoOut
->sliceSize
;
197 surf_level
->pitch_bytes
= AddrSurfInfoOut
->pitch
* (is_stencil
? 1 : surf
->bpe
);
198 surf_level
->npix_x
= u_minify(surf
->npix_x
, level
);
199 surf_level
->npix_y
= u_minify(surf
->npix_y
, level
);
200 surf_level
->npix_z
= u_minify(surf
->npix_z
, level
);
201 surf_level
->nblk_x
= AddrSurfInfoOut
->pitch
;
202 surf_level
->nblk_y
= AddrSurfInfoOut
->height
;
203 if (type
== RADEON_SURF_TYPE_3D
)
204 surf_level
->nblk_z
= AddrSurfInfoOut
->depth
;
206 surf_level
->nblk_z
= 1;
208 switch (AddrSurfInfoOut
->tileMode
) {
209 case ADDR_TM_LINEAR_ALIGNED
:
210 surf_level
->mode
= RADEON_SURF_MODE_LINEAR_ALIGNED
;
212 case ADDR_TM_1D_TILED_THIN1
:
213 surf_level
->mode
= RADEON_SURF_MODE_1D
;
215 case ADDR_TM_2D_TILED_THIN1
:
216 surf_level
->mode
= RADEON_SURF_MODE_2D
;
223 surf
->stencil_tiling_index
[level
] = AddrSurfInfoOut
->tileIndex
;
225 surf
->tiling_index
[level
] = AddrSurfInfoOut
->tileIndex
;
227 surf
->bo_size
= surf_level
->offset
+ AddrSurfInfoOut
->surfSize
;
229 /* Clear DCC fields at the beginning. */
230 surf_level
->dcc_offset
= 0;
231 surf_level
->dcc_enabled
= false;
233 /* The previous level's flag tells us if we can use DCC for this level. */
234 if (AddrSurfInfoIn
->flags
.dccCompatible
&&
235 (level
== 0 || AddrDccOut
->subLvlCompressible
)) {
236 AddrDccIn
->colorSurfSize
= AddrSurfInfoOut
->surfSize
;
237 AddrDccIn
->tileMode
= AddrSurfInfoOut
->tileMode
;
238 AddrDccIn
->tileInfo
= *AddrSurfInfoOut
->pTileInfo
;
239 AddrDccIn
->tileIndex
= AddrSurfInfoOut
->tileIndex
;
240 AddrDccIn
->macroModeIndex
= AddrSurfInfoOut
->macroModeIndex
;
242 ret
= AddrComputeDccInfo(ws
->addrlib
,
246 if (ret
== ADDR_OK
) {
247 surf_level
->dcc_offset
= surf
->dcc_size
;
248 surf_level
->dcc_fast_clear_size
= AddrDccOut
->dccFastClearSize
;
249 surf_level
->dcc_enabled
= true;
250 surf
->dcc_size
= surf_level
->dcc_offset
+ AddrDccOut
->dccRamSize
;
251 surf
->dcc_alignment
= MAX2(surf
->dcc_alignment
, AddrDccOut
->dccRamBaseAlign
);
258 #define G_009910_MICRO_TILE_MODE(x) (((x) >> 0) & 0x03)
259 #define G_009910_MICRO_TILE_MODE_NEW(x) (((x) >> 22) & 0x07)
261 static void set_micro_tile_mode(struct radeon_surf
*surf
,
262 struct radeon_info
*info
)
264 uint32_t tile_mode
= info
->si_tile_mode_array
[surf
->tiling_index
[0]];
266 if (info
->chip_class
>= CIK
)
267 surf
->micro_tile_mode
= G_009910_MICRO_TILE_MODE_NEW(tile_mode
);
269 surf
->micro_tile_mode
= G_009910_MICRO_TILE_MODE(tile_mode
);
272 static int amdgpu_surface_init(struct radeon_winsys
*rws
,
273 struct radeon_surf
*surf
)
275 struct amdgpu_winsys
*ws
= (struct amdgpu_winsys
*)rws
;
276 unsigned level
, mode
, type
;
278 ADDR_COMPUTE_SURFACE_INFO_INPUT AddrSurfInfoIn
= {0};
279 ADDR_COMPUTE_SURFACE_INFO_OUTPUT AddrSurfInfoOut
= {0};
280 ADDR_COMPUTE_DCCINFO_INPUT AddrDccIn
= {0};
281 ADDR_COMPUTE_DCCINFO_OUTPUT AddrDccOut
= {0};
282 ADDR_TILEINFO AddrTileInfoIn
= {0};
283 ADDR_TILEINFO AddrTileInfoOut
= {0};
286 r
= amdgpu_surface_sanity(surf
);
290 AddrSurfInfoIn
.size
= sizeof(ADDR_COMPUTE_SURFACE_INFO_INPUT
);
291 AddrSurfInfoOut
.size
= sizeof(ADDR_COMPUTE_SURFACE_INFO_OUTPUT
);
292 AddrDccIn
.size
= sizeof(ADDR_COMPUTE_DCCINFO_INPUT
);
293 AddrDccOut
.size
= sizeof(ADDR_COMPUTE_DCCINFO_OUTPUT
);
294 AddrSurfInfoOut
.pTileInfo
= &AddrTileInfoOut
;
296 type
= RADEON_SURF_GET(surf
->flags
, TYPE
);
297 mode
= RADEON_SURF_GET(surf
->flags
, MODE
);
298 compressed
= surf
->blk_w
== 4 && surf
->blk_h
== 4;
300 /* MSAA and FMASK require 2D tiling. */
301 if (surf
->nsamples
> 1 ||
302 (surf
->flags
& RADEON_SURF_FMASK
))
303 mode
= RADEON_SURF_MODE_2D
;
305 /* DB doesn't support linear layouts. */
306 if (surf
->flags
& (RADEON_SURF_Z_OR_SBUFFER
) &&
307 mode
< RADEON_SURF_MODE_1D
)
308 mode
= RADEON_SURF_MODE_1D
;
310 /* Set the requested tiling mode. */
312 case RADEON_SURF_MODE_LINEAR_ALIGNED
:
313 AddrSurfInfoIn
.tileMode
= ADDR_TM_LINEAR_ALIGNED
;
315 case RADEON_SURF_MODE_1D
:
316 AddrSurfInfoIn
.tileMode
= ADDR_TM_1D_TILED_THIN1
;
318 case RADEON_SURF_MODE_2D
:
319 AddrSurfInfoIn
.tileMode
= ADDR_TM_2D_TILED_THIN1
;
325 /* The format must be set correctly for the allocation of compressed
326 * textures to work. In other cases, setting the bpp is sufficient. */
330 AddrSurfInfoIn
.format
= ADDR_FMT_BC1
;
333 AddrSurfInfoIn
.format
= ADDR_FMT_BC3
;
340 AddrDccIn
.bpp
= AddrSurfInfoIn
.bpp
= surf
->bpe
* 8;
343 AddrDccIn
.numSamples
= AddrSurfInfoIn
.numSamples
= surf
->nsamples
;
344 AddrSurfInfoIn
.tileIndex
= -1;
346 /* Set the micro tile type. */
347 if (surf
->flags
& RADEON_SURF_SCANOUT
)
348 AddrSurfInfoIn
.tileType
= ADDR_DISPLAYABLE
;
349 else if (surf
->flags
& RADEON_SURF_Z_OR_SBUFFER
)
350 AddrSurfInfoIn
.tileType
= ADDR_DEPTH_SAMPLE_ORDER
;
352 AddrSurfInfoIn
.tileType
= ADDR_NON_DISPLAYABLE
;
354 AddrSurfInfoIn
.flags
.color
= !(surf
->flags
& RADEON_SURF_Z_OR_SBUFFER
);
355 AddrSurfInfoIn
.flags
.depth
= (surf
->flags
& RADEON_SURF_ZBUFFER
) != 0;
356 AddrSurfInfoIn
.flags
.cube
= type
== RADEON_SURF_TYPE_CUBEMAP
;
357 AddrSurfInfoIn
.flags
.display
= (surf
->flags
& RADEON_SURF_SCANOUT
) != 0;
358 AddrSurfInfoIn
.flags
.pow2Pad
= surf
->last_level
> 0;
359 AddrSurfInfoIn
.flags
.degrade4Space
= 1;
362 * - If we add MSAA support, keep in mind that CB can't decompress 8bpp
364 * - Mipmapped array textures have low performance (discovered by a closed
367 AddrSurfInfoIn
.flags
.dccCompatible
= !(surf
->flags
& RADEON_SURF_Z_OR_SBUFFER
) &&
368 !(surf
->flags
& RADEON_SURF_SCANOUT
) &&
369 !(surf
->flags
& RADEON_SURF_DISABLE_DCC
) &&
370 !compressed
&& AddrDccIn
.numSamples
<= 1 &&
371 ((surf
->array_size
== 1 && surf
->npix_z
== 1) ||
372 surf
->last_level
== 0);
374 AddrSurfInfoIn
.flags
.noStencil
= (surf
->flags
& RADEON_SURF_SBUFFER
) == 0;
375 AddrSurfInfoIn
.flags
.compressZ
= AddrSurfInfoIn
.flags
.depth
;
377 /* TODO: update addrlib to a newer version, remove this, and
378 * set flags.matchStencilTileCfg = 1 to fix stencil texturing.
380 AddrSurfInfoIn
.flags
.noStencil
= 1;
382 /* Set preferred macrotile parameters. This is usually required
383 * for shared resources. This is for 2D tiling only. */
384 if (AddrSurfInfoIn
.tileMode
>= ADDR_TM_2D_TILED_THIN1
&&
385 surf
->bankw
&& surf
->bankh
&& surf
->mtilea
&& surf
->tile_split
) {
386 /* If any of these parameters are incorrect, the calculation
388 AddrTileInfoIn
.banks
= surf
->num_banks
;
389 AddrTileInfoIn
.bankWidth
= surf
->bankw
;
390 AddrTileInfoIn
.bankHeight
= surf
->bankh
;
391 AddrTileInfoIn
.macroAspectRatio
= surf
->mtilea
;
392 AddrTileInfoIn
.tileSplitBytes
= surf
->tile_split
;
393 AddrTileInfoIn
.pipeConfig
= surf
->pipe_config
+ 1; /* +1 compared to GB_TILE_MODE */
394 AddrSurfInfoIn
.flags
.degrade4Space
= 0;
395 AddrSurfInfoIn
.pTileInfo
= &AddrTileInfoIn
;
397 /* If AddrSurfInfoIn.pTileInfo is set, Addrlib doesn't set
398 * the tile index, because we are expected to know it if
399 * we know the other parameters.
401 * This is something that can easily be fixed in Addrlib.
402 * For now, just figure it out here.
403 * Note that only 2D_TILE_THIN1 is handled here.
405 assert(!(surf
->flags
& RADEON_SURF_Z_OR_SBUFFER
));
406 assert(AddrSurfInfoIn
.tileMode
== ADDR_TM_2D_TILED_THIN1
);
408 if (AddrSurfInfoIn
.tileType
== ADDR_DISPLAYABLE
)
409 AddrSurfInfoIn
.tileIndex
= 10; /* 2D displayable */
411 AddrSurfInfoIn
.tileIndex
= 14; /* 2D non-displayable */
416 surf
->dcc_alignment
= 1;
418 /* Calculate texture layout information. */
419 for (level
= 0; level
<= surf
->last_level
; level
++) {
420 r
= compute_level(ws
, surf
, false, level
, type
, compressed
,
421 &AddrSurfInfoIn
, &AddrSurfInfoOut
, &AddrDccIn
, &AddrDccOut
);
426 surf
->bo_alignment
= AddrSurfInfoOut
.baseAlign
;
427 surf
->pipe_config
= AddrSurfInfoOut
.pTileInfo
->pipeConfig
- 1;
428 set_micro_tile_mode(surf
, &ws
->info
);
430 /* For 2D modes only. */
431 if (AddrSurfInfoOut
.tileMode
>= ADDR_TM_2D_TILED_THIN1
) {
432 surf
->bankw
= AddrSurfInfoOut
.pTileInfo
->bankWidth
;
433 surf
->bankh
= AddrSurfInfoOut
.pTileInfo
->bankHeight
;
434 surf
->mtilea
= AddrSurfInfoOut
.pTileInfo
->macroAspectRatio
;
435 surf
->tile_split
= AddrSurfInfoOut
.pTileInfo
->tileSplitBytes
;
436 surf
->num_banks
= AddrSurfInfoOut
.pTileInfo
->banks
;
437 surf
->macro_tile_index
= AddrSurfInfoOut
.macroModeIndex
;
439 surf
->macro_tile_index
= 0;
444 /* Calculate texture layout information for stencil. */
445 if (surf
->flags
& RADEON_SURF_SBUFFER
) {
446 AddrSurfInfoIn
.bpp
= 8;
447 AddrSurfInfoIn
.flags
.depth
= 0;
448 AddrSurfInfoIn
.flags
.stencil
= 1;
449 /* This will be ignored if AddrSurfInfoIn.pTileInfo is NULL. */
450 AddrTileInfoIn
.tileSplitBytes
= surf
->stencil_tile_split
;
452 for (level
= 0; level
<= surf
->last_level
; level
++) {
453 r
= compute_level(ws
, surf
, true, level
, type
, compressed
,
454 &AddrSurfInfoIn
, &AddrSurfInfoOut
, &AddrDccIn
, &AddrDccOut
);
459 surf
->stencil_offset
= surf
->stencil_level
[0].offset
;
461 /* For 2D modes only. */
462 if (AddrSurfInfoOut
.tileMode
>= ADDR_TM_2D_TILED_THIN1
) {
463 surf
->stencil_tile_split
=
464 AddrSurfInfoOut
.pTileInfo
->tileSplitBytes
;
470 /* Recalculate the whole DCC miptree size including disabled levels.
471 * This is what addrlib does, but calling addrlib would be a lot more
474 if (surf
->dcc_size
&& surf
->last_level
> 0) {
475 surf
->dcc_size
= align64(surf
->bo_size
>> 8,
476 ws
->info
.pipe_interleave_bytes
*
477 ws
->info
.num_tile_pipes
);
483 static int amdgpu_surface_best(struct radeon_winsys
*rws
,
484 struct radeon_surf
*surf
)
489 void amdgpu_surface_init_functions(struct amdgpu_winsys
*ws
)
491 ws
->base
.surface_init
= amdgpu_surface_init
;
492 ws
->base
.surface_best
= amdgpu_surface_best
;