Files
mesa/src/amd/addrlib/r800/ciaddrlib.cpp
Nicolai Hähnle 8b110f0319 amdgpu/addrlib: Add a member "bpp" for input of method AddrConvertTileIndex and AddrConvertTileInfoToHW
When clients queries tile Info from tile index and expects accurate
tileSplit info,  bits per pixel info is required to be provided since
this is necessary for computing tileSplitBytes; otherwise Addrlib will
return value of "tileBytes" instead if bpp is 0 - which is also
current logic. If clients don't need tileSplit info, it's OK to pass
bpp with value 0.
2017-03-30 14:44:33 +02:00

1853 lines
62 KiB
C++

/*
* 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;
pOut->dccRamSizeAligned = TRUE;
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);
}
if ((pOut->dccRamSize & (dccRamSizeAlign - 1)) != 0)
{
pOut->dccRamSizeAligned = FALSE;
}
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 (Min(m_tileTable[index].info.tileSplitBytes,
m_rowSize) == pInfo->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(
UINT_32 bpp, ///< [in] Bits per pixel
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));
UINT_32 tileSplit;
*pInfo = m_macroTileTable[macroModeIndex];
if (pCfgTable->type == ADDR_DEPTH_SAMPLE_ORDER)
{
tileSplit = pCfgTable->info.tileSplitBytes;
}
else
{
if (bpp > 0)
{
UINT_32 thickness = ComputeSurfaceThickness(pCfgTable->mode);
UINT_32 tileBytes1x = BITS_TO_BYTES(bpp * MicroTilePixels * thickness);
// Non-depth entries store a split factor
UINT_32 sampleSplit = m_tileTable[index].info.tileSplitBytes;
tileSplit = Max(256u, sampleSplit * tileBytes1x);
}
else
{
// Return tileBytes instead if not enough info
tileSplit = pInfo->tileSplitBytes;
}
}
// Clamp to row_size
pInfo->tileSplitBytes = Min(m_rowSize, tileSplit);
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;
}
// Pass tcCompatible flag from input to output; and turn off it if tile split occurs
pOut->tcCompatible = pIn->flags.tcCompatible;
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::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)
{
// tileSize = thickness * bpp * numSamples * 8 * 8 / 8
UINT_32 tileSize = thickness * bpp * numSamples * 8;
// Turn off tc compatible if row_size is smaller than tile size (tile split occurs).
if (m_rowSize < tileSize)
{
flags.tcCompatible = FALSE;
pOut->tcCompatible = FALSE;
}
if (flags.depth && (flags.nonSplit || flags.tcCompatible))
{
// 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))
{
static const UINT_32 PrtTileBytes = 0x10000;
ADDR_TILEINFO tileInfo = {0};
HwlComputeMacroModeIndex(index, flags, bpp, numSamples, &tileInfo);
UINT_32 macroTileBytes = (bpp >> 3) * 64 * numSamples * thickness *
HwlGetPipes(&tileInfo) * tileInfo.banks *
tileInfo.bankWidth * tileInfo.bankHeight;
if (macroTileBytes != PrtTileBytes)
{
// Switching to next tile mode entry to make sure macro tile size is 64KB
index += 1;
tileInfo.pipeConfig = m_tileTable[index].info.pipeConfig;
macroTileBytes = (bpp >> 3) * 64 * numSamples * thickness *
HwlGetPipes(&tileInfo) * tileInfo.banks *
tileInfo.bankWidth * tileInfo.bankHeight;
ADDR_ASSERT(macroTileBytes == PrtTileBytes);
}
}
}
}
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;
}
// Turn off tcCompatible for color surface if tileSplit happens. Depth/stencil is
// handled at tileIndex selecting time.
if (pOut->tcCompatible && (inTileType != ADDR_DEPTH_SAMPLE_ORDER))
{
if (IsMacroTiled(tileMode))
{
// Non-depth entries store a split factor
UINT_32 sampleSplit = m_tileTable[pOut->tileIndex].info.tileSplitBytes;
UINT_32 tileBytes1x = BITS_TO_BYTES(bpp * MicroTilePixels * thickness);
UINT_32 colorTileSplit = Max(256u, sampleSplit * tileBytes1x);
if (m_rowSize < colorTileSplit)
{
pOut->tcCompatible = FALSE;
}
}
else
{
// Client should not enable tc compatible for linear and 1D tile modes.
pOut->tcCompatible = FALSE;
}
}
}
/**
***************************************************************************************************
* 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;
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;
pTileInfo->tileSplitBytes = tileSplitC;
}
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::HwlComputeMetadataNibbleAddress
*
* @brief
* calculate meta data address based on input information
*
* &parameter
* 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;
}
}
}
}
}
}
/**
***************************************************************************************************
* CiAddrLib::HwlGetMaxAlignments
*
* @brief
* Gets maximum alignments
* @return
* ADDR_E_RETURNCODE
***************************************************************************************************
*/
ADDR_E_RETURNCODE CiAddrLib::HwlGetMaxAlignments(
ADDR_GET_MAX_ALINGMENTS_OUTPUT* pOut ///< [out] output structure
) const
{
const UINT_32 pipes = HwlGetPipes(&m_tileTable[0].info);
// Initial size is 64 KiB for PRT.
UINT_64 maxBaseAlign = 64 * 1024;
for (UINT_32 i = 0; i < m_noOfMacroEntries; i++)
{
// The maximum tile size is 16 byte-per-pixel and either 8-sample or 8-slice.
UINT_32 tileSize = m_macroTileTable[i].tileSplitBytes;
UINT_64 baseAlign = tileSize * pipes * m_macroTileTable[i].banks *
m_macroTileTable[i].bankWidth * m_macroTileTable[i].bankHeight;
if (baseAlign > maxBaseAlign)
{
maxBaseAlign = baseAlign;
}
}
if (pOut != NULL)
{
pOut->baseAlign = maxBaseAlign;
}
return ADDR_OK;
}