/*
* 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 CiLib class.
****************************************************************************************************
*/
#include "ciaddrlib.h"
#include "si_gb_reg.h"
#include "amdgpu_asic_addr.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Addr
{
/**
****************************************************************************************************
* CiHwlInit
*
* @brief
* Creates an CiLib object.
*
* @return
* Returns an CiLib object pointer.
****************************************************************************************************
*/
Lib* CiHwlInit(const Client* pClient)
{
return V1::CiLib::CreateObj(pClient);
}
namespace V1
{
/**
****************************************************************************************************
* Mask
*
* @brief
* Gets a mask of "width"
* @return
* Bit mask
****************************************************************************************************
*/
static UINT_64 Mask(
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;
}
/**
****************************************************************************************************
* GetBits
*
* @brief
* Gets bits within a range of [msb, lsb]
* @return
* Bits of this range
****************************************************************************************************
*/
static UINT_64 GetBits(
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) & (Mask(1 + msb - lsb));
}
return ret;
}
/**
****************************************************************************************************
* RemoveBits
*
* @brief
* Removes bits within the range of [msb, lsb]
* @return
* Modified bits
****************************************************************************************************
*/
static UINT_64 RemoveBits(
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 = GetBits(bits, lsb - 1, 0) // low bits
| (GetBits(bits, 8 * sizeof(bits) - 1, msb + 1) << lsb); //high bits
}
return ret;
}
/**
****************************************************************************************************
* InsertBits
*
* @brief
* Inserts new bits into the range of [msb, lsb]
* @return
* Modified bits
****************************************************************************************************
*/
static UINT_64 InsertBits(
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 = GetBits(bits, lsb - 1, 0) // old low bitss
| (GetBits(newBits, msb - lsb, 0) << lsb) //new bits
| (GetBits(bits, 8 * sizeof(bits) - 1, lsb) << (msb + 1)); //old high bits
}
return ret;
}
/**
****************************************************************************************************
* CiLib::CiLib
*
* @brief
* Constructor
*
****************************************************************************************************
*/
CiLib::CiLib(const Client* pClient)
:
SiLib(pClient),
m_noOfMacroEntries(0),
m_allowNonDispThickModes(FALSE)
{
m_class = CI_ADDRLIB;
}
/**
****************************************************************************************************
* CiLib::~CiLib
*
* @brief
* Destructor
****************************************************************************************************
*/
CiLib::~CiLib()
{
}
/**
****************************************************************************************************
* CiLib::HwlComputeDccInfo
*
* @brief
* Compute DCC key size, base alignment
* @return
* ADDR_E_RETURNCODE
****************************************************************************************************
*/
ADDR_E_RETURNCODE CiLib::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;
}
/**
****************************************************************************************************
* CiLib::HwlComputeCmaskAddrFromCoord
*
* @brief
* Compute tc compatible Cmask address from fmask ram address
*
* @return
* ADDR_E_RETURNCODE
****************************************************************************************************
*/
ADDR_E_RETURNCODE CiLib::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, // cmask 4 bits
elemBits,
blockByte,
m_pipeInterleaveBytes,
numOfPipes,
numOfBanks,
1);
pOut->addr = (metaNibbleAddress >> 1);
pOut->bitPosition = (metaNibbleAddress % 2) ? 4 : 0;
returnCode = ADDR_OK;
}
return returnCode;
}
/**
****************************************************************************************************
* CiLib::HwlComputeHtileAddrFromCoord
*
* @brief
* Compute tc compatible Htile address from depth/stencil address
*
* @return
* ADDR_E_RETURNCODE
****************************************************************************************************
*/
ADDR_E_RETURNCODE CiLib::HwlComputeHtileAddrFromCoord(
const ADDR_COMPUTE_HTILE_ADDRFROMCOORD_INPUT* pIn, ///< [in] depth/stencil addr/bpp/tile input
ADDR_COMPUTE_HTILE_ADDRFROMCOORD_OUTPUT* pOut ///< [out] htile 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 zStencilAddr = pIn->zStencilAddr;
UINT_32 elemBits = pIn->bpp;
UINT_32 blockByte = 64 * elemBits / 8;
UINT_64 metaNibbleAddress = HwlComputeMetadataNibbleAddress(zStencilAddr,
0,
0,
32, // htile 32 bits
elemBits,
blockByte,
m_pipeInterleaveBytes,
numOfPipes,
numOfBanks,
1);
pOut->addr = (metaNibbleAddress >> 1);
pOut->bitPosition = 0;
returnCode = ADDR_OK;
}
return returnCode;
}
/**
****************************************************************************************************
* CiLib::HwlConvertChipFamily
*
* @brief
* Convert familyID defined in atiid.h to ChipFamily and set m_chipFamily/m_chipRevision
* @return
* ChipFamily
****************************************************************************************************
*/
ChipFamily CiLib::HwlConvertChipFamily(
UINT_32 uChipFamily, ///< [in] chip family defined in atiih.h
UINT_32 uChipRevision) ///< [in] chip revision defined in "asic_family"_id.h
{
ChipFamily 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);
family = ADDR_CHIP_FAMILY_VI;
break;
case FAMILY_CZ:
m_settings.isCarrizo = 1;
m_settings.isVolcanicIslands = 1;
family = ADDR_CHIP_FAMILY_VI;
break;
default:
ADDR_ASSERT(!"This should be a unexpected Fusion");
break;
}
return family;
}
/**
****************************************************************************************************
* CiLib::HwlInitGlobalParams
*
* @brief
* Initializes global parameters
*
* @return
* TRUE if all settings are valid
*
****************************************************************************************************
*/
BOOL_32 CiLib::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)
{
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);
}
if (valid)
{
InitEquationTable();
}
return valid;
}
/**
****************************************************************************************************
* CiLib::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 CiLib::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;
}
/**
****************************************************************************************************
* CiLib::HwlSetupTileCfg
*
* @brief
* Map tile index to tile setting.
* @return
* ADDR_E_RETURNCODE
****************************************************************************************************
*/
ADDR_E_RETURNCODE CiLib::HwlSetupTileCfg(
UINT_32 bpp, ///< Bits per pixel
INT_32 index, ///< Tile index
INT_32 macroModeIndex, ///< 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 (index == TileIndexLinearGeneral)
{
pInfo->banks = 2;
pInfo->bankWidth = 1;
pInfo->bankHeight = 1;
pInfo->macroAspectRatio = 1;
pInfo->tileSplitBytes = 64;
pInfo->pipeConfig = ADDR_PIPECFG_P2;
}
else if (static_cast<UINT_32>(index) >= m_noOfEntries)
{
returnCode = ADDR_INVALIDPARAMS;
}
else
{
const 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 = Thickness(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;
}
/**
****************************************************************************************************
* CiLib::HwlComputeSurfaceInfo
*
* @brief
* Entry of CI's ComputeSurfaceInfo
* @return
* ADDR_E_RETURNCODE
****************************************************************************************************
*/
ADDR_E_RETURNCODE CiLib::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 = SiLib::HwlComputeSurfaceInfo(pIn, pOut);
if ((pIn->mipLevel > 0) &&
(pOut->tcCompatible == TRUE) &&
(pOut->tileMode != pIn->tileMode) &&
(m_settings.isVolcanicIslands == TRUE))
{
pOut->tcCompatible = CheckTcCompatibility(pOut->pTileInfo, pIn->bpp, pOut->tileMode, pOut->tileType, pOut);
}
if (pOut->macroModeIndex == TileIndexNoMacroIndex)
{
pOut->macroModeIndex = TileIndexInvalid;
}
if ((pIn->flags.matchStencilTileCfg == TRUE) &&
(pIn->flags.depth == TRUE))
{
pOut->stencilTileIdx = TileIndexInvalid;
if ((MinDepth2DThinIndex <= pOut->tileIndex) &&
(MaxDepth2DThinIndex >= pOut->tileIndex))
{
BOOL_32 depthStencil2DTileConfigMatch = DepthStencilTileCfgMatch(pIn, pOut);
if ((depthStencil2DTileConfigMatch == FALSE) &&
(pOut->tcCompatible == TRUE))
{
pOut->macroModeIndex = TileIndexInvalid;
ADDR_COMPUTE_SURFACE_INFO_INPUT localIn = *pIn;
localIn.tileIndex = TileIndexInvalid;
localIn.pTileInfo = NULL;
localIn.flags.tcCompatible = FALSE;
SiLib::HwlComputeSurfaceInfo(&localIn, pOut);
ADDR_ASSERT(((MinDepth2DThinIndex <= pOut->tileIndex) && (MaxDepth2DThinIndex >= pOut->tileIndex)) || pOut->tileIndex == Depth1DThinIndex);
depthStencil2DTileConfigMatch = DepthStencilTileCfgMatch(pIn, pOut);
}
if ((depthStencil2DTileConfigMatch == FALSE) &&
(pIn->numSamples <= 1))
{
pOut->macroModeIndex = TileIndexInvalid;
ADDR_COMPUTE_SURFACE_INFO_INPUT localIn = *pIn;
localIn.tileMode = ADDR_TM_1D_TILED_THIN1;
localIn.tileIndex = TileIndexInvalid;
localIn.pTileInfo = NULL;
retCode = SiLib::HwlComputeSurfaceInfo(&localIn, pOut);
}
}
if (pOut->tileIndex == Depth1DThinIndex)
{
pOut->stencilTileIdx = Depth1DThinIndex;
}
}
return retCode;
}
/**
****************************************************************************************************
* CiLib::HwlFmaskSurfaceInfo
* @brief
* Entry of r800's ComputeFmaskInfo
* @return
* ADDR_E_RETURNCODE
****************************************************************************************************
*/
ADDR_E_RETURNCODE CiLib::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;
}
/**
****************************************************************************************************
* CiLib::HwlFmaskPreThunkSurfInfo
*
* @brief
* Some preparation before thunking a ComputeSurfaceInfo call for Fmask
* @return
* ADDR_E_RETURNCODE
****************************************************************************************************
*/
VOID CiLib::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;
}
/**
****************************************************************************************************
* CiLib::HwlFmaskPostThunkSurfInfo
*
* @brief
* Copy hwl extra field after calling thunked ComputeSurfaceInfo
* @return
* ADDR_E_RETURNCODE
****************************************************************************************************
*/
VOID CiLib::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;
}
/**
****************************************************************************************************
* CiLib::HwlDegradeThickTileMode
*
* @brief
* Degrades valid tile mode for thick modes if needed
*
* @return
* Suitable tile mode
****************************************************************************************************
*/
AddrTileMode CiLib::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;
}
/**
****************************************************************************************************
* CiLib::HwlOptimizeTileMode
*
* @brief
* Optimize tile mode on CI
*
* @return
* N/A
*
****************************************************************************************************
*/
VOID CiLib::HwlOptimizeTileMode(
ADDR_COMPUTE_SURFACE_INFO_INPUT* pInOut ///< [in,out] input output structure
) const
{
AddrTileMode tileMode = pInOut->tileMode;
// Override 2D/3D macro tile mode to PRT_* tile mode if
// client driver requests this surface is equation compatible
if (IsMacroTiled(tileMode) == TRUE)
{
if ((pInOut->flags.needEquation == TRUE) &&
(pInOut->numSamples <= 1) &&
(IsPrtTileMode(tileMode) == FALSE))
{
if ((pInOut->numSlices > 1) && ((pInOut->maxBaseAlign == 0) || (pInOut->maxBaseAlign >= Block64K)))
{
UINT_32 thickness = Thickness(tileMode);
if (thickness == 1)
{
tileMode = ADDR_TM_PRT_TILED_THIN1;
}
else
{
static const UINT_32 PrtTileBytes = 0x10000;
// First prt thick tile index in the tile mode table
static const UINT_32 PrtThickTileIndex = 22;
ADDR_TILEINFO tileInfo = {0};
HwlComputeMacroModeIndex(PrtThickTileIndex,
pInOut->flags,
pInOut->bpp,
pInOut->numSamples,
&tileInfo);
UINT_32 macroTileBytes = ((pInOut->bpp) >> 3) * 64 * pInOut->numSamples *
thickness * HwlGetPipes(&tileInfo) *
tileInfo.banks * tileInfo.bankWidth *
tileInfo.bankHeight;
if (macroTileBytes <= PrtTileBytes)
{
tileMode = ADDR_TM_PRT_TILED_THICK;
}
else
{
tileMode = ADDR_TM_PRT_TILED_THIN1;
}
}
}
}
if (pInOut->maxBaseAlign != 0)
{
pInOut->flags.dccPipeWorkaround = FALSE;
}
}
if (tileMode != pInOut->tileMode)
{
pInOut->tileMode = tileMode;
}
}
/**
****************************************************************************************************
* CiLib::HwlOverrideTileMode
*
* @brief
* Override THICK to THIN, for specific formats on CI
*
* @return
* N/A
*
****************************************************************************************************
*/
VOID CiLib::HwlOverrideTileMode(
ADDR_COMPUTE_SURFACE_INFO_INPUT* pInOut ///< [in,out] input output structure
) const
{
AddrTileMode tileMode = pInOut->tileMode;
AddrTileType tileType = pInOut->tileType;
// 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 = Thickness(tileMode);
// tile_thickness = (array_mode == XTHICK) ? 8 : ((array_mode == THICK) ? 4 : 1)
if (thickness > 1)
{
switch (pInOut->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 != pInOut->tileMode)
{
// see tileIndex: 13-18
tileType = ADDR_NON_DISPLAYABLE;
}
break;
default:
break;
}
}
}
if (tileMode != pInOut->tileMode)
{
pInOut->tileMode = tileMode;
pInOut->tileType = tileType;
}
}
/**
****************************************************************************************************
* CiLib::HwlSelectTileMode
*
* @brief
* Select tile modes.
*
* @return
* N/A
*
****************************************************************************************************
*/
VOID CiLib::HwlSelectTileMode(
ADDR_COMPUTE_SURFACE_INFO_INPUT* pInOut ///< [in,out] input output structure
) const
{
AddrTileMode tileMode;
AddrTileType tileType;
if (pInOut->flags.rotateDisplay)
{
tileMode = ADDR_TM_2D_TILED_THIN1;
tileType = ADDR_ROTATED;
}
else if (pInOut->flags.volume)
{
BOOL_32 bThin = (m_settings.isBonaire == TRUE) ||
((m_allowNonDispThickModes == TRUE) && (pInOut->flags.color == TRUE));
if (pInOut->numSlices >= 8)
{
tileMode = ADDR_TM_2D_TILED_XTHICK;
tileType = (bThin == TRUE) ? ADDR_NON_DISPLAYABLE : ADDR_THICK;
}
else if (pInOut->numSlices >= 4)
{
tileMode = ADDR_TM_2D_TILED_THICK;
tileType = (bThin == TRUE) ? ADDR_NON_DISPLAYABLE : ADDR_THICK;
}
else
{
tileMode = ADDR_TM_2D_TILED_THIN1;
tileType = ADDR_NON_DISPLAYABLE;
}
}
else
{
tileMode = ADDR_TM_2D_TILED_THIN1;
if (pInOut->flags.depth || pInOut->flags.stencil)
{
tileType = ADDR_DEPTH_SAMPLE_ORDER;
}
else if ((pInOut->bpp <= 32) ||
(pInOut->flags.display == TRUE) ||
(pInOut->flags.overlay == TRUE))
{
tileType = ADDR_DISPLAYABLE;
}
else
{
tileType = ADDR_NON_DISPLAYABLE;
}
}
if (pInOut->flags.prt)
{
if (Thickness(tileMode) > 1)
{
tileMode = ADDR_TM_PRT_TILED_THICK;
tileType = (m_settings.isBonaire == TRUE) ? ADDR_NON_DISPLAYABLE : ADDR_THICK;
}
else
{
tileMode = ADDR_TM_PRT_TILED_THIN1;
}
}
pInOut->tileMode = tileMode;
pInOut->tileType = tileType;
if ((pInOut->flags.dccCompatible == FALSE) &&
(pInOut->flags.tcCompatible == FALSE))
{
pInOut->flags.opt4Space = TRUE;
pInOut->maxBaseAlign = Block64K;
}
// Optimize tile mode if possible
OptimizeTileMode(pInOut);
HwlOverrideTileMode(pInOut);
}
/**
****************************************************************************************************
* CiLib::HwlSetPrtTileMode
*
* @brief
* Set PRT tile mode.
*
* @return
* N/A
*
****************************************************************************************************
*/
VOID CiLib::HwlSetPrtTileMode(
ADDR_COMPUTE_SURFACE_INFO_INPUT* pInOut ///< [in,out] input output structure
) const
{
AddrTileMode tileMode = pInOut->tileMode;
AddrTileType tileType = pInOut->tileType;
if (Thickness(tileMode) > 1)
{
tileMode = ADDR_TM_PRT_TILED_THICK;
tileType = (m_settings.isBonaire == TRUE) ? ADDR_NON_DISPLAYABLE : ADDR_THICK;
}
else
{
tileMode = ADDR_TM_PRT_TILED_THIN1;
tileType = (tileType == ADDR_THICK) ? ADDR_NON_DISPLAYABLE : tileType;
}
pInOut->tileMode = tileMode;
pInOut->tileType = tileType;
}
/**
****************************************************************************************************
* CiLib::HwlSetupTileInfo
*
* @brief
* Setup default value of tile info for SI
****************************************************************************************************
*/
VOID CiLib::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 = Thickness(tileMode);
ADDR_TILEINFO* pTileInfo = pTileInfoOut;
INT index = TileIndexInvalid;
INT macroModeIndex = TileIndexInvalid;
// Fail-safe code
if (IsLinear(tileMode) == FALSE)
{
// 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) ||
// There is no PRT_THICK + THIN entry in tile mode table except Bonaire
(IsPrtTileMode(tileMode) == TRUE))
{
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;
}
}
// tcCompatible flag is only meaningful for gfx8.
if (m_settings.isVolcanicIslands == FALSE)
{
flags.tcCompatible = FALSE;
}
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;
}
if (flags.nonSplit | flags.tcCompatible | flags.needEquation)
{
// Texture readable depth surface should not be split
switch (tileSize)
{
case 64:
index = 0;
break;
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
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
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);
flags.tcCompatible = FALSE;
pOut->dccUnsupport = TRUE;
}
}
}
}
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;
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;
}
}
UINT_32 numPipes = GetPipePerSurf(pTileInfo->pipeConfig);
if (m_pipes != numPipes)
{
pOut->dccUnsupport = TRUE;
}
}
// 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;
}
if (flags.tcCompatible)
{
flags.tcCompatible = CheckTcCompatibility(pTileInfo, bpp, tileMode, inTileType, pOut);
}
pOut->tcCompatible = flags.tcCompatible;
}
/**
****************************************************************************************************
* CiLib::ReadGbTileMode
*
* @brief
* Convert GB_TILE_MODE HW value to ADDR_TILE_CONFIG.
****************************************************************************************************
*/
VOID CiLib::ReadGbTileMode(
UINT_32 regValue, ///< [in] GB_TILE_MODE register
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;
}
}
/**
****************************************************************************************************
* CiLib::InitTileSettingTable
*
* @brief
* Initialize the ADDR_TILE_CONFIG table.
* @return
* TRUE if tile table is correctly initialized
****************************************************************************************************
*/
BOOL_32 CiLib::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;
}
/**
****************************************************************************************************
* CiLib::ReadGbMacroTileCfg
*
* @brief
* Convert GB_MACRO_TILE_CFG HW value to ADDR_TILE_CONFIG.
****************************************************************************************************
*/
VOID CiLib::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;
}
/**
****************************************************************************************************
* CiLib::InitMacroTileCfgTable
*
* @brief
* Initialize the ADDR_MACRO_TILE_CONFIG table.
* @return
* TRUE if macro tile table is correctly initialized
****************************************************************************************************
*/
BOOL_32 CiLib::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;
}
/**
****************************************************************************************************
* CiLib::HwlComputeMacroModeIndex
*
* @brief
* Computes macro tile mode index
* @return
* TRUE if macro tile table is correctly initialized
****************************************************************************************************
*/
INT_32 CiLib::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 = Thickness(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))
{
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;
}
/**
****************************************************************************************************
* CiLib::HwlComputeTileDataWidthAndHeightLinear
*
* @brief
* Compute the squared cache shape for per-tile data (CMASK and HTILE) for linear layout
*
* @note
* MacroWidth and macroHeight are measured in pixels
****************************************************************************************************
*/
VOID CiLib::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;
}
/**
****************************************************************************************************
* CiLib::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 CiLib::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 = GetBits(offset, msb, lsb);
///--------------------------------------------------------------------------------------------
/// Save pipe data bits
///--------------------------------------------------------------------------------------------
lsb = pipeInterleaveBits;
msb = pipeBits - 1 + lsb;
UINT_64 pipeDataBits = GetBits(offset, msb, lsb);
///--------------------------------------------------------------------------------------------
/// Remove pipe and bank bits
///--------------------------------------------------------------------------------------------
lsb = pipeInterleaveBits;
msb = dataMacrotileBits - 1;
UINT_64 offsetWithoutPipeBankBits = RemoveBits(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 = InsertBits(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 = InsertBits(metaAddressInPipe, pipeDataBits, msb, lsb);
return metadataAddress;
}
/**
****************************************************************************************************
* CiLib::HwlComputeSurfaceAlignmentsMacroTiled
*
* @brief
* Hardware layer function to compute alignment request for macro tile mode
*
****************************************************************************************************
*/
VOID CiLib::HwlComputeSurfaceAlignmentsMacroTiled(
AddrTileMode tileMode, ///< [in] tile mode
UINT_32 bpp, ///< [in] bits per pixel
ADDR_SURFACE_FLAGS flags, ///< [in] surface flags
UINT_32 mipLevel, ///< [in] mip level
UINT_32 numSamples, ///< [in] number of samples
ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [in,out] Surface output
) const
{
// This is to workaround a H/W limitation that DCC doesn't work when pipe config is switched to
// P4. In theory, all asics that have such switching should be patched but we now only know what
// to pad for Fiji.
if ((m_settings.isFiji == TRUE) &&
(flags.dccPipeWorkaround == TRUE) &&
(flags.prt == FALSE) &&
(mipLevel == 0) &&
(tileMode == ADDR_TM_PRT_TILED_THIN1) &&
(pOut->dccUnsupport == TRUE))
{
pOut->pitchAlign = PowTwoAlign(pOut->pitchAlign, 256);
// In case the client still requests DCC usage.
pOut->dccUnsupport = FALSE;
}
}
/**
****************************************************************************************************
* CiLib::HwlPadDimensions
*
* @brief
* Helper function to pad dimensions
*
****************************************************************************************************
*/
VOID CiLib::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] tile info
UINT_32 mipLevel, ///< [in] mip level
UINT_32* pPitch, ///< [in,out] pitch in pixels
UINT_32* pPitchAlign, ///< [in,out] pitch alignment
UINT_32 height, ///< [in] height in pixels
UINT_32 heightAlign ///< [in] height alignment
) const
{
if ((m_settings.isVolcanicIslands == TRUE) &&
(flags.dccCompatible == TRUE) &&
(numSamples > 1) &&
(mipLevel == 0) &&
(IsMacroTiled(tileMode) == TRUE))
{
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) * height * bpp * samplesPerSplit);
ADDR_ASSERT(IsPow2(dccFastClearByteAlign));
if (0 != (bytesPerSplit & (dccFastClearByteAlign - 1)))
{
UINT_32 dccFastClearPixelAlign = dccFastClearByteAlign /
BITS_TO_BYTES(bpp) /
samplesPerSplit;
UINT_32 macroTilePixelAlign = (*pPitchAlign) * heightAlign;
if ((dccFastClearPixelAlign >= macroTilePixelAlign) &&
((dccFastClearPixelAlign % macroTilePixelAlign) == 0))
{
UINT_32 dccFastClearPitchAlignInMacroTile =
dccFastClearPixelAlign / macroTilePixelAlign;
UINT_32 heightInMacroTile = height / heightAlign;
while ((heightInMacroTile > 1) &&
((heightInMacroTile % 2) == 0) &&
(dccFastClearPitchAlignInMacroTile > 1) &&
((dccFastClearPitchAlignInMacroTile % 2) == 0))
{
heightInMacroTile >>= 1;
dccFastClearPitchAlignInMacroTile >>= 1;
}
UINT_32 dccFastClearPitchAlignInPixels =
(*pPitchAlign) * dccFastClearPitchAlignInMacroTile;
if (IsPow2(dccFastClearPitchAlignInPixels))
{
*pPitch = PowTwoAlign((*pPitch), dccFastClearPitchAlignInPixels);
}
else
{
*pPitch += (dccFastClearPitchAlignInPixels - 1);
*pPitch /= dccFastClearPitchAlignInPixels;
*pPitch *= dccFastClearPitchAlignInPixels;
}
*pPitchAlign = dccFastClearPitchAlignInPixels;
}
}
}
}
}
/**
****************************************************************************************************
* CiLib::HwlGetMaxAlignments
*
* @brief
* Gets maximum alignments
* @return
* ADDR_E_RETURNCODE
****************************************************************************************************
*/
ADDR_E_RETURNCODE CiLib::HwlGetMaxAlignments(
ADDR_GET_MAX_ALIGNMENTS_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;
}
/**
****************************************************************************************************
* CiLib::DepthStencilTileCfgMatch
*
* @brief
* Try to find a tile index for stencil which makes its tile config parameters matches to depth
* @return
* TRUE if such tile index for stencil can be found
****************************************************************************************************
*/
BOOL_32 CiLib::DepthStencilTileCfgMatch(
const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure
ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure
) const
{
BOOL_32 depthStencil2DTileConfigMatch = FALSE;
for (INT_32 stencilTileIndex = MinDepth2DThinIndex;
stencilTileIndex <= MaxDepth2DThinIndex;
stencilTileIndex++)
{
ADDR_TILEINFO tileInfo = {0};
INT_32 stencilMacroIndex = HwlComputeMacroModeIndex(stencilTileIndex,
pIn->flags,
8,
pIn->numSamples,
&tileInfo);
if (stencilMacroIndex != TileIndexNoMacroIndex)
{
if ((m_macroTileTable[stencilMacroIndex].banks ==
m_macroTileTable[pOut->macroModeIndex].banks) &&
(m_macroTileTable[stencilMacroIndex].bankWidth ==
m_macroTileTable[pOut->macroModeIndex].bankWidth) &&
(m_macroTileTable[stencilMacroIndex].bankHeight ==
m_macroTileTable[pOut->macroModeIndex].bankHeight) &&
(m_macroTileTable[stencilMacroIndex].macroAspectRatio ==
m_macroTileTable[pOut->macroModeIndex].macroAspectRatio) &&
(m_macroTileTable[stencilMacroIndex].pipeConfig ==
m_macroTileTable[pOut->macroModeIndex].pipeConfig))
{
if ((pOut->tcCompatible == FALSE) ||
(tileInfo.tileSplitBytes >= MicroTileWidth * MicroTileHeight * pIn->numSamples))
{
depthStencil2DTileConfigMatch = TRUE;
pOut->stencilTileIdx = stencilTileIndex;
break;
}
}
}
else
{
ADDR_ASSERT_ALWAYS();
}
}
return depthStencil2DTileConfigMatch;
}
/**
****************************************************************************************************
* CiLib::DepthStencilTileCfgMatch
*
* @brief
* Check if tc compatibility is available
* @return
* If tc compatibility is not available
****************************************************************************************************
*/
BOOL_32 CiLib::CheckTcCompatibility(
const ADDR_TILEINFO* pTileInfo, ///< [in] input tile info
UINT_32 bpp, ///< [in] Bits per pixel
AddrTileMode tileMode, ///< [in] input tile mode
AddrTileType tileType, ///< [in] input tile type
const ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [in] output surf info
) const
{
BOOL_32 tcCompatible = TRUE;
if (IsMacroTiled(tileMode))
{
if (tileType != ADDR_DEPTH_SAMPLE_ORDER)
{
// Turn off tcCompatible for color surface if tileSplit happens. Depth/stencil
// tileSplit case was handled at tileIndex selecting time.
INT_32 tileIndex = pOut->tileIndex;
if ((tileIndex == TileIndexInvalid) && (IsTileInfoAllZero(pTileInfo) == FALSE))
{
tileIndex = HwlPostCheckTileIndex(pTileInfo, tileMode, tileType, tileIndex);
}
if (tileIndex != TileIndexInvalid)
{
UINT_32 thickness = Thickness(tileMode);
ADDR_ASSERT(static_cast<UINT_32>(tileIndex) < TileTableSize);
// Non-depth entries store a split factor
UINT_32 sampleSplit = m_tileTable[tileIndex].info.tileSplitBytes;
UINT_32 tileBytes1x = BITS_TO_BYTES(bpp * MicroTilePixels * thickness);
UINT_32 colorTileSplit = Max(256u, sampleSplit * tileBytes1x);
if (m_rowSize < colorTileSplit)
{
tcCompatible = FALSE;
}
}
}
}
else
{
// Client should not enable tc compatible for linear and 1D tile modes.
tcCompatible = FALSE;
}
return tcCompatible;
}
} // V1
} // Addr