diff options
Diffstat (limited to 'src/amd/addrlib/r800/ciaddrlib.cpp')
-rw-r--r-- | src/amd/addrlib/r800/ciaddrlib.cpp | 1831 |
1 files changed, 1831 insertions, 0 deletions
diff --git a/src/amd/addrlib/r800/ciaddrlib.cpp b/src/amd/addrlib/r800/ciaddrlib.cpp new file mode 100644 index 00000000000..7c5d29a2166 --- /dev/null +++ b/src/amd/addrlib/r800/ciaddrlib.cpp @@ -0,0 +1,1831 @@ +/* + * Copyright © 2014 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ + +/** +*************************************************************************************************** +* @file ciaddrlib.cpp +* @brief Contains the implementation for the CIAddrLib class. +*************************************************************************************************** +*/ + +#include "ciaddrlib.h" + +#include "si_gb_reg.h" + +#include "si_ci_vi_merged_enum.h" + +#if BRAHMA_BUILD +#include "amdgpu_id.h" +#else +#include "ci_id.h" +#include "kv_id.h" +#include "vi_id.h" +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +/** +*************************************************************************************************** +* AddrMask +* +* @brief +* Gets a mask of "width" +* @return +* Bit mask +*************************************************************************************************** +*/ +static UINT_64 AddrMask( + UINT_32 width) ///< Width of bits +{ + UINT_64 ret; + + if (width >= sizeof(UINT_64)*8) + { + ret = ~((UINT_64) 0); + } + else + { + return (((UINT_64) 1) << width) - 1; + } + return ret; +} + +/** +*************************************************************************************************** +* AddrGetBits +* +* @brief +* Gets bits within a range of [msb, lsb] +* @return +* Bits of this range +*************************************************************************************************** +*/ +static UINT_64 AddrGetBits( + UINT_64 bits, ///< Source bits + UINT_32 msb, ///< Most signicant bit + UINT_32 lsb) ///< Least signicant bit +{ + UINT_64 ret = 0; + + if (msb >= lsb) + { + ret = (bits >> lsb) & (AddrMask(1 + msb - lsb)); + } + return ret; +} + +/** +*************************************************************************************************** +* AddrRemoveBits +* +* @brief +* Removes bits within the range of [msb, lsb] +* @return +* Modified bits +*************************************************************************************************** +*/ +static UINT_64 AddrRemoveBits( + UINT_64 bits, ///< Source bits + UINT_32 msb, ///< Most signicant bit + UINT_32 lsb) ///< Least signicant bit +{ + UINT_64 ret = bits; + + if (msb >= lsb) + { + ret = AddrGetBits(bits, lsb - 1, 0) // low bits + | (AddrGetBits(bits, 8 * sizeof(bits) - 1, msb + 1) << lsb); //high bits + } + return ret; +} + +/** +*************************************************************************************************** +* AddrInsertBits +* +* @brief +* Inserts new bits into the range of [msb, lsb] +* @return +* Modified bits +*************************************************************************************************** +*/ +static UINT_64 AddrInsertBits( + UINT_64 bits, ///< Source bits + UINT_64 newBits, ///< New bits to be inserted + UINT_32 msb, ///< Most signicant bit + UINT_32 lsb) ///< Least signicant bit +{ + UINT_64 ret = bits; + + if (msb >= lsb) + { + ret = AddrGetBits(bits, lsb - 1, 0) // old low bitss + | (AddrGetBits(newBits, msb - lsb, 0) << lsb) //new bits + | (AddrGetBits(bits, 8 * sizeof(bits) - 1, lsb) << (msb + 1)); //old high bits + } + return ret; +} + + +/** +*************************************************************************************************** +* AddrCIHwlInit +* +* @brief +* Creates an CIAddrLib object. +* +* @return +* Returns an CIAddrLib object pointer. +*************************************************************************************************** +*/ +AddrLib* AddrCIHwlInit(const AddrClient* pClient) +{ + return CIAddrLib::CreateObj(pClient); +} + +/** +*************************************************************************************************** +* CIAddrLib::CIAddrLib +* +* @brief +* Constructor +* +*************************************************************************************************** +*/ +CIAddrLib::CIAddrLib(const AddrClient* pClient) : + SIAddrLib(pClient), + m_noOfMacroEntries(0), + m_allowNonDispThickModes(FALSE) +{ + m_class = CI_ADDRLIB; + memset(&m_settings, 0, sizeof(m_settings)); +} + +/** +*************************************************************************************************** +* CIAddrLib::~CIAddrLib +* +* @brief +* Destructor +*************************************************************************************************** +*/ +CIAddrLib::~CIAddrLib() +{ +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlComputeDccInfo +* +* @brief +* Compute DCC key size, base alignment +* @return +* ADDR_E_RETURNCODE +*************************************************************************************************** +*/ +ADDR_E_RETURNCODE CIAddrLib::HwlComputeDccInfo( + const ADDR_COMPUTE_DCCINFO_INPUT* pIn, + ADDR_COMPUTE_DCCINFO_OUTPUT* pOut) const +{ + ADDR_E_RETURNCODE returnCode = ADDR_OK; + + if (m_settings.isVolcanicIslands && IsMacroTiled(pIn->tileMode)) + { + UINT_64 dccFastClearSize = pIn->colorSurfSize >> 8; + + ADDR_ASSERT(0 == (pIn->colorSurfSize & 0xff)); + + if (pIn->numSamples > 1) + { + UINT_32 tileSizePerSample = BITS_TO_BYTES(pIn->bpp * MicroTileWidth * MicroTileHeight); + UINT_32 samplesPerSplit = pIn->tileInfo.tileSplitBytes / tileSizePerSample; + + if (samplesPerSplit < pIn->numSamples) + { + UINT_32 numSplits = pIn->numSamples / samplesPerSplit; + UINT_32 fastClearBaseAlign = HwlGetPipes(&pIn->tileInfo) * m_pipeInterleaveBytes; + + ADDR_ASSERT(IsPow2(fastClearBaseAlign)); + + dccFastClearSize /= numSplits; + + if (0 != (dccFastClearSize & (fastClearBaseAlign - 1))) + { + // Disable dcc fast clear + // if key size of fisrt sample split is not pipe*interleave aligned + dccFastClearSize = 0; + } + } + } + + pOut->dccRamSize = pIn->colorSurfSize >> 8; + pOut->dccRamBaseAlign = pIn->tileInfo.banks * + HwlGetPipes(&pIn->tileInfo) * + m_pipeInterleaveBytes; + pOut->dccFastClearSize = dccFastClearSize; + + ADDR_ASSERT(IsPow2(pOut->dccRamBaseAlign)); + + if (0 == (pOut->dccRamSize & (pOut->dccRamBaseAlign - 1))) + { + pOut->subLvlCompressible = TRUE; + } + else + { + UINT_64 dccRamSizeAlign = HwlGetPipes(&pIn->tileInfo) * m_pipeInterleaveBytes; + + if (pOut->dccRamSize == pOut->dccFastClearSize) + { + pOut->dccFastClearSize = PowTwoAlign(pOut->dccRamSize, dccRamSizeAlign); + } + pOut->dccRamSize = PowTwoAlign(pOut->dccRamSize, dccRamSizeAlign); + pOut->subLvlCompressible = FALSE; + } + } + else + { + returnCode = ADDR_NOTSUPPORTED; + } + + return returnCode; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlComputeCmaskAddrFromCoord +* +* @brief +* Compute tc compatible Cmask address from fmask ram address +* +* @return +* ADDR_E_RETURNCODE +*************************************************************************************************** +*/ +ADDR_E_RETURNCODE CIAddrLib::HwlComputeCmaskAddrFromCoord( + const ADDR_COMPUTE_CMASK_ADDRFROMCOORD_INPUT* pIn, ///< [in] fmask addr/bpp/tile input + ADDR_COMPUTE_CMASK_ADDRFROMCOORD_OUTPUT* pOut ///< [out] cmask address + ) const +{ + ADDR_E_RETURNCODE returnCode = ADDR_NOTSUPPORTED; + + if ((m_settings.isVolcanicIslands == TRUE) && + (pIn->flags.tcCompatible == TRUE)) + { + UINT_32 numOfPipes = HwlGetPipes(pIn->pTileInfo); + UINT_32 numOfBanks = pIn->pTileInfo->banks; + UINT_64 fmaskAddress = pIn->fmaskAddr; + UINT_32 elemBits = pIn->bpp; + UINT_32 blockByte = 64 * elemBits / 8; + UINT_64 metaNibbleAddress = HwlComputeMetadataNibbleAddress(fmaskAddress, + 0, + 0, + 4, + elemBits, + blockByte, + m_pipeInterleaveBytes, + numOfPipes, + numOfBanks, + 1); + pOut->addr = (metaNibbleAddress >> 1); + pOut->bitPosition = (metaNibbleAddress % 2) ? 4 : 0; + returnCode = ADDR_OK; + } + + return returnCode; +} +/** +*************************************************************************************************** +* CIAddrLib::HwlConvertChipFamily +* +* @brief +* Convert familyID defined in atiid.h to AddrChipFamily and set m_chipFamily/m_chipRevision +* @return +* AddrChipFamily +*************************************************************************************************** +*/ +AddrChipFamily CIAddrLib::HwlConvertChipFamily( + UINT_32 uChipFamily, ///< [in] chip family defined in atiih.h + UINT_32 uChipRevision) ///< [in] chip revision defined in "asic_family"_id.h +{ + AddrChipFamily family = ADDR_CHIP_FAMILY_CI; + + switch (uChipFamily) + { + case FAMILY_CI: + m_settings.isSeaIsland = 1; + m_settings.isBonaire = ASICREV_IS_BONAIRE_M(uChipRevision); + m_settings.isHawaii = ASICREV_IS_HAWAII_P(uChipRevision); + break; + case FAMILY_KV: + m_settings.isKaveri = 1; + m_settings.isSpectre = ASICREV_IS_SPECTRE(uChipRevision); + m_settings.isSpooky = ASICREV_IS_SPOOKY(uChipRevision); + m_settings.isKalindi = ASICREV_IS_KALINDI(uChipRevision); + break; + case FAMILY_VI: + m_settings.isVolcanicIslands = 1; + m_settings.isIceland = ASICREV_IS_ICELAND_M(uChipRevision); + m_settings.isTonga = ASICREV_IS_TONGA_P(uChipRevision); + m_settings.isFiji = ASICREV_IS_FIJI_P(uChipRevision); + m_settings.isPolaris10 = ASICREV_IS_POLARIS10_P(uChipRevision); + m_settings.isPolaris11 = ASICREV_IS_POLARIS11_M(uChipRevision); + break; + case FAMILY_CZ: + m_settings.isCarrizo = 1; + m_settings.isVolcanicIslands = 1; + break; + default: + ADDR_ASSERT(!"This should be a unexpected Fusion"); + break; + } + + return family; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlInitGlobalParams +* +* @brief +* Initializes global parameters +* +* @return +* TRUE if all settings are valid +* +*************************************************************************************************** +*/ +BOOL_32 CIAddrLib::HwlInitGlobalParams( + const ADDR_CREATE_INPUT* pCreateIn) ///< [in] create input +{ + BOOL_32 valid = TRUE; + + const ADDR_REGISTER_VALUE* pRegValue = &pCreateIn->regValue; + + valid = DecodeGbRegs(pRegValue); + + // The following assignments for m_pipes is only for fail-safe, InitTileSettingTable should + // read the correct pipes from tile mode table + if (m_settings.isHawaii) + { + // Hawaii has 16-pipe, see GFXIP_Config_Summary.xls + m_pipes = 16; + } + else if (m_settings.isBonaire || m_settings.isSpectre) + { + m_pipes = 4; + } + else // Treat other KV asics to be 2-pipe + { + m_pipes = 2; + } + + // @todo: VI + // Move this to VI code path once created + if (m_settings.isTonga || m_settings.isPolaris10) + { + m_pipes = 8; + } + else if (m_settings.isIceland) + { + m_pipes = 2; + } + else if (m_settings.isFiji) + { + m_pipes = 16; + } + else if (m_settings.isPolaris11) + { + m_pipes = 4; + } + + if (valid) + { + valid = InitTileSettingTable(pRegValue->pTileConfig, pRegValue->noOfEntries); + } + if (valid) + { + valid = InitMacroTileCfgTable(pRegValue->pMacroTileConfig, pRegValue->noOfMacroEntries); + } + + return valid; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlPostCheckTileIndex +* +* @brief +* Map a tile setting to index if curIndex is invalid, otherwise check if curIndex matches +* tile mode/type/info and change the index if needed +* @return +* Tile index. +*************************************************************************************************** +*/ +INT_32 CIAddrLib::HwlPostCheckTileIndex( + const ADDR_TILEINFO* pInfo, ///< [in] Tile Info + AddrTileMode mode, ///< [in] Tile mode + AddrTileType type, ///< [in] Tile type + INT curIndex ///< [in] Current index assigned in HwlSetupTileInfo + ) const +{ + INT_32 index = curIndex; + + if (mode == ADDR_TM_LINEAR_GENERAL) + { + index = TileIndexLinearGeneral; + } + else + { + BOOL_32 macroTiled = IsMacroTiled(mode); + + // We need to find a new index if either of them is true + // 1. curIndex is invalid + // 2. tile mode is changed + // 3. tile info does not match for macro tiled + if ((index == TileIndexInvalid) || + (mode != m_tileTable[index].mode) || + (macroTiled && pInfo->pipeConfig != m_tileTable[index].info.pipeConfig)) + { + for (index = 0; index < static_cast<INT_32>(m_noOfEntries); index++) + { + if (macroTiled) + { + // macro tile modes need all to match + if ((pInfo->pipeConfig == m_tileTable[index].info.pipeConfig) && + (mode == m_tileTable[index].mode) && + (type == m_tileTable[index].type)) + { + // tileSplitBytes stored in m_tileTable is only valid for depth entries + if (type == ADDR_DEPTH_SAMPLE_ORDER) + { + if (pInfo->tileSplitBytes == m_tileTable[index].info.tileSplitBytes) + { + break; + } + } + else // other entries are determined by other 3 fields + { + break; + } + } + } + else if (mode == ADDR_TM_LINEAR_ALIGNED) + { + // linear mode only needs tile mode to match + if (mode == m_tileTable[index].mode) + { + break; + } + } + else + { + // micro tile modes only need tile mode and tile type to match + if (mode == m_tileTable[index].mode && + type == m_tileTable[index].type) + { + break; + } + } + } + } + } + + ADDR_ASSERT(index < static_cast<INT_32>(m_noOfEntries)); + + if (index >= static_cast<INT_32>(m_noOfEntries)) + { + index = TileIndexInvalid; + } + + return index; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlSetupTileCfg +* +* @brief +* Map tile index to tile setting. +* @return +* ADDR_E_RETURNCODE +*************************************************************************************************** +*/ +ADDR_E_RETURNCODE CIAddrLib::HwlSetupTileCfg( + INT_32 index, ///< [in] Tile index + INT_32 macroModeIndex, ///< [in] Index in macro tile mode table(CI) + ADDR_TILEINFO* pInfo, ///< [out] Tile Info + AddrTileMode* pMode, ///< [out] Tile mode + AddrTileType* pType ///< [out] Tile type + ) const +{ + ADDR_E_RETURNCODE returnCode = ADDR_OK; + + // Global flag to control usage of tileIndex + if (UseTileIndex(index)) + { + if (static_cast<UINT_32>(index) >= m_noOfEntries) + { + returnCode = ADDR_INVALIDPARAMS; + } + else + { + const ADDR_TILECONFIG* pCfgTable = GetTileSetting(index); + + if (pInfo != NULL) + { + if (IsMacroTiled(pCfgTable->mode)) + { + ADDR_ASSERT(((macroModeIndex != TileIndexInvalid) + && (macroModeIndex != TileIndexNoMacroIndex))); + // Here we used tile_bytes to replace of tile_split + // According info as below: + // "tile_split_c = MIN(ROW_SIZE, tile_split) + // "tile_bytes = MIN(tile_split_c, num_samples * tile_bytes_1x) + // when using tile_bytes replacing of tile_split, the result of + // alignment and others(such as slicesPerTile) are unaffected - + // since if tile_split_c is larger, split won't happen, otherwise + // (num_samples * tile_bytes_1x is larger), a correct tile_split is + // returned. + *pInfo = m_macroTileTable[macroModeIndex]; + + if (pCfgTable->type == ADDR_DEPTH_SAMPLE_ORDER) + { + pInfo->tileSplitBytes = pCfgTable->info.tileSplitBytes; + } + pInfo->pipeConfig = pCfgTable->info.pipeConfig; + } + else // 1D and linear modes, we return default value stored in table + { + *pInfo = pCfgTable->info; + } + } + + if (pMode != NULL) + { + *pMode = pCfgTable->mode; + } + + if (pType != NULL) + { + *pType = pCfgTable->type; + } + } + } + + return returnCode; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlComputeSurfaceInfo +* +* @brief +* Entry of ci's ComputeSurfaceInfo +* @return +* ADDR_E_RETURNCODE +*************************************************************************************************** +*/ +ADDR_E_RETURNCODE CIAddrLib::HwlComputeSurfaceInfo( + const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure + ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure + ) const +{ + // If tileIndex is invalid, force macroModeIndex to be invalid, too + if (pIn->tileIndex == TileIndexInvalid) + { + pOut->macroModeIndex = TileIndexInvalid; + } + + ADDR_E_RETURNCODE retCode = SIAddrLib::HwlComputeSurfaceInfo(pIn,pOut); + + if (pOut->macroModeIndex == TileIndexNoMacroIndex) + { + pOut->macroModeIndex = TileIndexInvalid; + } + + return retCode; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlFmaskSurfaceInfo +* @brief +* Entry of r800's ComputeFmaskInfo +* @return +* ADDR_E_RETURNCODE +*************************************************************************************************** +*/ +ADDR_E_RETURNCODE CIAddrLib::HwlComputeFmaskInfo( + const ADDR_COMPUTE_FMASK_INFO_INPUT* pIn, ///< [in] input structure + ADDR_COMPUTE_FMASK_INFO_OUTPUT* pOut ///< [out] output structure + ) +{ + ADDR_E_RETURNCODE retCode = ADDR_OK; + + ADDR_TILEINFO tileInfo = {0}; + ADDR_COMPUTE_FMASK_INFO_INPUT fmaskIn; + fmaskIn = *pIn; + + AddrTileMode tileMode = pIn->tileMode; + + // Use internal tile info if pOut does not have a valid pTileInfo + if (pOut->pTileInfo == NULL) + { + pOut->pTileInfo = &tileInfo; + } + + ADDR_ASSERT(tileMode == ADDR_TM_2D_TILED_THIN1 || + tileMode == ADDR_TM_3D_TILED_THIN1 || + tileMode == ADDR_TM_PRT_TILED_THIN1 || + tileMode == ADDR_TM_PRT_2D_TILED_THIN1 || + tileMode == ADDR_TM_PRT_3D_TILED_THIN1); + + ADDR_ASSERT(m_tileTable[14].mode == ADDR_TM_2D_TILED_THIN1); + ADDR_ASSERT(m_tileTable[15].mode == ADDR_TM_3D_TILED_THIN1); + + // The only valid tile modes for fmask are 2D_THIN1 and 3D_THIN1 plus non-displayable + INT_32 tileIndex = tileMode == ADDR_TM_2D_TILED_THIN1 ? 14 : 15; + ADDR_SURFACE_FLAGS flags = {{0}}; + flags.fmask = 1; + + INT_32 macroModeIndex = TileIndexInvalid; + + UINT_32 numSamples = pIn->numSamples; + UINT_32 numFrags = pIn->numFrags == 0 ? numSamples : pIn->numFrags; + + UINT_32 bpp = QLog2(numFrags); + + // EQAA needs one more bit + if (numSamples > numFrags) + { + bpp++; + } + + if (bpp == 3) + { + bpp = 4; + } + + bpp = Max(8u, bpp * numSamples); + + macroModeIndex = HwlComputeMacroModeIndex(tileIndex, flags, bpp, numSamples, pOut->pTileInfo); + + fmaskIn.tileIndex = tileIndex; + fmaskIn.pTileInfo = pOut->pTileInfo; + pOut->macroModeIndex = macroModeIndex; + pOut->tileIndex = tileIndex; + + retCode = DispatchComputeFmaskInfo(&fmaskIn, pOut); + + if (retCode == ADDR_OK) + { + pOut->tileIndex = + HwlPostCheckTileIndex(pOut->pTileInfo, pIn->tileMode, ADDR_NON_DISPLAYABLE, + pOut->tileIndex); + } + + // Resets pTileInfo to NULL if the internal tile info is used + if (pOut->pTileInfo == &tileInfo) + { + pOut->pTileInfo = NULL; + } + + return retCode; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlFmaskPreThunkSurfInfo +* +* @brief +* Some preparation before thunking a ComputeSurfaceInfo call for Fmask +* @return +* ADDR_E_RETURNCODE +*************************************************************************************************** +*/ +VOID CIAddrLib::HwlFmaskPreThunkSurfInfo( + const ADDR_COMPUTE_FMASK_INFO_INPUT* pFmaskIn, ///< [in] Input of fmask info + const ADDR_COMPUTE_FMASK_INFO_OUTPUT* pFmaskOut, ///< [in] Output of fmask info + ADDR_COMPUTE_SURFACE_INFO_INPUT* pSurfIn, ///< [out] Input of thunked surface info + ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pSurfOut ///< [out] Output of thunked surface info + ) const +{ + pSurfIn->tileIndex = pFmaskIn->tileIndex; + pSurfOut->macroModeIndex = pFmaskOut->macroModeIndex; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlFmaskPostThunkSurfInfo +* +* @brief +* Copy hwl extra field after calling thunked ComputeSurfaceInfo +* @return +* ADDR_E_RETURNCODE +*************************************************************************************************** +*/ +VOID CIAddrLib::HwlFmaskPostThunkSurfInfo( + const ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pSurfOut, ///< [in] Output of surface info + ADDR_COMPUTE_FMASK_INFO_OUTPUT* pFmaskOut ///< [out] Output of fmask info + ) const +{ + pFmaskOut->tileIndex = pSurfOut->tileIndex; + pFmaskOut->macroModeIndex = pSurfOut->macroModeIndex; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlDegradeThickTileMode +* +* @brief +* Degrades valid tile mode for thick modes if needed +* +* @return +* Suitable tile mode +*************************************************************************************************** +*/ +AddrTileMode CIAddrLib::HwlDegradeThickTileMode( + AddrTileMode baseTileMode, ///< [in] base tile mode + UINT_32 numSlices, ///< [in] current number of slices + UINT_32* pBytesPerTile ///< [in/out] pointer to bytes per slice + ) const +{ + return baseTileMode; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlOverrideTileMode +* +* @brief +* Override THICK to THIN, for specific formats on CI +* +* @return +* Suitable tile mode +* +*************************************************************************************************** +*/ +BOOL_32 CIAddrLib::HwlOverrideTileMode( + const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure + AddrTileMode* pTileMode, ///< [in/out] pointer to the tile mode + AddrTileType* pTileType ///< [in/out] pointer to the tile type + ) const +{ + BOOL_32 bOverrided = FALSE; + AddrTileMode tileMode = *pTileMode; + + // currently, all CI/VI family do not + // support ADDR_TM_PRT_2D_TILED_THICK,ADDR_TM_PRT_3D_TILED_THICK and + // ADDR_TM_PRT_2D_TILED_THIN1, ADDR_TM_PRT_3D_TILED_THIN1 + switch (tileMode) + { + case ADDR_TM_PRT_2D_TILED_THICK: + case ADDR_TM_PRT_3D_TILED_THICK: + tileMode = ADDR_TM_PRT_TILED_THICK; + break; + case ADDR_TM_PRT_2D_TILED_THIN1: + case ADDR_TM_PRT_3D_TILED_THIN1: + tileMode = ADDR_TM_PRT_TILED_THIN1; + break; + default: + break; + } + + // UBTS#404321, we do not need such overriding, as THICK+THICK entries removed from the tile-mode table + if (!m_settings.isBonaire) + { + UINT_32 thickness = ComputeSurfaceThickness(tileMode); + + // tile_thickness = (array_mode == XTHICK) ? 8 : ((array_mode == THICK) ? 4 : 1) + if (thickness > 1) + { + switch (pIn->format) + { + // see //gfxip/gcB/devel/cds/src/verif/tc/models/csim/tcp.cpp + // tcpError("Thick micro tiling is not supported for format... + case ADDR_FMT_X24_8_32_FLOAT: + case ADDR_FMT_32_AS_8: + case ADDR_FMT_32_AS_8_8: + case ADDR_FMT_32_AS_32_32_32_32: + + // packed formats + case ADDR_FMT_GB_GR: + case ADDR_FMT_BG_RG: + case ADDR_FMT_1_REVERSED: + case ADDR_FMT_1: + case ADDR_FMT_BC1: + case ADDR_FMT_BC2: + case ADDR_FMT_BC3: + case ADDR_FMT_BC4: + case ADDR_FMT_BC5: + case ADDR_FMT_BC6: + case ADDR_FMT_BC7: + switch (tileMode) + { + case ADDR_TM_1D_TILED_THICK: + tileMode = ADDR_TM_1D_TILED_THIN1; + break; + + case ADDR_TM_2D_TILED_XTHICK: + case ADDR_TM_2D_TILED_THICK: + tileMode = ADDR_TM_2D_TILED_THIN1; + break; + + case ADDR_TM_3D_TILED_XTHICK: + case ADDR_TM_3D_TILED_THICK: + tileMode = ADDR_TM_3D_TILED_THIN1; + break; + + case ADDR_TM_PRT_TILED_THICK: + tileMode = ADDR_TM_PRT_TILED_THIN1; + break; + + case ADDR_TM_PRT_2D_TILED_THICK: + tileMode = ADDR_TM_PRT_2D_TILED_THIN1; + break; + + case ADDR_TM_PRT_3D_TILED_THICK: + tileMode = ADDR_TM_PRT_3D_TILED_THIN1; + break; + + default: + break; + + } + + // Switch tile type from thick to thin + if (tileMode != *pTileMode) + { + // see tileIndex: 13-18 + *pTileType = ADDR_NON_DISPLAYABLE; + } + + break; + default: + break; + } + } + } + + if (tileMode != *pTileMode) + { + *pTileMode = tileMode; + bOverrided = TRUE; + } + + return bOverrided; +} + +/** +*************************************************************************************************** +* CiAddrLib::GetPrtSwitchP4Threshold +* +* @brief +* Return the threshold of switching to P4_* instead of P16_* for PRT resources +*************************************************************************************************** +*/ +UINT_32 CIAddrLib::GetPrtSwitchP4Threshold() const +{ + UINT_32 threshold; + + switch (m_pipes) + { + case 8: + threshold = 32; + break; + case 16: + if (m_settings.isFiji) + { + threshold = 16; + } + else if (m_settings.isHawaii) + { + threshold = 8; + } + else + { + ///@todo add for possible new ASICs. + ADDR_ASSERT_ALWAYS(); + threshold = 16; + } + break; + default: + ///@todo add for possible new ASICs. + ADDR_ASSERT_ALWAYS(); + threshold = 32; + break; + } + + return threshold; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlSetupTileInfo +* +* @brief +* Setup default value of tile info for SI +*************************************************************************************************** +*/ +VOID CIAddrLib::HwlSetupTileInfo( + AddrTileMode tileMode, ///< [in] Tile mode + ADDR_SURFACE_FLAGS flags, ///< [in] Surface type flags + UINT_32 bpp, ///< [in] Bits per pixel + UINT_32 pitch, ///< [in] Pitch in pixels + UINT_32 height, ///< [in] Height in pixels + UINT_32 numSamples, ///< [in] Number of samples + ADDR_TILEINFO* pTileInfoIn, ///< [in] Tile info input: NULL for default + ADDR_TILEINFO* pTileInfoOut, ///< [out] Tile info output + AddrTileType inTileType, ///< [in] Tile type + ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] Output + ) const +{ + UINT_32 thickness = ComputeSurfaceThickness(tileMode); + ADDR_TILEINFO* pTileInfo = pTileInfoOut; + INT index = TileIndexInvalid; + INT macroModeIndex = TileIndexInvalid; + + // Fail-safe code + if (!IsLinear(tileMode)) + { + // Thick tile modes must use thick micro tile mode but Bonaire does not support due to + // old derived netlists (UBTS 404321) + if (thickness > 1) + { + if (m_settings.isBonaire) + { + inTileType = ADDR_NON_DISPLAYABLE; + } + else if ((m_allowNonDispThickModes == FALSE) || (inTileType != ADDR_NON_DISPLAYABLE)) + { + inTileType = ADDR_THICK; + } + } + // 128 bpp tiling must be non-displayable. + // Fmask reuse color buffer's entry but bank-height field can be from another entry + // To simplify the logic, fmask entry should be picked from non-displayable ones + else if (bpp == 128 || flags.fmask) + { + inTileType = ADDR_NON_DISPLAYABLE; + } + // These two modes only have non-disp entries though they can be other micro tile modes + else if (tileMode == ADDR_TM_3D_TILED_THIN1 || tileMode == ADDR_TM_PRT_3D_TILED_THIN1) + { + inTileType = ADDR_NON_DISPLAYABLE; + } + + if (flags.depth || flags.stencil) + { + inTileType = ADDR_DEPTH_SAMPLE_ORDER; + } + } + + if (IsTileInfoAllZero(pTileInfo)) + { + // See table entries 0-4 + if (flags.depth || flags.stencil) + { + if (flags.depth && flags.tcCompatible) + { + // tileSize = bpp * numSamples * 8 * 8 / 8 + UINT_32 tileSize = bpp * numSamples * 8; + + // Texure readable depth surface should not be split + switch (tileSize) + { + case 128: + index = 1; + break; + case 256: + index = 2; + break; + case 512: + index = 3; + break; + default: + index = 4; + break; + } + } + else + { + // Depth and stencil need to use the same index, thus the pre-defined tile_split + // can meet the requirement to choose the same macro mode index + // uncompressed depth/stencil are not supported for now + switch (numSamples) + { + case 1: + index = 0; + break; + case 2: + case 4: + index = 1; + break; + case 8: + index = 2; + break; + default: + break; + } + } + } + + // See table entries 5-6 + if (inTileType == ADDR_DEPTH_SAMPLE_ORDER) + { + switch (tileMode) + { + case ADDR_TM_1D_TILED_THIN1: + index = 5; + break; + case ADDR_TM_PRT_TILED_THIN1: + index = 6; + break; + default: + break; + } + } + + // See table entries 8-12 + if (inTileType == ADDR_DISPLAYABLE) + { + switch (tileMode) + { + case ADDR_TM_1D_TILED_THIN1: + index = 9; + break; + case ADDR_TM_2D_TILED_THIN1: + index = 10; + break; + case ADDR_TM_PRT_TILED_THIN1: + index = 11; + break; + default: + break; + } + } + + // See table entries 13-18 + if (inTileType == ADDR_NON_DISPLAYABLE) + { + switch (tileMode) + { + case ADDR_TM_1D_TILED_THIN1: + index = 13; + break; + case ADDR_TM_2D_TILED_THIN1: + index = 14; + break; + case ADDR_TM_3D_TILED_THIN1: + index = 15; + break; + case ADDR_TM_PRT_TILED_THIN1: + index = 16; + break; + default: + break; + } + } + + // See table entries 19-26 + if (thickness > 1) + { + switch (tileMode) + { + case ADDR_TM_1D_TILED_THICK: + //special check for bonaire, for the compatablity between old KMD and new UMD for bonaire + index = ((inTileType == ADDR_THICK) || m_settings.isBonaire) ? 19 : 18; + break; + case ADDR_TM_2D_TILED_THICK: + // special check for bonaire, for the compatablity between old KMD and new UMD for bonaire + index = ((inTileType == ADDR_THICK) || m_settings.isBonaire) ? 20 : 24; + break; + case ADDR_TM_3D_TILED_THICK: + index = 21; + break; + case ADDR_TM_PRT_TILED_THICK: + index = 22; + break; + case ADDR_TM_2D_TILED_XTHICK: + index = 25; + break; + case ADDR_TM_3D_TILED_XTHICK: + index = 26; + break; + default: + break; + } + } + + // See table entries 27-30 + if (inTileType == ADDR_ROTATED) + { + switch (tileMode) + { + case ADDR_TM_1D_TILED_THIN1: + index = 27; + break; + case ADDR_TM_2D_TILED_THIN1: + index = 28; + break; + case ADDR_TM_PRT_TILED_THIN1: + index = 29; + break; + case ADDR_TM_PRT_2D_TILED_THIN1: + index = 30; + break; + default: + break; + } + } + + if (m_pipes >= 8) + { + ADDR_ASSERT((index + 1) < static_cast<INT_32>(m_noOfEntries)); + // Only do this when tile mode table is updated. + if (((tileMode == ADDR_TM_PRT_TILED_THIN1) || (tileMode == ADDR_TM_PRT_TILED_THICK)) && + (m_tileTable[index+1].mode == tileMode)) + { + UINT_32 bytesXSamples = bpp * numSamples / 8; + UINT_32 bytesXThickness = bpp * thickness / 8; + UINT_32 switchP4Threshold = GetPrtSwitchP4Threshold(); + + if ((bytesXSamples > switchP4Threshold) || (bytesXThickness > switchP4Threshold)) + { + // Pick next 4 pipe entry + index += 1; + } + } + } + } + else + { + // A pre-filled tile info is ready + index = pOut->tileIndex; + macroModeIndex = pOut->macroModeIndex; + + // pass tile type back for post tile index compute + pOut->tileType = inTileType; + } + + // We only need to set up tile info if there is a valid index but macroModeIndex is invalid + if (index != TileIndexInvalid && macroModeIndex == TileIndexInvalid) + { + macroModeIndex = HwlComputeMacroModeIndex(index, flags, bpp, numSamples, pTileInfo); + + /// Copy to pOut->tileType/tileIndex/macroModeIndex + pOut->tileIndex = index; + pOut->tileType = m_tileTable[index].type; // Or inTileType, the samea + pOut->macroModeIndex = macroModeIndex; + } + else if (tileMode == ADDR_TM_LINEAR_GENERAL) + { + pOut->tileIndex = TileIndexLinearGeneral; + + // Copy linear-aligned entry?? + *pTileInfo = m_tileTable[8].info; + } + else if (tileMode == ADDR_TM_LINEAR_ALIGNED) + { + pOut->tileIndex = 8; + *pTileInfo = m_tileTable[8].info; + } +} + +/** +*************************************************************************************************** +* CIAddrLib::ReadGbTileMode +* +* @brief +* Convert GB_TILE_MODE HW value to ADDR_TILE_CONFIG. +* @return +* NA. +*************************************************************************************************** +*/ +VOID CIAddrLib::ReadGbTileMode( + UINT_32 regValue, ///< [in] GB_TILE_MODE register + ADDR_TILECONFIG* pCfg ///< [out] output structure + ) const +{ + GB_TILE_MODE gbTileMode; + gbTileMode.val = regValue; + + pCfg->type = static_cast<AddrTileType>(gbTileMode.f.micro_tile_mode_new); + pCfg->info.pipeConfig = static_cast<AddrPipeCfg>(gbTileMode.f.pipe_config + 1); + + if (pCfg->type == ADDR_DEPTH_SAMPLE_ORDER) + { + pCfg->info.tileSplitBytes = 64 << gbTileMode.f.tile_split; + } + else + { + pCfg->info.tileSplitBytes = 1 << gbTileMode.f.sample_split; + } + + UINT_32 regArrayMode = gbTileMode.f.array_mode; + + pCfg->mode = static_cast<AddrTileMode>(regArrayMode); + + switch (regArrayMode) + { + case 5: + pCfg->mode = ADDR_TM_PRT_TILED_THIN1; + break; + case 6: + pCfg->mode = ADDR_TM_PRT_2D_TILED_THIN1; + break; + case 8: + pCfg->mode = ADDR_TM_2D_TILED_XTHICK; + break; + case 9: + pCfg->mode = ADDR_TM_PRT_TILED_THICK; + break; + case 0xa: + pCfg->mode = ADDR_TM_PRT_2D_TILED_THICK; + break; + case 0xb: + pCfg->mode = ADDR_TM_PRT_3D_TILED_THIN1; + break; + case 0xe: + pCfg->mode = ADDR_TM_3D_TILED_XTHICK; + break; + case 0xf: + pCfg->mode = ADDR_TM_PRT_3D_TILED_THICK; + break; + default: + break; + } + + // Fail-safe code for these always convert tile info, as the non-macro modes + // return the entry of tile mode table directly without looking up macro mode table + if (!IsMacroTiled(pCfg->mode)) + { + pCfg->info.banks = 2; + pCfg->info.bankWidth = 1; + pCfg->info.bankHeight = 1; + pCfg->info.macroAspectRatio = 1; + pCfg->info.tileSplitBytes = 64; + } +} + +/** +*************************************************************************************************** +* CIAddrLib::InitTileSettingTable +* +* @brief +* Initialize the ADDR_TILE_CONFIG table. +* @return +* TRUE if tile table is correctly initialized +*************************************************************************************************** +*/ +BOOL_32 CIAddrLib::InitTileSettingTable( + const UINT_32* pCfg, ///< [in] Pointer to table of tile configs + UINT_32 noOfEntries ///< [in] Numbe of entries in the table above + ) +{ + BOOL_32 initOk = TRUE; + + ADDR_ASSERT(noOfEntries <= TileTableSize); + + memset(m_tileTable, 0, sizeof(m_tileTable)); + + if (noOfEntries != 0) + { + m_noOfEntries = noOfEntries; + } + else + { + m_noOfEntries = TileTableSize; + } + + if (pCfg) // From Client + { + for (UINT_32 i = 0; i < m_noOfEntries; i++) + { + ReadGbTileMode(*(pCfg + i), &m_tileTable[i]); + } + } + else + { + ADDR_ASSERT_ALWAYS(); + initOk = FALSE; + } + + if (initOk) + { + ADDR_ASSERT(m_tileTable[TILEINDEX_LINEAR_ALIGNED].mode == ADDR_TM_LINEAR_ALIGNED); + + if (m_settings.isBonaire == FALSE) + { + // Check if entry 18 is "thick+thin" combination + if ((m_tileTable[18].mode == ADDR_TM_1D_TILED_THICK) && + (m_tileTable[18].type == ADDR_NON_DISPLAYABLE)) + { + m_allowNonDispThickModes = TRUE; + ADDR_ASSERT(m_tileTable[24].mode == ADDR_TM_2D_TILED_THICK); + } + } + else + { + m_allowNonDispThickModes = TRUE; + } + + // Assume the first entry is always programmed with full pipes + m_pipes = HwlGetPipes(&m_tileTable[0].info); + } + + return initOk; +} + +/** +*************************************************************************************************** +* CIAddrLib::ReadGbMacroTileCfg +* +* @brief +* Convert GB_MACRO_TILE_CFG HW value to ADDR_TILE_CONFIG. +* @return +* NA. +*************************************************************************************************** +*/ +VOID CIAddrLib::ReadGbMacroTileCfg( + UINT_32 regValue, ///< [in] GB_MACRO_TILE_MODE register + ADDR_TILEINFO* pCfg ///< [out] output structure + ) const +{ + GB_MACROTILE_MODE gbTileMode; + gbTileMode.val = regValue; + + pCfg->bankHeight = 1 << gbTileMode.f.bank_height; + pCfg->bankWidth = 1 << gbTileMode.f.bank_width; + pCfg->banks = 1 << (gbTileMode.f.num_banks + 1); + pCfg->macroAspectRatio = 1 << gbTileMode.f.macro_tile_aspect; +} + +/** +*************************************************************************************************** +* CIAddrLib::InitMacroTileCfgTable +* +* @brief +* Initialize the ADDR_MACRO_TILE_CONFIG table. +* @return +* TRUE if macro tile table is correctly initialized +*************************************************************************************************** +*/ +BOOL_32 CIAddrLib::InitMacroTileCfgTable( + const UINT_32* pCfg, ///< [in] Pointer to table of tile configs + UINT_32 noOfMacroEntries ///< [in] Numbe of entries in the table above + ) +{ + BOOL_32 initOk = TRUE; + + ADDR_ASSERT(noOfMacroEntries <= MacroTileTableSize); + + memset(m_macroTileTable, 0, sizeof(m_macroTileTable)); + + if (noOfMacroEntries != 0) + { + m_noOfMacroEntries = noOfMacroEntries; + } + else + { + m_noOfMacroEntries = MacroTileTableSize; + } + + if (pCfg) // From Client + { + for (UINT_32 i = 0; i < m_noOfMacroEntries; i++) + { + ReadGbMacroTileCfg(*(pCfg + i), &m_macroTileTable[i]); + + m_macroTileTable[i].tileSplitBytes = 64 << (i % 8); + } + } + else + { + ADDR_ASSERT_ALWAYS(); + initOk = FALSE; + } + return initOk; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlComputeMacroModeIndex +* +* @brief +* Computes macro tile mode index +* @return +* TRUE if macro tile table is correctly initialized +*************************************************************************************************** +*/ +INT_32 CIAddrLib::HwlComputeMacroModeIndex( + INT_32 tileIndex, ///< [in] Tile mode index + ADDR_SURFACE_FLAGS flags, ///< [in] Surface flags + UINT_32 bpp, ///< [in] Bit per pixel + UINT_32 numSamples, ///< [in] Number of samples + ADDR_TILEINFO* pTileInfo, ///< [out] Pointer to ADDR_TILEINFO + AddrTileMode* pTileMode, ///< [out] Pointer to AddrTileMode + AddrTileType* pTileType ///< [out] Pointer to AddrTileType + ) const +{ + INT_32 macroModeIndex = TileIndexInvalid; + + if (flags.tcCompatible && flags.stencil) + { + // Don't compute macroModeIndex for tc compatible stencil surface + macroModeIndex = TileIndexNoMacroIndex; + } + else + { + AddrTileMode tileMode = m_tileTable[tileIndex].mode; + AddrTileType tileType = m_tileTable[tileIndex].type; + UINT_32 thickness = ComputeSurfaceThickness(tileMode); + + if (!IsMacroTiled(tileMode)) + { + *pTileInfo = m_tileTable[tileIndex].info; + macroModeIndex = TileIndexNoMacroIndex; + } + else + { + UINT_32 tileBytes1x = BITS_TO_BYTES(bpp * MicroTilePixels * thickness); + UINT_32 tileSplit; + + if (m_tileTable[tileIndex].type == ADDR_DEPTH_SAMPLE_ORDER) + { + // Depth entries store real tileSplitBytes + tileSplit = m_tileTable[tileIndex].info.tileSplitBytes; + } + else + { + // Non-depth entries store a split factor + UINT_32 sampleSplit = m_tileTable[tileIndex].info.tileSplitBytes; + UINT_32 colorTileSplit = Max(256u, sampleSplit * tileBytes1x); + + tileSplit = colorTileSplit; + } + + UINT_32 tileSplitC = Min(m_rowSize, tileSplit); + UINT_32 tileBytes; + + if (flags.fmask) + { + tileBytes = Min(tileSplitC, tileBytes1x); + } + else + { + tileBytes = Min(tileSplitC, numSamples * tileBytes1x); + } + + if (tileBytes < 64) + { + tileBytes = 64; + } + + macroModeIndex = Log2(tileBytes / 64); + + if (flags.prt || IsPrtTileMode(tileMode)) + { + // Unknown - assume it is 1/2 of table size + const UINT_32 PrtMacroModeOffset = MacroTileTableSize / 2; + + macroModeIndex += PrtMacroModeOffset; + *pTileInfo = m_macroTileTable[macroModeIndex]; + } + else + { + *pTileInfo = m_macroTileTable[macroModeIndex]; + } + + pTileInfo->pipeConfig = m_tileTable[tileIndex].info.pipeConfig; + + if (m_tileTable[tileIndex].type != ADDR_DEPTH_SAMPLE_ORDER) + { + pTileInfo->tileSplitBytes = tileSplitC; + } + else + { + pTileInfo->tileSplitBytes = m_tileTable[tileIndex].info.tileSplitBytes; + } + } + + if (NULL != pTileMode) + { + *pTileMode = tileMode; + } + + if (NULL != pTileType) + { + *pTileType = tileType; + } + } + + return macroModeIndex; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlComputeTileDataWidthAndHeightLinear +* +* @brief +* Compute the squared cache shape for per-tile data (CMASK and HTILE) for linear layout +* +* @return +* N/A +* +* @note +* MacroWidth and macroHeight are measured in pixels +*************************************************************************************************** +*/ +VOID CIAddrLib::HwlComputeTileDataWidthAndHeightLinear( + UINT_32* pMacroWidth, ///< [out] macro tile width + UINT_32* pMacroHeight, ///< [out] macro tile height + UINT_32 bpp, ///< [in] bits per pixel + ADDR_TILEINFO* pTileInfo ///< [in] tile info + ) const +{ + ADDR_ASSERT(pTileInfo != NULL); + + UINT_32 numTiles; + + switch (pTileInfo->pipeConfig) + { + case ADDR_PIPECFG_P16_32x32_8x16: + case ADDR_PIPECFG_P16_32x32_16x16: + case ADDR_PIPECFG_P8_32x64_32x32: + case ADDR_PIPECFG_P8_32x32_16x32: + case ADDR_PIPECFG_P8_32x32_16x16: + case ADDR_PIPECFG_P8_32x32_8x16: + case ADDR_PIPECFG_P4_32x32: + numTiles = 8; + break; + default: + numTiles = 4; + break; + } + + *pMacroWidth = numTiles * MicroTileWidth; + *pMacroHeight = numTiles * MicroTileHeight; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlStereoCheckRightOffsetPadding +* +* @brief +* check if the height needs extra padding for stereo right eye offset, to avoid swizzling +* +* @return +* TRUE is the extra padding is needed +* +* @note +* Kalindi (Kabini) is the only one that needs this padding as there is a uncertain +* possible HW issue where the right eye displays incorrectly with some type of swizzles, if +* the right eye offset is not 64KB aligned - EPR#366461 +* Other Kaveri APUs also need the padding according to DXX team's report otherwise +* corruption observed. - EPR#374788 +*************************************************************************************************** +*/ +BOOL_32 CIAddrLib::HwlStereoCheckRightOffsetPadding() const +{ + BOOL_32 bNeedPadding = FALSE; + + if (m_settings.isKaveri) + { + bNeedPadding = TRUE; + } + + return bNeedPadding; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlComputeMetadataNibbleAddress +* +* @brief +* calculate meta data address based on input information +* +* ¶meter +* uncompressedDataByteAddress - address of a pixel in color surface +* dataBaseByteAddress - base address of color surface +* metadataBaseByteAddress - base address of meta ram +* metadataBitSize - meta key size, 8 for DCC, 4 for cmask +* elementBitSize - element size of color surface +* blockByteSize - compression block size, 256 for DCC +* pipeInterleaveBytes - pipe interleave size +* numOfPipes - number of pipes +* numOfBanks - number of banks +* numOfSamplesPerSplit - number of samples per tile split +* @return +* meta data nibble address (nibble address is used to support DCC compatible cmask) +* +*************************************************************************************************** +*/ +UINT_64 CIAddrLib::HwlComputeMetadataNibbleAddress( + UINT_64 uncompressedDataByteAddress, + UINT_64 dataBaseByteAddress, + UINT_64 metadataBaseByteAddress, + UINT_32 metadataBitSize, + UINT_32 elementBitSize, + UINT_32 blockByteSize, + UINT_32 pipeInterleaveBytes, + UINT_32 numOfPipes, + UINT_32 numOfBanks, + UINT_32 numOfSamplesPerSplit) const +{ + ///-------------------------------------------------------------------------------------------- + /// Get pipe interleave, bank and pipe bits + ///-------------------------------------------------------------------------------------------- + UINT_32 pipeInterleaveBits = Log2(pipeInterleaveBytes); + UINT_32 pipeBits = Log2(numOfPipes); + UINT_32 bankBits = Log2(numOfBanks); + + ///-------------------------------------------------------------------------------------------- + /// Clear pipe and bank swizzles + ///-------------------------------------------------------------------------------------------- + UINT_32 dataMacrotileBits = pipeInterleaveBits + pipeBits + bankBits; + UINT_32 metadataMacrotileBits = pipeInterleaveBits + pipeBits + bankBits; + + UINT_64 dataMacrotileClearMask = ~((1L << dataMacrotileBits) - 1); + UINT_64 metadataMacrotileClearMask = ~((1L << metadataMacrotileBits) - 1); + + UINT_64 dataBaseByteAddressNoSwizzle = dataBaseByteAddress & dataMacrotileClearMask; + UINT_64 metadataBaseByteAddressNoSwizzle = metadataBaseByteAddress & metadataMacrotileClearMask; + + ///-------------------------------------------------------------------------------------------- + /// Modify metadata base before adding in so that when final address is divided by data ratio, + /// the base address returns to where it should be + ///-------------------------------------------------------------------------------------------- + ADDR_ASSERT((0 != metadataBitSize)); + UINT_64 metadataBaseShifted = metadataBaseByteAddressNoSwizzle * blockByteSize * 8 / + metadataBitSize; + UINT_64 offset = uncompressedDataByteAddress - + dataBaseByteAddressNoSwizzle + + metadataBaseShifted; + + ///-------------------------------------------------------------------------------------------- + /// Save bank data bits + ///-------------------------------------------------------------------------------------------- + UINT_32 lsb = pipeBits + pipeInterleaveBits; + UINT_32 msb = bankBits - 1 + lsb; + + UINT_64 bankDataBits = AddrGetBits(offset, msb, lsb); + + ///-------------------------------------------------------------------------------------------- + /// Save pipe data bits + ///-------------------------------------------------------------------------------------------- + lsb = pipeInterleaveBits; + msb = pipeBits - 1 + lsb; + + UINT_64 pipeDataBits = AddrGetBits(offset, msb, lsb); + + ///-------------------------------------------------------------------------------------------- + /// Remove pipe and bank bits + ///-------------------------------------------------------------------------------------------- + lsb = pipeInterleaveBits; + msb = dataMacrotileBits - 1; + + UINT_64 offsetWithoutPipeBankBits = AddrRemoveBits(offset, msb, lsb); + + ADDR_ASSERT((0 != blockByteSize)); + UINT_64 blockInBankpipe = offsetWithoutPipeBankBits / blockByteSize; + + UINT_32 tileSize = 8 * 8 * elementBitSize/8 * numOfSamplesPerSplit; + UINT_32 blocksInTile = tileSize / blockByteSize; + + if (0 == blocksInTile) + { + lsb = 0; + } + else + { + lsb = Log2(blocksInTile); + } + msb = bankBits - 1 + lsb; + + UINT_64 blockInBankpipeWithBankBits = AddrInsertBits(blockInBankpipe, bankDataBits, msb, lsb); + + /// NOTE *2 because we are converting to Nibble address in this step + UINT_64 metaAddressInPipe = blockInBankpipeWithBankBits * 2 * metadataBitSize / 8; + + + ///-------------------------------------------------------------------------------------------- + /// Reinsert pipe bits back into the final address + ///-------------------------------------------------------------------------------------------- + lsb = pipeInterleaveBits + 1; ///<+1 due to Nibble address now gives interleave bits extra lsb. + msb = pipeBits - 1 + lsb; + UINT_64 metadataAddress = AddrInsertBits(metaAddressInPipe, pipeDataBits, msb, lsb); + + return metadataAddress; +} + +/** +*************************************************************************************************** +* CIAddrLib::HwlPadDimensions +* +* @brief +* Helper function to pad dimensions +* +* @return +* N/A +* +*************************************************************************************************** +*/ +VOID CIAddrLib::HwlPadDimensions( + AddrTileMode tileMode, ///< [in] tile mode + UINT_32 bpp, ///< [in] bits per pixel + ADDR_SURFACE_FLAGS flags, ///< [in] surface flags + UINT_32 numSamples, ///< [in] number of samples + ADDR_TILEINFO* pTileInfo, ///< [in/out] bank structure. + UINT_32 padDims, ///< [in] Dimensions to pad valid value 1,2,3 + UINT_32 mipLevel, ///< [in] MipLevel + UINT_32* pPitch, ///< [in/out] pitch in pixels + UINT_32 pitchAlign, ///< [in] pitch alignment + UINT_32* pHeight, ///< [in/out] height in pixels + UINT_32 heightAlign, ///< [in] height alignment + UINT_32* pSlices, ///< [in/out] number of slices + UINT_32 sliceAlign ///< [in] number of slice alignment + ) const +{ + if (m_settings.isVolcanicIslands && + flags.dccCompatible && + (numSamples > 1) && + (mipLevel == 0) && + IsMacroTiled(tileMode)) + { + UINT_32 tileSizePerSample = BITS_TO_BYTES(bpp * MicroTileWidth * MicroTileHeight); + UINT_32 samplesPerSplit = pTileInfo->tileSplitBytes / tileSizePerSample; + + if (samplesPerSplit < numSamples) + { + UINT_32 dccFastClearByteAlign = HwlGetPipes(pTileInfo) * m_pipeInterleaveBytes * 256; + UINT_32 bytesPerSplit = BITS_TO_BYTES((*pPitch) * (*pHeight) * bpp * samplesPerSplit); + + ADDR_ASSERT(IsPow2(dccFastClearByteAlign)); + + if (0 != (bytesPerSplit & (dccFastClearByteAlign - 1))) + { + UINT_32 dccFastClearPixelAlign = dccFastClearByteAlign / + BITS_TO_BYTES(bpp) / + samplesPerSplit; + UINT_32 macroTilePixelAlign = pitchAlign * heightAlign; + + if ((dccFastClearPixelAlign >= macroTilePixelAlign) && + ((dccFastClearPixelAlign % macroTilePixelAlign) == 0)) + { + UINT_32 dccFastClearPitchAlignInMacroTile = + dccFastClearPixelAlign / macroTilePixelAlign; + UINT_32 heightInMacroTile = *pHeight / heightAlign; + UINT_32 dccFastClearPitchAlignInPixels; + + while ((heightInMacroTile > 1) && + ((heightInMacroTile % 2) == 0) && + (dccFastClearPitchAlignInMacroTile > 1) && + ((dccFastClearPitchAlignInMacroTile % 2) == 0)) + { + heightInMacroTile >>= 1; + dccFastClearPitchAlignInMacroTile >>= 1; + } + + dccFastClearPitchAlignInPixels = pitchAlign * dccFastClearPitchAlignInMacroTile; + + if (IsPow2(dccFastClearPitchAlignInPixels)) + { + *pPitch = PowTwoAlign((*pPitch), dccFastClearPitchAlignInPixels); + } + else + { + *pPitch += (dccFastClearPitchAlignInPixels - 1); + *pPitch /= dccFastClearPitchAlignInPixels; + *pPitch *= dccFastClearPitchAlignInPixels; + } + } + } + } + } +} + |