/*
* 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);
m_settings.isPolaris12 = ASICREV_IS_POLARIS12_V(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_settings.isPolaris12)
{
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;
}
}
}
}
}
}