#include "ac_surface.h"
#include "amd_family.h"
-#include "amdgpu_id.h"
+#include "addrlib/amdgpu_asic_addr.h"
#include "ac_gpu_info.h"
#include "util/macros.h"
#include "util/u_atomic.h"
#define CIASICIDGFXENGINE_ARCTICISLAND 0x0000000D
#endif
+static unsigned get_first(unsigned x, unsigned y)
+{
+ return x;
+}
+
static void addrlib_family_rev_id(enum radeon_family family,
- unsigned *addrlib_family,
- unsigned *addrlib_revid)
+ unsigned *addrlib_family,
+ unsigned *addrlib_revid)
{
switch (family) {
case CHIP_TAHITI:
*addrlib_family = FAMILY_SI;
- *addrlib_revid = SI_TAHITI_P_A0;
+ *addrlib_revid = get_first(AMDGPU_TAHITI_RANGE);
break;
case CHIP_PITCAIRN:
*addrlib_family = FAMILY_SI;
- *addrlib_revid = SI_PITCAIRN_PM_A0;
+ *addrlib_revid = get_first(AMDGPU_PITCAIRN_RANGE);
break;
case CHIP_VERDE:
*addrlib_family = FAMILY_SI;
- *addrlib_revid = SI_CAPEVERDE_M_A0;
+ *addrlib_revid = get_first(AMDGPU_CAPEVERDE_RANGE);
break;
case CHIP_OLAND:
*addrlib_family = FAMILY_SI;
- *addrlib_revid = SI_OLAND_M_A0;
+ *addrlib_revid = get_first(AMDGPU_OLAND_RANGE);
break;
case CHIP_HAINAN:
*addrlib_family = FAMILY_SI;
- *addrlib_revid = SI_HAINAN_V_A0;
+ *addrlib_revid = get_first(AMDGPU_HAINAN_RANGE);
break;
case CHIP_BONAIRE:
*addrlib_family = FAMILY_CI;
- *addrlib_revid = CI_BONAIRE_M_A0;
+ *addrlib_revid = get_first(AMDGPU_BONAIRE_RANGE);
break;
case CHIP_KAVERI:
*addrlib_family = FAMILY_KV;
- *addrlib_revid = KV_SPECTRE_A0;
+ *addrlib_revid = get_first(AMDGPU_SPECTRE_RANGE);
break;
case CHIP_KABINI:
*addrlib_family = FAMILY_KV;
- *addrlib_revid = KB_KALINDI_A0;
+ *addrlib_revid = get_first(AMDGPU_KALINDI_RANGE);
break;
case CHIP_HAWAII:
*addrlib_family = FAMILY_CI;
- *addrlib_revid = CI_HAWAII_P_A0;
+ *addrlib_revid = get_first(AMDGPU_HAWAII_RANGE);
break;
case CHIP_MULLINS:
*addrlib_family = FAMILY_KV;
- *addrlib_revid = ML_GODAVARI_A0;
+ *addrlib_revid = get_first(AMDGPU_GODAVARI_RANGE);
break;
case CHIP_TONGA:
*addrlib_family = FAMILY_VI;
- *addrlib_revid = VI_TONGA_P_A0;
+ *addrlib_revid = get_first(AMDGPU_TONGA_RANGE);
break;
case CHIP_ICELAND:
*addrlib_family = FAMILY_VI;
- *addrlib_revid = VI_ICELAND_M_A0;
+ *addrlib_revid = get_first(AMDGPU_ICELAND_RANGE);
break;
case CHIP_CARRIZO:
*addrlib_family = FAMILY_CZ;
- *addrlib_revid = CARRIZO_A0;
+ *addrlib_revid = get_first(AMDGPU_CARRIZO_RANGE);
break;
case CHIP_STONEY:
*addrlib_family = FAMILY_CZ;
- *addrlib_revid = STONEY_A0;
+ *addrlib_revid = get_first(AMDGPU_STONEY_RANGE);
break;
case CHIP_FIJI:
*addrlib_family = FAMILY_VI;
- *addrlib_revid = VI_FIJI_P_A0;
+ *addrlib_revid = get_first(AMDGPU_FIJI_RANGE);
break;
case CHIP_POLARIS10:
*addrlib_family = FAMILY_VI;
- *addrlib_revid = VI_POLARIS10_P_A0;
+ *addrlib_revid = get_first(AMDGPU_POLARIS10_RANGE);
break;
case CHIP_POLARIS11:
*addrlib_family = FAMILY_VI;
- *addrlib_revid = VI_POLARIS11_M_A0;
+ *addrlib_revid = get_first(AMDGPU_POLARIS11_RANGE);
break;
case CHIP_POLARIS12:
*addrlib_family = FAMILY_VI;
- *addrlib_revid = VI_POLARIS12_V_A0;
+ *addrlib_revid = get_first(AMDGPU_POLARIS12_RANGE);
break;
case CHIP_VEGA10:
*addrlib_family = FAMILY_AI;
- *addrlib_revid = AI_VEGA10_P_A0;
+ *addrlib_revid = get_first(AMDGPU_VEGA10_RANGE);
+ break;
+ case CHIP_VEGA12:
+ *addrlib_family = FAMILY_AI;
+ *addrlib_revid = get_first(AMDGPU_VEGA12_RANGE);
break;
case CHIP_RAVEN:
*addrlib_family = FAMILY_RV;
- *addrlib_revid = RAVEN_A0;
+ *addrlib_revid = get_first(AMDGPU_RAVEN_RANGE);
break;
default:
fprintf(stderr, "amdgpu: Unknown family.\n");
ADDR_CREATE_OUTPUT addrCreateOutput = {0};
ADDR_REGISTER_VALUE regValue = {0};
ADDR_CREATE_FLAGS createFlags = {{0}};
- ADDR_GET_MAX_ALIGNMENTS_OUTPUT addrGetMaxAlignmentsOutput = {0};
+ ADDR_GET_MAX_ALINGMENTS_OUTPUT addrGetMaxAlignmentsOutput = {0};
ADDR_E_RETURNCODE addrRet;
addrCreateInput.size = sizeof(ADDR_CREATE_INPUT);
regValue.gbAddrConfig = amdinfo->gb_addr_cfg;
createFlags.value = 0;
- addrlib_family_rev_id(info->family, &addrCreateInput.chipFamily, &addrCreateInput.chipRevision);
+ addrlib_family_rev_id(info->family, &addrCreateInput.chipFamily, &addrCreateInput.chipRevision);
if (addrCreateInput.chipFamily == FAMILY_UNKNOWN)
return NULL;
AddrSurfInfoIn->bpp) {
unsigned alignment = 256 / (AddrSurfInfoIn->bpp / 8);
- assert(util_is_power_of_two(AddrSurfInfoIn->bpp));
+ assert(util_is_power_of_two_or_zero(AddrSurfInfoIn->bpp));
AddrSurfInfoIn->width = align(AddrSurfInfoIn->width, alignment);
}
surf_level = is_stencil ? &surf->u.legacy.stencil_level[level] : &surf->u.legacy.level[level];
surf_level->offset = align64(surf->surf_size, AddrSurfInfoOut->baseAlign);
- surf_level->slice_size = AddrSurfInfoOut->sliceSize;
+ surf_level->slice_size_dw = AddrSurfInfoOut->sliceSize / 4;
surf_level->nblk_x = AddrSurfInfoOut->pitch;
surf_level->nblk_y = AddrSurfInfoOut->height;
return index;
}
+static bool get_display_flag(const struct ac_surf_config *config,
+ const struct radeon_surf *surf)
+{
+ unsigned num_channels = config->info.num_channels;
+ unsigned bpe = surf->bpe;
+
+ if (surf->flags & RADEON_SURF_SCANOUT &&
+ !(surf->flags & RADEON_SURF_FMASK) &&
+ config->info.samples <= 1 &&
+ surf->blk_w <= 2 && surf->blk_h == 1) {
+ /* subsampled */
+ if (surf->blk_w == 2 && surf->blk_h == 1)
+ return true;
+
+ if (/* RGBA8 or RGBA16F */
+ (bpe >= 4 && bpe <= 8 && num_channels == 4) ||
+ /* R5G6B5 or R5G5B5A1 */
+ (bpe == 2 && num_channels >= 3) ||
+ /* C8 palette */
+ (bpe == 1 && num_channels == 1))
+ return true;
+ }
+ return false;
+}
+
/**
* This must be called after the first level is computed.
*
config->info.surf_index &&
surf->u.legacy.level[0].mode == RADEON_SURF_MODE_2D &&
!(surf->flags & (RADEON_SURF_Z_OR_SBUFFER | RADEON_SURF_SHAREABLE)) &&
- (config->info.samples > 1 || !(surf->flags & RADEON_SURF_SCANOUT))) {
+ !get_display_flag(config, surf)) {
ADDR_COMPUTE_BASE_SWIZZLE_INPUT AddrBaseSwizzleIn = {0};
ADDR_COMPUTE_BASE_SWIZZLE_OUTPUT AddrBaseSwizzleOut = {0};
AddrSurfInfoIn.flags.depth = (surf->flags & RADEON_SURF_ZBUFFER) != 0;
AddrSurfInfoIn.flags.cube = config->is_cube;
AddrSurfInfoIn.flags.fmask = (surf->flags & RADEON_SURF_FMASK) != 0;
- AddrSurfInfoIn.flags.display = (surf->flags & RADEON_SURF_SCANOUT) != 0;
+ AddrSurfInfoIn.flags.display = get_display_flag(config, surf);
AddrSurfInfoIn.flags.pow2Pad = config->info.levels > 1;
AddrSurfInfoIn.flags.tcCompatible = (surf->flags & RADEON_SURF_TC_COMPATIBLE_HTILE) != 0;
info->chip_class >= VI &&
!(surf->flags & RADEON_SURF_Z_OR_SBUFFER) &&
!(surf->flags & RADEON_SURF_DISABLE_DCC) &&
- !compressed && AddrDccIn.numSamples <= 1 &&
+ !compressed &&
((config->info.array_size == 1 && config->info.depth == 1) ||
config->info.levels == 1);
surf->htile_size *= 2;
surf->is_linear = surf->u.legacy.level[0].mode == RADEON_SURF_MODE_LINEAR_ALIGNED;
+ surf->is_displayable = surf->is_linear ||
+ surf->micro_tile_mode == RADEON_MICRO_MODE_DISPLAY ||
+ surf->micro_tile_mode == RADEON_MICRO_MODE_ROTATED;
return 0;
}
static int
gfx9_get_preferred_swizzle_mode(ADDR_HANDLE addrlib,
ADDR2_COMPUTE_SURFACE_INFO_INPUT *in,
- bool is_fmask, AddrSwizzleMode *swizzle_mode)
+ bool is_fmask, unsigned flags,
+ AddrSwizzleMode *swizzle_mode)
{
ADDR_E_RETURNCODE ret;
ADDR2_GET_PREFERRED_SURF_SETTING_INPUT sin = {0};
sin.numSamples = in->numSamples;
sin.numFrags = in->numFrags;
+ if (flags & RADEON_SURF_SCANOUT)
+ sin.preferredSwSet.sw_D = 1;
+ else if (in->flags.depth || in->flags.stencil || is_fmask)
+ sin.preferredSwSet.sw_Z = 1;
+ else
+ sin.preferredSwSet.sw_S = 1;
+
if (is_fmask) {
+ sin.flags.display = 0;
sin.flags.color = 0;
sin.flags.fmask = 1;
}
}
static int gfx9_compute_miptree(ADDR_HANDLE addrlib,
+ const struct ac_surf_config *config,
struct radeon_surf *surf, bool compressed,
ADDR2_COMPUTE_SURFACE_INFO_INPUT *in)
{
ret = Addr2ComputeSurfaceInfo(addrlib, in, &out);
if (ret != ADDR_OK)
- return ret;
+ return ret;
if (in->flags.stencil) {
surf->u.gfx9.stencil.swizzle_mode = in->swizzleMode;
hin.size = sizeof(ADDR2_COMPUTE_HTILE_INFO_INPUT);
hout.size = sizeof(ADDR2_COMPUTE_HTILE_INFO_OUTPUT);
- hin.hTileFlags.pipeAligned = 1;
- hin.hTileFlags.rbAligned = 1;
+ hin.hTileFlags.pipeAligned = !in->flags.metaPipeUnaligned;
+ hin.hTileFlags.rbAligned = !in->flags.metaRbUnaligned;
hin.depthFlags = in->flags;
hin.swizzleMode = in->swizzleMode;
hin.unalignedWidth = in->width;
surf->htile_slice_size = hout.sliceSize;
surf->htile_alignment = hout.baseAlign;
} else {
+ /* Compute tile swizzle for the color surface.
+ * All *_X and *_T modes can use the swizzle.
+ */
+ if (config->info.surf_index &&
+ in->swizzleMode >= ADDR_SW_64KB_Z_T &&
+ !out.mipChainInTail &&
+ !(surf->flags & RADEON_SURF_SHAREABLE) &&
+ !in->flags.display) {
+ ADDR2_COMPUTE_PIPEBANKXOR_INPUT xin = {0};
+ ADDR2_COMPUTE_PIPEBANKXOR_OUTPUT xout = {0};
+
+ xin.size = sizeof(ADDR2_COMPUTE_PIPEBANKXOR_INPUT);
+ xout.size = sizeof(ADDR2_COMPUTE_PIPEBANKXOR_OUTPUT);
+
+ xin.surfIndex = p_atomic_inc_return(config->info.surf_index) - 1;
+ xin.flags = in->flags;
+ xin.swizzleMode = in->swizzleMode;
+ xin.resourceType = in->resourceType;
+ xin.format = in->format;
+ xin.numSamples = in->numSamples;
+ xin.numFrags = in->numFrags;
+
+ ret = Addr2ComputePipeBankXor(addrlib, &xin, &xout);
+ if (ret != ADDR_OK)
+ return ret;
+
+ assert(xout.pipeBankXor <=
+ u_bit_consecutive(0, sizeof(surf->tile_swizzle) * 8));
+ surf->tile_swizzle = xout.pipeBankXor;
+ }
+
/* DCC */
if (!(surf->flags & RADEON_SURF_DISABLE_DCC) &&
- !(surf->flags & RADEON_SURF_SCANOUT) &&
!compressed &&
- in->swizzleMode != ADDR_SW_LINEAR &&
- /* TODO: We could support DCC with MSAA. */
- in->numSamples == 1) {
+ in->swizzleMode != ADDR_SW_LINEAR) {
ADDR2_COMPUTE_DCCINFO_INPUT din = {0};
ADDR2_COMPUTE_DCCINFO_OUTPUT dout = {0};
+ ADDR2_META_MIP_INFO meta_mip_info[RADEON_SURF_MAX_LEVELS] = {};
din.size = sizeof(ADDR2_COMPUTE_DCCINFO_INPUT);
dout.size = sizeof(ADDR2_COMPUTE_DCCINFO_OUTPUT);
+ dout.pMipInfo = meta_mip_info;
- din.dccKeyFlags.pipeAligned = 1;
- din.dccKeyFlags.rbAligned = 1;
+ din.dccKeyFlags.pipeAligned = !in->flags.metaPipeUnaligned;
+ din.dccKeyFlags.rbAligned = !in->flags.metaRbUnaligned;
din.colorFlags = in->flags;
din.resourceType = in->resourceType;
din.swizzleMode = in->swizzleMode;
surf->dcc_alignment = dout.dccRamBaseAlign;
surf->num_dcc_levels = in->numMipLevels;
- /* Disable DCC for the smallest levels. It seems to be
- * required for DCC readability between CB and shaders
- * when TC L2 isn't flushed. This was guessed.
+ /* Disable DCC for levels that are in the mip tail.
+ *
+ * There are two issues that this is intended to
+ * address:
+ *
+ * 1. Multiple mip levels may share a cache line. This
+ * can lead to corruption when switching between
+ * rendering to different mip levels because the
+ * RBs don't maintain coherency.
+ *
+ * 2. Texturing with metadata after rendering sometimes
+ * fails with corruption, probably for a similar
+ * reason.
+ *
+ * Working around these issues for all levels in the
+ * mip tail may be overly conservative, but it's what
+ * Vulkan does.
*
* Alternative solutions that also work but are worse:
- * - Disable DCC.
+ * - Disable DCC entirely.
* - Flush TC L2 after rendering.
*/
- for (unsigned i = 1; i < in->numMipLevels; i++) {
- if (mip_info[i].pitch *
- mip_info[i].height * surf->bpe < 1024) {
+ for (unsigned i = 0; i < in->numMipLevels; i++) {
+ if (meta_mip_info[i].inMiptail) {
surf->num_dcc_levels = i;
break;
}
}
+
+ if (!surf->num_dcc_levels)
+ surf->dcc_size = 0;
}
/* FMASK */
fin.size = sizeof(ADDR2_COMPUTE_FMASK_INFO_INPUT);
fout.size = sizeof(ADDR2_COMPUTE_FMASK_INFO_OUTPUT);
- ret = gfx9_get_preferred_swizzle_mode(addrlib, in, true, &fin.swizzleMode);
+ ret = gfx9_get_preferred_swizzle_mode(addrlib, in,
+ true, surf->flags,
+ &fin.swizzleMode);
if (ret != ADDR_OK)
return ret;
surf->u.gfx9.fmask.epitch = fout.pitch - 1;
surf->u.gfx9.fmask_size = fout.fmaskBytes;
surf->u.gfx9.fmask_alignment = fout.baseAlign;
+
+ /* Compute tile swizzle for the FMASK surface. */
+ if (config->info.fmask_surf_index &&
+ fin.swizzleMode >= ADDR_SW_64KB_Z_T &&
+ !(surf->flags & RADEON_SURF_SHAREABLE)) {
+ ADDR2_COMPUTE_PIPEBANKXOR_INPUT xin = {0};
+ ADDR2_COMPUTE_PIPEBANKXOR_OUTPUT xout = {0};
+
+ xin.size = sizeof(ADDR2_COMPUTE_PIPEBANKXOR_INPUT);
+ xout.size = sizeof(ADDR2_COMPUTE_PIPEBANKXOR_OUTPUT);
+
+ /* This counter starts from 1 instead of 0. */
+ xin.surfIndex = p_atomic_inc_return(config->info.fmask_surf_index);
+ xin.flags = in->flags;
+ xin.swizzleMode = in->swizzleMode;
+ xin.resourceType = in->resourceType;
+ xin.format = in->format;
+ xin.numSamples = in->numSamples;
+ xin.numFrags = in->numFrags;
+
+ ret = Addr2ComputePipeBankXor(addrlib, &xin, &xout);
+ if (ret != ADDR_OK)
+ return ret;
+
+ assert(xout.pipeBankXor <=
+ u_bit_consecutive(0, sizeof(surf->u.gfx9.fmask_tile_swizzle) * 8));
+ surf->u.gfx9.fmask_tile_swizzle = xout.pipeBankXor;
+ }
}
/* CMASK */
cin.size = sizeof(ADDR2_COMPUTE_CMASK_INFO_INPUT);
cout.size = sizeof(ADDR2_COMPUTE_CMASK_INFO_OUTPUT);
- cin.cMaskFlags.pipeAligned = 1;
- cin.cMaskFlags.rbAligned = 1;
+ if (in->numSamples) {
+ /* FMASK is always aligned. */
+ cin.cMaskFlags.pipeAligned = 1;
+ cin.cMaskFlags.rbAligned = 1;
+ } else {
+ cin.cMaskFlags.pipeAligned = !in->flags.metaPipeUnaligned;
+ cin.cMaskFlags.rbAligned = !in->flags.metaRbUnaligned;
+ }
cin.colorFlags = in->flags;
cin.resourceType = in->resourceType;
cin.unalignedWidth = in->width;
}
static int gfx9_compute_surface(ADDR_HANDLE addrlib,
+ const struct radeon_info *info,
const struct ac_surf_config *config,
enum radeon_surf_mode mode,
struct radeon_surf *surf)
assert(0);
}
} else {
+ switch (surf->bpe) {
+ case 1:
+ assert(!(surf->flags & RADEON_SURF_ZBUFFER));
+ AddrSurfInfoIn.format = ADDR_FMT_8;
+ break;
+ case 2:
+ assert(surf->flags & RADEON_SURF_ZBUFFER ||
+ !(surf->flags & RADEON_SURF_SBUFFER));
+ AddrSurfInfoIn.format = ADDR_FMT_16;
+ break;
+ case 4:
+ assert(surf->flags & RADEON_SURF_ZBUFFER ||
+ !(surf->flags & RADEON_SURF_SBUFFER));
+ AddrSurfInfoIn.format = ADDR_FMT_32;
+ break;
+ case 8:
+ assert(!(surf->flags & RADEON_SURF_Z_OR_SBUFFER));
+ AddrSurfInfoIn.format = ADDR_FMT_32_32;
+ break;
+ case 16:
+ assert(!(surf->flags & RADEON_SURF_Z_OR_SBUFFER));
+ AddrSurfInfoIn.format = ADDR_FMT_32_32_32_32;
+ break;
+ default:
+ assert(0);
+ }
AddrSurfInfoIn.bpp = surf->bpe * 8;
}
AddrSurfInfoIn.flags.color = !(surf->flags & RADEON_SURF_Z_OR_SBUFFER);
AddrSurfInfoIn.flags.depth = (surf->flags & RADEON_SURF_ZBUFFER) != 0;
- AddrSurfInfoIn.flags.display = (surf->flags & RADEON_SURF_SCANOUT) != 0;
+ AddrSurfInfoIn.flags.display = get_display_flag(config, surf);
/* flags.texture currently refers to TC-compatible HTILE */
AddrSurfInfoIn.flags.texture = AddrSurfInfoIn.flags.color ||
surf->flags & RADEON_SURF_TC_COMPATIBLE_HTILE;
else
AddrSurfInfoIn.numSlices = config->info.array_size;
+ /* This is propagated to HTILE/DCC/CMASK. */
+ AddrSurfInfoIn.flags.metaPipeUnaligned = 0;
+ AddrSurfInfoIn.flags.metaRbUnaligned = 0;
+
switch (mode) {
case RADEON_SURF_MODE_LINEAR_ALIGNED:
assert(config->info.samples <= 1);
break;
}
- r = gfx9_get_preferred_swizzle_mode(addrlib, &AddrSurfInfoIn, false,
+ r = gfx9_get_preferred_swizzle_mode(addrlib, &AddrSurfInfoIn,
+ false, surf->flags,
&AddrSurfInfoIn.swizzleMode);
if (r)
return r;
surf->u.gfx9.cmask_size = 0;
/* Calculate texture layout information. */
- r = gfx9_compute_miptree(addrlib, surf, compressed, &AddrSurfInfoIn);
+ r = gfx9_compute_miptree(addrlib, config, surf, compressed,
+ &AddrSurfInfoIn);
if (r)
return r;
if (surf->flags & RADEON_SURF_SBUFFER) {
AddrSurfInfoIn.flags.stencil = 1;
AddrSurfInfoIn.bpp = 8;
+ AddrSurfInfoIn.format = ADDR_FMT_8;
if (!AddrSurfInfoIn.flags.depth) {
- r = gfx9_get_preferred_swizzle_mode(addrlib, &AddrSurfInfoIn, false,
+ r = gfx9_get_preferred_swizzle_mode(addrlib, &AddrSurfInfoIn,
+ false, surf->flags,
&AddrSurfInfoIn.swizzleMode);
if (r)
return r;
} else
AddrSurfInfoIn.flags.depth = 0;
- r = gfx9_compute_miptree(addrlib, surf, compressed, &AddrSurfInfoIn);
+ r = gfx9_compute_miptree(addrlib, config, surf, compressed,
+ &AddrSurfInfoIn);
if (r)
return r;
}
surf->is_linear = surf->u.gfx9.surf.swizzle_mode == ADDR_SW_LINEAR;
+ /* Query whether the surface is displayable. */
+ bool displayable = false;
+ r = Addr2IsValidDisplaySwizzleMode(addrlib, surf->u.gfx9.surf.swizzle_mode,
+ surf->bpe * 8, &displayable);
+ if (r)
+ return r;
+ surf->is_displayable = displayable;
+
switch (surf->u.gfx9.surf.swizzle_mode) {
/* S = standard. */
case ADDR_SW_256B_S:
assert(0);
}
+ /* Temporary workaround to prevent VM faults and hangs. */
+ if (info->family == CHIP_VEGA12)
+ surf->u.gfx9.fmask_size *= 8;
+
return 0;
}
return r;
if (info->chip_class >= GFX9)
- return gfx9_compute_surface(addrlib, config, mode, surf);
+ return gfx9_compute_surface(addrlib, info, config, mode, surf);
else
return gfx6_compute_surface(addrlib, info, config, mode, surf);
}