radeonsi/gfx9: fix linear mipmap CPU access
[mesa.git] / src / gallium / winsys / amdgpu / drm / amdgpu_surface.c
1 /*
2 * Copyright © 2011 Red Hat All Rights Reserved.
3 * Copyright © 2014 Advanced Micro Devices, Inc.
4 * All Rights Reserved.
5 *
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:
13 *
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.
22 *
23 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
25 * of the Software.
26 */
27
28 /* Contact:
29 * Marek Olšák <maraeo@gmail.com>
30 */
31
32 #include "amdgpu_winsys.h"
33 #include "util/u_format.h"
34
35 #ifndef CIASICIDGFXENGINE_SOUTHERNISLAND
36 #define CIASICIDGFXENGINE_SOUTHERNISLAND 0x0000000A
37 #endif
38
39 #ifndef CIASICIDGFXENGINE_ARCTICISLAND
40 #define CIASICIDGFXENGINE_ARCTICISLAND 0x0000000D
41 #endif
42
43 static int amdgpu_surface_sanity(const struct pipe_resource *tex)
44 {
45 /* all dimension must be at least 1 ! */
46 if (!tex->width0 || !tex->height0 || !tex->depth0 ||
47 !tex->array_size)
48 return -EINVAL;
49
50 switch (tex->nr_samples) {
51 case 0:
52 case 1:
53 case 2:
54 case 4:
55 case 8:
56 break;
57 default:
58 return -EINVAL;
59 }
60
61 switch (tex->target) {
62 case PIPE_TEXTURE_1D:
63 if (tex->height0 > 1)
64 return -EINVAL;
65 /* fall through */
66 case PIPE_TEXTURE_2D:
67 case PIPE_TEXTURE_RECT:
68 if (tex->depth0 > 1 || tex->array_size > 1)
69 return -EINVAL;
70 break;
71 case PIPE_TEXTURE_3D:
72 if (tex->array_size > 1)
73 return -EINVAL;
74 break;
75 case PIPE_TEXTURE_1D_ARRAY:
76 if (tex->height0 > 1)
77 return -EINVAL;
78 /* fall through */
79 case PIPE_TEXTURE_CUBE:
80 case PIPE_TEXTURE_2D_ARRAY:
81 case PIPE_TEXTURE_CUBE_ARRAY:
82 if (tex->depth0 > 1)
83 return -EINVAL;
84 break;
85 default:
86 return -EINVAL;
87 }
88 return 0;
89 }
90
91 static void *ADDR_API allocSysMem(const ADDR_ALLOCSYSMEM_INPUT * pInput)
92 {
93 return malloc(pInput->sizeInBytes);
94 }
95
96 static ADDR_E_RETURNCODE ADDR_API freeSysMem(const ADDR_FREESYSMEM_INPUT * pInput)
97 {
98 free(pInput->pVirtAddr);
99 return ADDR_OK;
100 }
101
102 ADDR_HANDLE amdgpu_addr_create(struct amdgpu_winsys *ws)
103 {
104 ADDR_CREATE_INPUT addrCreateInput = {0};
105 ADDR_CREATE_OUTPUT addrCreateOutput = {0};
106 ADDR_REGISTER_VALUE regValue = {0};
107 ADDR_CREATE_FLAGS createFlags = {{0}};
108 ADDR_E_RETURNCODE addrRet;
109
110 addrCreateInput.size = sizeof(ADDR_CREATE_INPUT);
111 addrCreateOutput.size = sizeof(ADDR_CREATE_OUTPUT);
112
113 regValue.gbAddrConfig = ws->amdinfo.gb_addr_cfg;
114 createFlags.value = 0;
115
116 if (ws->info.chip_class >= GFX9) {
117 addrCreateInput.chipEngine = CIASICIDGFXENGINE_ARCTICISLAND;
118 regValue.blockVarSizeLog2 = 0;
119 } else {
120 regValue.noOfBanks = ws->amdinfo.mc_arb_ramcfg & 0x3;
121 regValue.noOfRanks = (ws->amdinfo.mc_arb_ramcfg & 0x4) >> 2;
122
123 regValue.backendDisables = ws->amdinfo.enabled_rb_pipes_mask;
124 regValue.pTileConfig = ws->amdinfo.gb_tile_mode;
125 regValue.noOfEntries = ARRAY_SIZE(ws->amdinfo.gb_tile_mode);
126 if (ws->info.chip_class == SI) {
127 regValue.pMacroTileConfig = NULL;
128 regValue.noOfMacroEntries = 0;
129 } else {
130 regValue.pMacroTileConfig = ws->amdinfo.gb_macro_tile_mode;
131 regValue.noOfMacroEntries = ARRAY_SIZE(ws->amdinfo.gb_macro_tile_mode);
132 }
133
134 createFlags.useTileIndex = 1;
135 createFlags.useHtileSliceAlign = 1;
136
137 addrCreateInput.chipEngine = CIASICIDGFXENGINE_SOUTHERNISLAND;
138 addrCreateInput.chipFamily = ws->family;
139 addrCreateInput.chipRevision = ws->rev_id;
140 }
141
142 addrCreateInput.chipFamily = ws->family;
143 addrCreateInput.chipRevision = ws->rev_id;
144 addrCreateInput.callbacks.allocSysMem = allocSysMem;
145 addrCreateInput.callbacks.freeSysMem = freeSysMem;
146 addrCreateInput.callbacks.debugPrint = 0;
147 addrCreateInput.createFlags = createFlags;
148 addrCreateInput.regValue = regValue;
149
150 addrRet = AddrCreate(&addrCreateInput, &addrCreateOutput);
151 if (addrRet != ADDR_OK)
152 return NULL;
153
154 return addrCreateOutput.hLib;
155 }
156
157 static int gfx6_compute_level(struct amdgpu_winsys *ws,
158 const struct pipe_resource *tex,
159 struct radeon_surf *surf, bool is_stencil,
160 unsigned level, bool compressed,
161 ADDR_COMPUTE_SURFACE_INFO_INPUT *AddrSurfInfoIn,
162 ADDR_COMPUTE_SURFACE_INFO_OUTPUT *AddrSurfInfoOut,
163 ADDR_COMPUTE_DCCINFO_INPUT *AddrDccIn,
164 ADDR_COMPUTE_DCCINFO_OUTPUT *AddrDccOut,
165 ADDR_COMPUTE_HTILE_INFO_INPUT *AddrHtileIn,
166 ADDR_COMPUTE_HTILE_INFO_OUTPUT *AddrHtileOut)
167 {
168 struct legacy_surf_level *surf_level;
169 ADDR_E_RETURNCODE ret;
170
171 AddrSurfInfoIn->mipLevel = level;
172 AddrSurfInfoIn->width = u_minify(tex->width0, level);
173 AddrSurfInfoIn->height = u_minify(tex->height0, level);
174
175 if (tex->target == PIPE_TEXTURE_3D)
176 AddrSurfInfoIn->numSlices = u_minify(tex->depth0, level);
177 else if (tex->target == PIPE_TEXTURE_CUBE)
178 AddrSurfInfoIn->numSlices = 6;
179 else
180 AddrSurfInfoIn->numSlices = tex->array_size;
181
182 if (level > 0) {
183 /* Set the base level pitch. This is needed for calculation
184 * of non-zero levels. */
185 if (is_stencil)
186 AddrSurfInfoIn->basePitch = surf->u.legacy.stencil_level[0].nblk_x;
187 else
188 AddrSurfInfoIn->basePitch = surf->u.legacy.level[0].nblk_x;
189
190 /* Convert blocks to pixels for compressed formats. */
191 if (compressed)
192 AddrSurfInfoIn->basePitch *= surf->blk_w;
193 }
194
195 ret = AddrComputeSurfaceInfo(ws->addrlib,
196 AddrSurfInfoIn,
197 AddrSurfInfoOut);
198 if (ret != ADDR_OK) {
199 return ret;
200 }
201
202 surf_level = is_stencil ? &surf->u.legacy.stencil_level[level] : &surf->u.legacy.level[level];
203 surf_level->offset = align64(surf->surf_size, AddrSurfInfoOut->baseAlign);
204 surf_level->slice_size = AddrSurfInfoOut->sliceSize;
205 surf_level->nblk_x = AddrSurfInfoOut->pitch;
206 surf_level->nblk_y = AddrSurfInfoOut->height;
207
208 switch (AddrSurfInfoOut->tileMode) {
209 case ADDR_TM_LINEAR_ALIGNED:
210 surf_level->mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
211 break;
212 case ADDR_TM_1D_TILED_THIN1:
213 surf_level->mode = RADEON_SURF_MODE_1D;
214 break;
215 case ADDR_TM_2D_TILED_THIN1:
216 surf_level->mode = RADEON_SURF_MODE_2D;
217 break;
218 default:
219 assert(0);
220 }
221
222 if (is_stencil)
223 surf->u.legacy.stencil_tiling_index[level] = AddrSurfInfoOut->tileIndex;
224 else
225 surf->u.legacy.tiling_index[level] = AddrSurfInfoOut->tileIndex;
226
227 surf->surf_size = surf_level->offset + AddrSurfInfoOut->surfSize;
228
229 /* Clear DCC fields at the beginning. */
230 surf_level->dcc_offset = 0;
231
232 /* The previous level's flag tells us if we can use DCC for this level. */
233 if (AddrSurfInfoIn->flags.dccCompatible &&
234 (level == 0 || AddrDccOut->subLvlCompressible)) {
235 AddrDccIn->colorSurfSize = AddrSurfInfoOut->surfSize;
236 AddrDccIn->tileMode = AddrSurfInfoOut->tileMode;
237 AddrDccIn->tileInfo = *AddrSurfInfoOut->pTileInfo;
238 AddrDccIn->tileIndex = AddrSurfInfoOut->tileIndex;
239 AddrDccIn->macroModeIndex = AddrSurfInfoOut->macroModeIndex;
240
241 ret = AddrComputeDccInfo(ws->addrlib,
242 AddrDccIn,
243 AddrDccOut);
244
245 if (ret == ADDR_OK) {
246 surf_level->dcc_offset = surf->dcc_size;
247 surf_level->dcc_fast_clear_size = AddrDccOut->dccFastClearSize;
248 surf->num_dcc_levels = level + 1;
249 surf->dcc_size = surf_level->dcc_offset + AddrDccOut->dccRamSize;
250 surf->dcc_alignment = MAX2(surf->dcc_alignment, AddrDccOut->dccRamBaseAlign);
251 }
252 }
253
254 /* TC-compatible HTILE. */
255 if (!is_stencil &&
256 AddrSurfInfoIn->flags.depth &&
257 AddrSurfInfoIn->flags.tcCompatible &&
258 surf_level->mode == RADEON_SURF_MODE_2D &&
259 level == 0) {
260 AddrHtileIn->flags.tcCompatible = 1;
261 AddrHtileIn->pitch = AddrSurfInfoOut->pitch;
262 AddrHtileIn->height = AddrSurfInfoOut->height;
263 AddrHtileIn->numSlices = AddrSurfInfoOut->depth;
264 AddrHtileIn->blockWidth = ADDR_HTILE_BLOCKSIZE_8;
265 AddrHtileIn->blockHeight = ADDR_HTILE_BLOCKSIZE_8;
266 AddrHtileIn->pTileInfo = AddrSurfInfoOut->pTileInfo;
267 AddrHtileIn->tileIndex = AddrSurfInfoOut->tileIndex;
268 AddrHtileIn->macroModeIndex = AddrSurfInfoOut->macroModeIndex;
269
270 ret = AddrComputeHtileInfo(ws->addrlib,
271 AddrHtileIn,
272 AddrHtileOut);
273
274 if (ret == ADDR_OK) {
275 surf->htile_size = AddrHtileOut->htileBytes;
276 surf->htile_alignment = AddrHtileOut->baseAlign;
277 }
278 }
279
280 return 0;
281 }
282
283 #define G_009910_MICRO_TILE_MODE(x) (((x) >> 0) & 0x03)
284 #define G_009910_MICRO_TILE_MODE_NEW(x) (((x) >> 22) & 0x07)
285
286 static void gfx6_set_micro_tile_mode(struct radeon_surf *surf,
287 struct radeon_info *info)
288 {
289 uint32_t tile_mode = info->si_tile_mode_array[surf->u.legacy.tiling_index[0]];
290
291 if (info->chip_class >= CIK)
292 surf->micro_tile_mode = G_009910_MICRO_TILE_MODE_NEW(tile_mode);
293 else
294 surf->micro_tile_mode = G_009910_MICRO_TILE_MODE(tile_mode);
295 }
296
297 static unsigned cik_get_macro_tile_index(struct radeon_surf *surf)
298 {
299 unsigned index, tileb;
300
301 tileb = 8 * 8 * surf->bpe;
302 tileb = MIN2(surf->u.legacy.tile_split, tileb);
303
304 for (index = 0; tileb > 64; index++)
305 tileb >>= 1;
306
307 assert(index < 16);
308 return index;
309 }
310
311 static int gfx6_surface_init(struct radeon_winsys *rws,
312 const struct pipe_resource *tex,
313 unsigned flags, unsigned bpe,
314 enum radeon_surf_mode mode,
315 struct radeon_surf *surf)
316 {
317 struct amdgpu_winsys *ws = (struct amdgpu_winsys*)rws;
318 unsigned level;
319 bool compressed;
320 ADDR_COMPUTE_SURFACE_INFO_INPUT AddrSurfInfoIn = {0};
321 ADDR_COMPUTE_SURFACE_INFO_OUTPUT AddrSurfInfoOut = {0};
322 ADDR_COMPUTE_DCCINFO_INPUT AddrDccIn = {0};
323 ADDR_COMPUTE_DCCINFO_OUTPUT AddrDccOut = {0};
324 ADDR_COMPUTE_HTILE_INFO_INPUT AddrHtileIn = {0};
325 ADDR_COMPUTE_HTILE_INFO_OUTPUT AddrHtileOut = {0};
326 ADDR_TILEINFO AddrTileInfoIn = {0};
327 ADDR_TILEINFO AddrTileInfoOut = {0};
328 int r;
329
330 r = amdgpu_surface_sanity(tex);
331 if (r)
332 return r;
333
334 AddrSurfInfoIn.size = sizeof(ADDR_COMPUTE_SURFACE_INFO_INPUT);
335 AddrSurfInfoOut.size = sizeof(ADDR_COMPUTE_SURFACE_INFO_OUTPUT);
336 AddrDccIn.size = sizeof(ADDR_COMPUTE_DCCINFO_INPUT);
337 AddrDccOut.size = sizeof(ADDR_COMPUTE_DCCINFO_OUTPUT);
338 AddrHtileIn.size = sizeof(ADDR_COMPUTE_HTILE_INFO_INPUT);
339 AddrHtileOut.size = sizeof(ADDR_COMPUTE_HTILE_INFO_OUTPUT);
340 AddrSurfInfoOut.pTileInfo = &AddrTileInfoOut;
341
342 surf->blk_w = util_format_get_blockwidth(tex->format);
343 surf->blk_h = util_format_get_blockheight(tex->format);
344 surf->bpe = bpe;
345 surf->flags = flags;
346
347 compressed = surf->blk_w == 4 && surf->blk_h == 4;
348
349 /* MSAA and FMASK require 2D tiling. */
350 if (tex->nr_samples > 1 ||
351 (flags & RADEON_SURF_FMASK))
352 mode = RADEON_SURF_MODE_2D;
353
354 /* DB doesn't support linear layouts. */
355 if (flags & (RADEON_SURF_Z_OR_SBUFFER) &&
356 mode < RADEON_SURF_MODE_1D)
357 mode = RADEON_SURF_MODE_1D;
358
359 /* Set the requested tiling mode. */
360 switch (mode) {
361 case RADEON_SURF_MODE_LINEAR_ALIGNED:
362 AddrSurfInfoIn.tileMode = ADDR_TM_LINEAR_ALIGNED;
363 break;
364 case RADEON_SURF_MODE_1D:
365 AddrSurfInfoIn.tileMode = ADDR_TM_1D_TILED_THIN1;
366 break;
367 case RADEON_SURF_MODE_2D:
368 AddrSurfInfoIn.tileMode = ADDR_TM_2D_TILED_THIN1;
369 break;
370 default:
371 assert(0);
372 }
373
374 /* The format must be set correctly for the allocation of compressed
375 * textures to work. In other cases, setting the bpp is sufficient. */
376 if (compressed) {
377 switch (bpe) {
378 case 8:
379 AddrSurfInfoIn.format = ADDR_FMT_BC1;
380 break;
381 case 16:
382 AddrSurfInfoIn.format = ADDR_FMT_BC3;
383 break;
384 default:
385 assert(0);
386 }
387 }
388 else {
389 AddrDccIn.bpp = AddrSurfInfoIn.bpp = bpe * 8;
390 }
391
392 AddrDccIn.numSamples = AddrSurfInfoIn.numSamples =
393 tex->nr_samples ? tex->nr_samples : 1;
394 AddrSurfInfoIn.tileIndex = -1;
395
396 /* Set the micro tile type. */
397 if (flags & RADEON_SURF_SCANOUT)
398 AddrSurfInfoIn.tileType = ADDR_DISPLAYABLE;
399 else if (flags & (RADEON_SURF_Z_OR_SBUFFER | RADEON_SURF_FMASK))
400 AddrSurfInfoIn.tileType = ADDR_DEPTH_SAMPLE_ORDER;
401 else
402 AddrSurfInfoIn.tileType = ADDR_NON_DISPLAYABLE;
403
404 AddrSurfInfoIn.flags.color = !(flags & RADEON_SURF_Z_OR_SBUFFER);
405 AddrSurfInfoIn.flags.depth = (flags & RADEON_SURF_ZBUFFER) != 0;
406 AddrSurfInfoIn.flags.cube = tex->target == PIPE_TEXTURE_CUBE;
407 AddrSurfInfoIn.flags.fmask = (flags & RADEON_SURF_FMASK) != 0;
408 AddrSurfInfoIn.flags.display = (flags & RADEON_SURF_SCANOUT) != 0;
409 AddrSurfInfoIn.flags.pow2Pad = tex->last_level > 0;
410 AddrSurfInfoIn.flags.tcCompatible = (flags & RADEON_SURF_TC_COMPATIBLE_HTILE) != 0;
411
412 /* Only degrade the tile mode for space if TC-compatible HTILE hasn't been
413 * requested, because TC-compatible HTILE requires 2D tiling.
414 */
415 AddrSurfInfoIn.flags.opt4Space = !AddrSurfInfoIn.flags.tcCompatible &&
416 !AddrSurfInfoIn.flags.fmask &&
417 tex->nr_samples <= 1 &&
418 (flags & RADEON_SURF_OPTIMIZE_FOR_SPACE);
419
420 /* DCC notes:
421 * - If we add MSAA support, keep in mind that CB can't decompress 8bpp
422 * with samples >= 4.
423 * - Mipmapped array textures have low performance (discovered by a closed
424 * driver team).
425 */
426 AddrSurfInfoIn.flags.dccCompatible = ws->info.chip_class >= VI &&
427 !(flags & RADEON_SURF_Z_OR_SBUFFER) &&
428 !(flags & RADEON_SURF_DISABLE_DCC) &&
429 !compressed && AddrDccIn.numSamples <= 1 &&
430 ((tex->array_size == 1 && tex->depth0 == 1) ||
431 tex->last_level == 0);
432
433 AddrSurfInfoIn.flags.noStencil = (flags & RADEON_SURF_SBUFFER) == 0;
434 AddrSurfInfoIn.flags.compressZ = AddrSurfInfoIn.flags.depth;
435
436 /* noStencil = 0 can result in a depth part that is incompatible with
437 * mipmapped texturing. So set noStencil = 1 when mipmaps are requested (in
438 * this case, we may end up setting stencil_adjusted).
439 *
440 * TODO: update addrlib to a newer version, remove this, and
441 * use flags.matchStencilTileCfg = 1 as an alternative fix.
442 */
443 if (tex->last_level > 0)
444 AddrSurfInfoIn.flags.noStencil = 1;
445
446 /* Set preferred macrotile parameters. This is usually required
447 * for shared resources. This is for 2D tiling only. */
448 if (AddrSurfInfoIn.tileMode >= ADDR_TM_2D_TILED_THIN1 &&
449 surf->u.legacy.bankw && surf->u.legacy.bankh &&
450 surf->u.legacy.mtilea && surf->u.legacy.tile_split) {
451 assert(!(flags & RADEON_SURF_FMASK));
452
453 /* If any of these parameters are incorrect, the calculation
454 * will fail. */
455 AddrTileInfoIn.banks = surf->u.legacy.num_banks;
456 AddrTileInfoIn.bankWidth = surf->u.legacy.bankw;
457 AddrTileInfoIn.bankHeight = surf->u.legacy.bankh;
458 AddrTileInfoIn.macroAspectRatio = surf->u.legacy.mtilea;
459 AddrTileInfoIn.tileSplitBytes = surf->u.legacy.tile_split;
460 AddrTileInfoIn.pipeConfig = surf->u.legacy.pipe_config + 1; /* +1 compared to GB_TILE_MODE */
461 AddrSurfInfoIn.flags.opt4Space = 0;
462 AddrSurfInfoIn.pTileInfo = &AddrTileInfoIn;
463
464 /* If AddrSurfInfoIn.pTileInfo is set, Addrlib doesn't set
465 * the tile index, because we are expected to know it if
466 * we know the other parameters.
467 *
468 * This is something that can easily be fixed in Addrlib.
469 * For now, just figure it out here.
470 * Note that only 2D_TILE_THIN1 is handled here.
471 */
472 assert(!(flags & RADEON_SURF_Z_OR_SBUFFER));
473 assert(AddrSurfInfoIn.tileMode == ADDR_TM_2D_TILED_THIN1);
474
475 if (ws->info.chip_class == SI) {
476 if (AddrSurfInfoIn.tileType == ADDR_DISPLAYABLE) {
477 if (bpe == 2)
478 AddrSurfInfoIn.tileIndex = 11; /* 16bpp */
479 else
480 AddrSurfInfoIn.tileIndex = 12; /* 32bpp */
481 } else {
482 if (bpe == 1)
483 AddrSurfInfoIn.tileIndex = 14; /* 8bpp */
484 else if (bpe == 2)
485 AddrSurfInfoIn.tileIndex = 15; /* 16bpp */
486 else if (bpe == 4)
487 AddrSurfInfoIn.tileIndex = 16; /* 32bpp */
488 else
489 AddrSurfInfoIn.tileIndex = 17; /* 64bpp (and 128bpp) */
490 }
491 } else {
492 /* CIK - VI */
493 if (AddrSurfInfoIn.tileType == ADDR_DISPLAYABLE)
494 AddrSurfInfoIn.tileIndex = 10; /* 2D displayable */
495 else
496 AddrSurfInfoIn.tileIndex = 14; /* 2D non-displayable */
497
498 /* Addrlib doesn't set this if tileIndex is forced like above. */
499 AddrSurfInfoOut.macroModeIndex = cik_get_macro_tile_index(surf);
500 }
501 }
502
503 surf->num_dcc_levels = 0;
504 surf->surf_size = 0;
505 surf->dcc_size = 0;
506 surf->dcc_alignment = 1;
507 surf->htile_size = 0;
508 surf->htile_alignment = 1;
509
510 /* Calculate texture layout information. */
511 for (level = 0; level <= tex->last_level; level++) {
512 r = gfx6_compute_level(ws, tex, surf, false, level, compressed,
513 &AddrSurfInfoIn, &AddrSurfInfoOut,
514 &AddrDccIn, &AddrDccOut, &AddrHtileIn, &AddrHtileOut);
515 if (r)
516 return r;
517
518 if (level == 0) {
519 surf->surf_alignment = AddrSurfInfoOut.baseAlign;
520 surf->u.legacy.pipe_config = AddrSurfInfoOut.pTileInfo->pipeConfig - 1;
521 gfx6_set_micro_tile_mode(surf, &ws->info);
522
523 /* For 2D modes only. */
524 if (AddrSurfInfoOut.tileMode >= ADDR_TM_2D_TILED_THIN1) {
525 surf->u.legacy.bankw = AddrSurfInfoOut.pTileInfo->bankWidth;
526 surf->u.legacy.bankh = AddrSurfInfoOut.pTileInfo->bankHeight;
527 surf->u.legacy.mtilea = AddrSurfInfoOut.pTileInfo->macroAspectRatio;
528 surf->u.legacy.tile_split = AddrSurfInfoOut.pTileInfo->tileSplitBytes;
529 surf->u.legacy.num_banks = AddrSurfInfoOut.pTileInfo->banks;
530 surf->u.legacy.macro_tile_index = AddrSurfInfoOut.macroModeIndex;
531 } else {
532 surf->u.legacy.macro_tile_index = 0;
533 }
534 }
535 }
536
537 /* Calculate texture layout information for stencil. */
538 if (flags & RADEON_SURF_SBUFFER) {
539 AddrSurfInfoIn.bpp = 8;
540 AddrSurfInfoIn.flags.depth = 0;
541 AddrSurfInfoIn.flags.stencil = 1;
542 AddrSurfInfoIn.flags.tcCompatible = 0;
543 /* This will be ignored if AddrSurfInfoIn.pTileInfo is NULL. */
544 AddrTileInfoIn.tileSplitBytes = surf->u.legacy.stencil_tile_split;
545
546 for (level = 0; level <= tex->last_level; level++) {
547 r = gfx6_compute_level(ws, tex, surf, true, level, compressed,
548 &AddrSurfInfoIn, &AddrSurfInfoOut,
549 &AddrDccIn, &AddrDccOut,
550 NULL, NULL);
551 if (r)
552 return r;
553
554 /* DB uses the depth pitch for both stencil and depth. */
555 if (surf->u.legacy.stencil_level[level].nblk_x != surf->u.legacy.level[level].nblk_x)
556 surf->u.legacy.stencil_adjusted = true;
557
558 if (level == 0) {
559 /* For 2D modes only. */
560 if (AddrSurfInfoOut.tileMode >= ADDR_TM_2D_TILED_THIN1) {
561 surf->u.legacy.stencil_tile_split =
562 AddrSurfInfoOut.pTileInfo->tileSplitBytes;
563 }
564 }
565 }
566 }
567
568 /* Recalculate the whole DCC miptree size including disabled levels.
569 * This is what addrlib does, but calling addrlib would be a lot more
570 * complicated.
571 */
572 if (surf->dcc_size && tex->last_level > 0) {
573 surf->dcc_size = align64(surf->surf_size >> 8,
574 ws->info.pipe_interleave_bytes *
575 ws->info.num_tile_pipes);
576 }
577
578 /* Make sure HTILE covers the whole miptree, because the shader reads
579 * TC-compatible HTILE even for levels where it's disabled by DB.
580 */
581 if (surf->htile_size && tex->last_level)
582 surf->htile_size *= 2;
583
584 surf->is_linear = surf->u.legacy.level[0].mode == RADEON_SURF_MODE_LINEAR_ALIGNED;
585 return 0;
586 }
587
588 /* This is only called when expecting a tiled layout. */
589 static int
590 gfx9_get_preferred_swizzle_mode(struct amdgpu_winsys *ws,
591 ADDR2_COMPUTE_SURFACE_INFO_INPUT *in,
592 bool is_fmask, AddrSwizzleMode *swizzle_mode)
593 {
594 ADDR_E_RETURNCODE ret;
595 ADDR2_GET_PREFERRED_SURF_SETTING_INPUT sin = {0};
596 ADDR2_GET_PREFERRED_SURF_SETTING_OUTPUT sout = {0};
597
598 sin.size = sizeof(ADDR2_GET_PREFERRED_SURF_SETTING_INPUT);
599 sout.size = sizeof(ADDR2_GET_PREFERRED_SURF_SETTING_OUTPUT);
600
601 sin.flags = in->flags;
602 sin.resourceType = in->resourceType;
603 sin.format = in->format;
604 sin.resourceLoction = ADDR_RSRC_LOC_INVIS;
605 /* TODO: We could allow some of these: */
606 sin.forbiddenBlock.micro = 1; /* don't allow the 256B swizzle modes */
607 sin.forbiddenBlock.var = 1; /* don't allow the variable-sized swizzle modes */
608 sin.forbiddenBlock.linear = 1; /* don't allow linear swizzle modes */
609 sin.bpp = in->bpp;
610 sin.width = in->width;
611 sin.height = in->height;
612 sin.numSlices = in->numSlices;
613 sin.numMipLevels = in->numMipLevels;
614 sin.numSamples = in->numSamples;
615 sin.numFrags = in->numFrags;
616
617 if (is_fmask) {
618 sin.flags.color = 0;
619 sin.flags.fmask = 1;
620 }
621
622 ret = Addr2GetPreferredSurfaceSetting(ws->addrlib, &sin, &sout);
623 if (ret != ADDR_OK)
624 return ret;
625
626 *swizzle_mode = sout.swizzleMode;
627 return 0;
628 }
629
630 static int gfx9_compute_miptree(struct amdgpu_winsys *ws,
631 struct radeon_surf *surf, bool compressed,
632 ADDR2_COMPUTE_SURFACE_INFO_INPUT *in)
633 {
634 ADDR2_MIP_INFO mip_info[RADEON_SURF_MAX_LEVELS] = {};
635 ADDR2_COMPUTE_SURFACE_INFO_OUTPUT out = {0};
636 ADDR_E_RETURNCODE ret;
637
638 out.size = sizeof(ADDR2_COMPUTE_SURFACE_INFO_OUTPUT);
639 out.pMipInfo = mip_info;
640
641 ret = Addr2ComputeSurfaceInfo(ws->addrlib, in, &out);
642 if (ret != ADDR_OK)
643 return ret;
644
645 if (in->flags.stencil) {
646 surf->u.gfx9.stencil.swizzle_mode = in->swizzleMode;
647 surf->u.gfx9.stencil.epitch = out.epitchIsHeight ? out.mipChainHeight - 1 :
648 out.mipChainPitch - 1;
649 surf->surf_alignment = MAX2(surf->surf_alignment, out.baseAlign);
650 surf->u.gfx9.stencil_offset = align(surf->surf_size, out.baseAlign);
651 surf->surf_size = surf->u.gfx9.stencil_offset + out.surfSize;
652 return 0;
653 }
654
655 surf->u.gfx9.surf.swizzle_mode = in->swizzleMode;
656 surf->u.gfx9.surf.epitch = out.epitchIsHeight ? out.mipChainHeight - 1 :
657 out.mipChainPitch - 1;
658 surf->u.gfx9.surf_slice_size = out.sliceSize;
659 surf->u.gfx9.surf_pitch = out.pitch;
660 surf->u.gfx9.surf_height = out.height;
661 surf->surf_size = out.surfSize;
662 surf->surf_alignment = out.baseAlign;
663
664 if (in->swizzleMode == ADDR_SW_LINEAR) {
665 for (unsigned i = 0; i < in->numMipLevels; i++)
666 surf->u.gfx9.offset[i] = mip_info[i].offset;
667 }
668
669 if (in->flags.depth) {
670 assert(in->swizzleMode != ADDR_SW_LINEAR);
671
672 /* HTILE */
673 ADDR2_COMPUTE_HTILE_INFO_INPUT hin = {0};
674 ADDR2_COMPUTE_HTILE_INFO_OUTPUT hout = {0};
675
676 hin.size = sizeof(ADDR2_COMPUTE_HTILE_INFO_INPUT);
677 hout.size = sizeof(ADDR2_COMPUTE_HTILE_INFO_OUTPUT);
678
679 hin.hTileFlags.pipeAligned = 1;
680 hin.hTileFlags.rbAligned = 1;
681 hin.depthFlags = in->flags;
682 hin.swizzleMode = in->swizzleMode;
683 hin.unalignedWidth = in->width;
684 hin.unalignedHeight = in->height;
685 hin.numSlices = in->numSlices;
686 hin.numMipLevels = in->numMipLevels;
687
688 ret = Addr2ComputeHtileInfo(ws->addrlib, &hin, &hout);
689 if (ret != ADDR_OK)
690 return ret;
691
692 surf->u.gfx9.htile.rb_aligned = hin.hTileFlags.rbAligned;
693 surf->u.gfx9.htile.pipe_aligned = hin.hTileFlags.pipeAligned;
694 surf->htile_size = hout.htileBytes;
695 surf->htile_alignment = hout.baseAlign;
696 } else {
697 /* DCC */
698 if (!(surf->flags & RADEON_SURF_DISABLE_DCC) &&
699 !(surf->flags & RADEON_SURF_SCANOUT) &&
700 !compressed &&
701 in->swizzleMode != ADDR_SW_LINEAR &&
702 /* TODO: We could support DCC with MSAA. */
703 in->numSamples == 1) {
704 ADDR2_COMPUTE_DCCINFO_INPUT din = {0};
705 ADDR2_COMPUTE_DCCINFO_OUTPUT dout = {0};
706
707 din.size = sizeof(ADDR2_COMPUTE_DCCINFO_INPUT);
708 dout.size = sizeof(ADDR2_COMPUTE_DCCINFO_OUTPUT);
709
710 din.dccKeyFlags.pipeAligned = 1;
711 din.dccKeyFlags.rbAligned = 1;
712 din.colorFlags = in->flags;
713 din.resourceType = in->resourceType;
714 din.swizzleMode = in->swizzleMode;
715 din.bpp = in->bpp;
716 din.unalignedWidth = in->width;
717 din.unalignedHeight = in->height;
718 din.numSlices = in->numSlices;
719 din.numFrags = in->numFrags;
720 din.numMipLevels = in->numMipLevels;
721 din.dataSurfaceSize = out.surfSize;
722
723 ret = Addr2ComputeDccInfo(ws->addrlib, &din, &dout);
724 if (ret != ADDR_OK)
725 return ret;
726
727 surf->u.gfx9.dcc.rb_aligned = din.dccKeyFlags.rbAligned;
728 surf->u.gfx9.dcc.pipe_aligned = din.dccKeyFlags.pipeAligned;
729 surf->u.gfx9.dcc_pitch_max = dout.pitch - 1;
730 surf->dcc_size = dout.dccRamSize;
731 surf->dcc_alignment = dout.dccRamBaseAlign;
732 }
733
734 /* FMASK */
735 if (in->numSamples > 1) {
736 ADDR2_COMPUTE_FMASK_INFO_INPUT fin = {0};
737 ADDR2_COMPUTE_FMASK_INFO_OUTPUT fout = {0};
738
739 fin.size = sizeof(ADDR2_COMPUTE_FMASK_INFO_INPUT);
740 fout.size = sizeof(ADDR2_COMPUTE_FMASK_INFO_OUTPUT);
741
742 ret = gfx9_get_preferred_swizzle_mode(ws, in, true, &fin.swizzleMode);
743 if (ret != ADDR_OK)
744 return ret;
745
746 fin.unalignedWidth = in->width;
747 fin.unalignedHeight = in->height;
748 fin.numSlices = in->numSlices;
749 fin.numSamples = in->numSamples;
750 fin.numFrags = in->numFrags;
751
752 ret = Addr2ComputeFmaskInfo(ws->addrlib, &fin, &fout);
753 if (ret != ADDR_OK)
754 return ret;
755
756 surf->u.gfx9.fmask.swizzle_mode = in->swizzleMode;
757 surf->u.gfx9.fmask.epitch = fout.pitch - 1;
758 surf->u.gfx9.fmask_size = fout.fmaskBytes;
759 surf->u.gfx9.fmask_alignment = fout.baseAlign;
760 }
761
762 /* CMASK */
763 if (in->swizzleMode != ADDR_SW_LINEAR) {
764 ADDR2_COMPUTE_CMASK_INFO_INPUT cin = {0};
765 ADDR2_COMPUTE_CMASK_INFO_OUTPUT cout = {0};
766
767 cin.size = sizeof(ADDR2_COMPUTE_CMASK_INFO_INPUT);
768 cout.size = sizeof(ADDR2_COMPUTE_CMASK_INFO_OUTPUT);
769
770 cin.cMaskFlags.pipeAligned = 1;
771 cin.cMaskFlags.rbAligned = 1;
772 cin.colorFlags = in->flags;
773 cin.resourceType = in->resourceType;
774 cin.unalignedWidth = in->width;
775 cin.unalignedHeight = in->height;
776 cin.numSlices = in->numSlices;
777
778 if (in->numSamples > 1)
779 cin.swizzleMode = surf->u.gfx9.fmask.swizzle_mode;
780 else
781 cin.swizzleMode = in->swizzleMode;
782
783 ret = Addr2ComputeCmaskInfo(ws->addrlib, &cin, &cout);
784 if (ret != ADDR_OK)
785 return ret;
786
787 surf->u.gfx9.cmask.rb_aligned = cin.cMaskFlags.rbAligned;
788 surf->u.gfx9.cmask.pipe_aligned = cin.cMaskFlags.pipeAligned;
789 surf->u.gfx9.cmask_size = cout.cmaskBytes;
790 surf->u.gfx9.cmask_alignment = cout.baseAlign;
791 }
792 }
793
794 return 0;
795 }
796
797 static int gfx9_surface_init(struct radeon_winsys *rws,
798 const struct pipe_resource *tex,
799 unsigned flags, unsigned bpe,
800 enum radeon_surf_mode mode,
801 struct radeon_surf *surf)
802 {
803 struct amdgpu_winsys *ws = (struct amdgpu_winsys*)rws;
804 bool compressed;
805 ADDR2_COMPUTE_SURFACE_INFO_INPUT AddrSurfInfoIn = {0};
806 int r;
807
808 assert(!(flags & RADEON_SURF_FMASK));
809
810 r = amdgpu_surface_sanity(tex);
811 if (r)
812 return r;
813
814 AddrSurfInfoIn.size = sizeof(ADDR2_COMPUTE_SURFACE_INFO_INPUT);
815
816 surf->blk_w = util_format_get_blockwidth(tex->format);
817 surf->blk_h = util_format_get_blockheight(tex->format);
818 surf->bpe = bpe;
819 surf->flags = flags;
820
821 compressed = surf->blk_w == 4 && surf->blk_h == 4;
822
823 /* The format must be set correctly for the allocation of compressed
824 * textures to work. In other cases, setting the bpp is sufficient. */
825 if (compressed) {
826 switch (bpe) {
827 case 8:
828 AddrSurfInfoIn.format = ADDR_FMT_BC1;
829 break;
830 case 16:
831 AddrSurfInfoIn.format = ADDR_FMT_BC3;
832 break;
833 default:
834 assert(0);
835 }
836 } else {
837 AddrSurfInfoIn.bpp = bpe * 8;
838 }
839
840 AddrSurfInfoIn.flags.color = !(flags & RADEON_SURF_Z_OR_SBUFFER);
841 AddrSurfInfoIn.flags.depth = (flags & RADEON_SURF_ZBUFFER) != 0;
842 AddrSurfInfoIn.flags.display = (flags & RADEON_SURF_SCANOUT) != 0;
843 AddrSurfInfoIn.flags.texture = 1;
844 AddrSurfInfoIn.flags.opt4space = 1;
845
846 AddrSurfInfoIn.numMipLevels = tex->last_level + 1;
847 AddrSurfInfoIn.numSamples = tex->nr_samples ? tex->nr_samples : 1;
848 AddrSurfInfoIn.numFrags = AddrSurfInfoIn.numSamples;
849
850 switch (tex->target) {
851 /* GFX9 doesn't support 1D depth textures, so allocate all 1D textures
852 * as 2D to avoid having shader variants for 1D vs 2D, so all shaders
853 * must sample 1D textures as 2D. */
854 case PIPE_TEXTURE_1D:
855 case PIPE_TEXTURE_1D_ARRAY:
856 case PIPE_TEXTURE_2D:
857 case PIPE_TEXTURE_2D_ARRAY:
858 case PIPE_TEXTURE_RECT:
859 case PIPE_TEXTURE_CUBE:
860 case PIPE_TEXTURE_CUBE_ARRAY:
861 case PIPE_TEXTURE_3D:
862 if (tex->target == PIPE_TEXTURE_3D)
863 AddrSurfInfoIn.resourceType = ADDR_RSRC_TEX_3D;
864 else
865 AddrSurfInfoIn.resourceType = ADDR_RSRC_TEX_2D;
866
867 AddrSurfInfoIn.width = tex->width0;
868 AddrSurfInfoIn.height = tex->height0;
869
870 if (tex->target == PIPE_TEXTURE_3D)
871 AddrSurfInfoIn.numSlices = tex->depth0;
872 else if (tex->target == PIPE_TEXTURE_CUBE)
873 AddrSurfInfoIn.numSlices = 6;
874 else
875 AddrSurfInfoIn.numSlices = tex->array_size;
876
877 switch (mode) {
878 case RADEON_SURF_MODE_LINEAR_ALIGNED:
879 assert(tex->nr_samples <= 1);
880 assert(!(flags & RADEON_SURF_Z_OR_SBUFFER));
881 AddrSurfInfoIn.swizzleMode = ADDR_SW_LINEAR;
882 break;
883
884 case RADEON_SURF_MODE_1D:
885 case RADEON_SURF_MODE_2D:
886 r = gfx9_get_preferred_swizzle_mode(ws, &AddrSurfInfoIn, false,
887 &AddrSurfInfoIn.swizzleMode);
888 if (r)
889 return r;
890 break;
891
892 default:
893 assert(0);
894 }
895 break;
896
897 default:
898 assert(0);
899 }
900
901 surf->u.gfx9.resource_type = AddrSurfInfoIn.resourceType;
902
903 surf->surf_size = 0;
904 surf->dcc_size = 0;
905 surf->htile_size = 0;
906 surf->u.gfx9.surf_offset = 0;
907 surf->u.gfx9.stencil_offset = 0;
908 surf->u.gfx9.fmask_size = 0;
909 surf->u.gfx9.cmask_size = 0;
910
911 /* Calculate texture layout information. */
912 r = gfx9_compute_miptree(ws, surf, compressed, &AddrSurfInfoIn);
913 if (r)
914 return r;
915
916 /* Calculate texture layout information for stencil. */
917 if (flags & RADEON_SURF_SBUFFER) {
918 AddrSurfInfoIn.bpp = 8;
919 AddrSurfInfoIn.flags.depth = 0;
920 AddrSurfInfoIn.flags.stencil = 1;
921
922 r = gfx9_compute_miptree(ws, surf, compressed, &AddrSurfInfoIn);
923 if (r)
924 return r;
925 }
926
927 surf->is_linear = surf->u.gfx9.surf.swizzle_mode == ADDR_SW_LINEAR;
928 surf->num_dcc_levels = surf->dcc_size ? tex->last_level + 1 : 0;
929
930 switch (surf->u.gfx9.surf.swizzle_mode) {
931 /* S = standard. */
932 case ADDR_SW_256B_S:
933 case ADDR_SW_4KB_S:
934 case ADDR_SW_64KB_S:
935 case ADDR_SW_VAR_S:
936 case ADDR_SW_64KB_S_T:
937 case ADDR_SW_4KB_S_X:
938 case ADDR_SW_64KB_S_X:
939 case ADDR_SW_VAR_S_X:
940 surf->micro_tile_mode = RADEON_MICRO_MODE_THIN;
941 break;
942
943 /* D = display. */
944 case ADDR_SW_LINEAR:
945 case ADDR_SW_256B_D:
946 case ADDR_SW_4KB_D:
947 case ADDR_SW_64KB_D:
948 case ADDR_SW_VAR_D:
949 case ADDR_SW_64KB_D_T:
950 case ADDR_SW_4KB_D_X:
951 case ADDR_SW_64KB_D_X:
952 case ADDR_SW_VAR_D_X:
953 surf->micro_tile_mode = RADEON_MICRO_MODE_DISPLAY;
954 break;
955
956 /* R = rotated. */
957 case ADDR_SW_256B_R:
958 case ADDR_SW_4KB_R:
959 case ADDR_SW_64KB_R:
960 case ADDR_SW_VAR_R:
961 case ADDR_SW_64KB_R_T:
962 case ADDR_SW_4KB_R_X:
963 case ADDR_SW_64KB_R_X:
964 case ADDR_SW_VAR_R_X:
965 surf->micro_tile_mode = RADEON_MICRO_MODE_ROTATED;
966 break;
967
968 /* Z = depth. */
969 case ADDR_SW_4KB_Z:
970 case ADDR_SW_64KB_Z:
971 case ADDR_SW_VAR_Z:
972 case ADDR_SW_64KB_Z_T:
973 case ADDR_SW_4KB_Z_X:
974 case ADDR_SW_64KB_Z_X:
975 case ADDR_SW_VAR_Z_X:
976 surf->micro_tile_mode = RADEON_MICRO_MODE_DEPTH;
977 break;
978
979 default:
980 assert(0);
981 }
982
983 return 0;
984 }
985
986 void amdgpu_surface_init_functions(struct amdgpu_winsys *ws)
987 {
988 if (ws->info.chip_class >= GFX9)
989 ws->base.surface_init = gfx9_surface_init;
990 else
991 ws->base.surface_init = gfx6_surface_init;
992 }