/*
* 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 siaddrlib.cpp
* @brief Contains the implementation for the SIAddrLib class.
***************************************************************************************************
*/
#include "siaddrlib.h"
#include "si_gb_reg.h"
#include "si_ci_vi_merged_enum.h"
#if BRAHMA_BUILD
#include "amdgpu_id.h"
#else
#include "si_id.h"
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
***************************************************************************************************
* AddrSIHwlInit
*
* @brief
* Creates an SIAddrLib object.
*
* @return
* Returns an SIAddrLib object pointer.
***************************************************************************************************
*/
AddrLib* AddrSIHwlInit(const AddrClient* pClient)
{
return SIAddrLib::CreateObj(pClient);
}
/**
***************************************************************************************************
* SIAddrLib::SIAddrLib
*
* @brief
* Constructor
*
***************************************************************************************************
*/
SIAddrLib::SIAddrLib(const AddrClient* pClient) :
EgBasedAddrLib(pClient),
m_noOfEntries(0)
{
m_class = SI_ADDRLIB;
memset(&m_settings, 0, sizeof(m_settings));
}
/**
***************************************************************************************************
* SIAddrLib::~SIAddrLib
*
* @brief
* Destructor
***************************************************************************************************
*/
SIAddrLib::~SIAddrLib()
{
}
/**
***************************************************************************************************
* SIAddrLib::HwlGetPipes
*
* @brief
* Get number pipes
* @return
* num pipes
***************************************************************************************************
*/
UINT_32 SIAddrLib::HwlGetPipes(
const ADDR_TILEINFO* pTileInfo ///< [in] Tile info
) const
{
UINT_32 numPipes;
if (pTileInfo)
{
numPipes = GetPipePerSurf(pTileInfo->pipeConfig);
}
else
{
ADDR_ASSERT_ALWAYS();
numPipes = m_pipes; // Suppose we should still have a global pipes
}
return numPipes;
}
/**
***************************************************************************************************
* SIAddrLib::GetPipePerSurf
* @brief
* get pipe num base on inputing tileinfo->pipeconfig
* @return
* pipe number
***************************************************************************************************
*/
UINT_32 SIAddrLib::GetPipePerSurf(
AddrPipeCfg pipeConfig ///< [in] pipe config
) const
{
UINT_32 numPipes = 0;
switch (pipeConfig)
{
case ADDR_PIPECFG_P2:
numPipes = 2;
break;
case ADDR_PIPECFG_P4_8x16:
case ADDR_PIPECFG_P4_16x16:
case ADDR_PIPECFG_P4_16x32:
case ADDR_PIPECFG_P4_32x32:
numPipes = 4;
break;
case ADDR_PIPECFG_P8_16x16_8x16:
case ADDR_PIPECFG_P8_16x32_8x16:
case ADDR_PIPECFG_P8_32x32_8x16:
case ADDR_PIPECFG_P8_16x32_16x16:
case ADDR_PIPECFG_P8_32x32_16x16:
case ADDR_PIPECFG_P8_32x32_16x32:
case ADDR_PIPECFG_P8_32x64_32x32:
numPipes = 8;
break;
case ADDR_PIPECFG_P16_32x32_8x16:
case ADDR_PIPECFG_P16_32x32_16x16:
numPipes = 16;
break;
default:
ADDR_ASSERT(!"Invalid pipe config");
numPipes = m_pipes;
}
return numPipes;
}
/**
***************************************************************************************************
* SIAddrLib::ComputePipeFromCoord
*
* @brief
* Compute pipe number from coordinates
* @return
* Pipe number
***************************************************************************************************
*/
UINT_32 SIAddrLib::ComputePipeFromCoord(
UINT_32 x, ///< [in] x coordinate
UINT_32 y, ///< [in] y coordinate
UINT_32 slice, ///< [in] slice index
AddrTileMode tileMode, ///< [in] tile mode
UINT_32 pipeSwizzle, ///< [in] pipe swizzle
BOOL_32 ignoreSE, ///< [in] TRUE if shader engines are ignored
ADDR_TILEINFO* pTileInfo ///< [in] Tile info
) const
{
UINT_32 pipe;
UINT_32 pipeBit0 = 0;
UINT_32 pipeBit1 = 0;
UINT_32 pipeBit2 = 0;
UINT_32 pipeBit3 = 0;
UINT_32 sliceRotation;
UINT_32 numPipes = 0;
UINT_32 tx = x / MicroTileWidth;
UINT_32 ty = y / MicroTileHeight;
UINT_32 x3 = _BIT(tx,0);
UINT_32 x4 = _BIT(tx,1);
UINT_32 x5 = _BIT(tx,2);
UINT_32 x6 = _BIT(tx,3);
UINT_32 y3 = _BIT(ty,0);
UINT_32 y4 = _BIT(ty,1);
UINT_32 y5 = _BIT(ty,2);
UINT_32 y6 = _BIT(ty,3);
switch (pTileInfo->pipeConfig)
{
case ADDR_PIPECFG_P2:
pipeBit0 = x3 ^ y3;
numPipes = 2;
break;
case ADDR_PIPECFG_P4_8x16:
pipeBit0 = x4 ^ y3;
pipeBit1 = x3 ^ y4;
numPipes = 4;
break;
case ADDR_PIPECFG_P4_16x16:
pipeBit0 = x3 ^ y3 ^ x4;
pipeBit1 = x4 ^ y4;
numPipes = 4;
break;
case ADDR_PIPECFG_P4_16x32:
pipeBit0 = x3 ^ y3 ^ x4;
pipeBit1 = x4 ^ y5;
numPipes = 4;
break;
case ADDR_PIPECFG_P4_32x32:
pipeBit0 = x3 ^ y3 ^ x5;
pipeBit1 = x5 ^ y5;
numPipes = 4;
break;
case ADDR_PIPECFG_P8_16x16_8x16:
pipeBit0 = x4 ^ y3 ^ x5;
pipeBit1 = x3 ^ y5;
numPipes = 8;
break;
case ADDR_PIPECFG_P8_16x32_8x16:
pipeBit0 = x4 ^ y3 ^ x5;
pipeBit1 = x3 ^ y4;
pipeBit2 = x4 ^ y5;
numPipes = 8;
break;
case ADDR_PIPECFG_P8_16x32_16x16:
pipeBit0 = x3 ^ y3 ^ x4;
pipeBit1 = x5 ^ y4;
pipeBit2 = x4 ^ y5;
numPipes = 8;
break;
case ADDR_PIPECFG_P8_32x32_8x16:
pipeBit0 = x4 ^ y3 ^ x5;
pipeBit1 = x3 ^ y4;
pipeBit2 = x5 ^ y5;
numPipes = 8;
break;
case ADDR_PIPECFG_P8_32x32_16x16:
pipeBit0 = x3 ^ y3 ^ x4;
pipeBit1 = x4 ^ y4;
pipeBit2 = x5 ^ y5;
numPipes = 8;
break;
case ADDR_PIPECFG_P8_32x32_16x32:
pipeBit0 = x3 ^ y3 ^ x4;
pipeBit1 = x4 ^ y6;
pipeBit2 = x5 ^ y5;
numPipes = 8;
break;
case ADDR_PIPECFG_P8_32x64_32x32:
pipeBit0 = x3 ^ y3 ^ x5;
pipeBit1 = x6 ^ y5;
pipeBit2 = x5 ^ y6;
numPipes = 8;
break;
case ADDR_PIPECFG_P16_32x32_8x16:
pipeBit0 = x4 ^ y3;
pipeBit1 = x3 ^ y4;
pipeBit2 = x5 ^ y6;
pipeBit3 = x6 ^ y5;
numPipes = 16;
break;
case ADDR_PIPECFG_P16_32x32_16x16:
pipeBit0 = x3 ^ y3 ^ x4;
pipeBit1 = x4 ^ y4;
pipeBit2 = x5 ^ y6;
pipeBit3 = x6 ^ y5;
numPipes = 16;
break;
default:
ADDR_UNHANDLED_CASE();
break;
}
pipe = pipeBit0 | (pipeBit1 << 1) | (pipeBit2 << 2) | (pipeBit3 << 3);
UINT_32 microTileThickness = ComputeSurfaceThickness(tileMode);
//
// Apply pipe rotation for the slice.
//
switch (tileMode)
{
case ADDR_TM_3D_TILED_THIN1: //fall through thin
case ADDR_TM_3D_TILED_THICK: //fall through thick
case ADDR_TM_3D_TILED_XTHICK:
sliceRotation =
Max(1, static_cast<INT_32>(numPipes / 2) - 1) * (slice / microTileThickness);
break;
default:
sliceRotation = 0;
break;
}
pipeSwizzle += sliceRotation;
pipeSwizzle &= (numPipes - 1);
pipe = pipe ^ pipeSwizzle;
return pipe;
}
/**
***************************************************************************************************
* SIAddrLib::ComputeTileCoordFromPipeAndElemIdx
*
* @brief
* Compute (x,y) of a tile within a macro tile from address
* @return
* Pipe number
***************************************************************************************************
*/
VOID SIAddrLib::ComputeTileCoordFromPipeAndElemIdx(
UINT_32 elemIdx, ///< [in] per pipe element index within a macro tile
UINT_32 pipe, ///< [in] pipe index
AddrPipeCfg pipeCfg, ///< [in] pipe config
UINT_32 pitchInMacroTile, ///< [in] surface pitch in macro tile
UINT_32 x, ///< [in] x coordinate of the (0,0) tile in a macro tile
UINT_32 y, ///< [in] y coordinate of the (0,0) tile in a macro tile
UINT_32* pX, ///< [out] x coordinate
UINT_32* pY ///< [out] y coordinate
) const
{
UINT_32 pipebit0 = _BIT(pipe,0);
UINT_32 pipebit1 = _BIT(pipe,1);
UINT_32 pipebit2 = _BIT(pipe,2);
UINT_32 pipebit3 = _BIT(pipe,3);
UINT_32 elemIdx0 = _BIT(elemIdx,0);
UINT_32 elemIdx1 = _BIT(elemIdx,1);
UINT_32 elemIdx2 = _BIT(elemIdx,2);
UINT_32 x3 = 0;
UINT_32 x4 = 0;
UINT_32 x5 = 0;
UINT_32 x6 = 0;
UINT_32 y3 = 0;
UINT_32 y4 = 0;
UINT_32 y5 = 0;
UINT_32 y6 = 0;
switch(pipeCfg)
{
case ADDR_PIPECFG_P2:
x4 = elemIdx2;
y4 = elemIdx1 ^ x4;
y3 = elemIdx0 ^ x4;
x3 = pipebit0 ^ y3;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
break;
case ADDR_PIPECFG_P4_8x16:
x4 = elemIdx1;
y4 = elemIdx0 ^ x4;
x3 = pipebit1 ^ y4;
y3 = pipebit0 ^ x4;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
break;
case ADDR_PIPECFG_P4_16x16:
x4 = elemIdx1;
y3 = elemIdx0 ^ x4;
y4 = pipebit1 ^ x4;
x3 = pipebit0 ^ y3 ^ x4;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
break;
case ADDR_PIPECFG_P4_16x32:
x3 = elemIdx0 ^ pipebit0;
y5 = _BIT(y,5);
x4 = pipebit1 ^ y5;
y3 = pipebit0 ^ x3 ^ x4;
y4 = elemIdx1 ^ x4;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
break;
case ADDR_PIPECFG_P4_32x32:
x4 = elemIdx2;
y3 = elemIdx0 ^ x4;
y4 = elemIdx1 ^ x4;
if((pitchInMacroTile % 2) == 0)
{ //even
y5 = _BIT(y,5);
x5 = pipebit1 ^ y5;
x3 = pipebit0 ^ y3 ^ x5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(3, x5, x4, x3);
}
else
{ //odd
x5 = _BIT(x,5);
x3 = pipebit0 ^ y3 ^ x5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
}
break;
case ADDR_PIPECFG_P8_16x16_8x16:
x4 = elemIdx0;
y5 = _BIT(y,5);
x5 = _BIT(x,5);
x3 = pipebit1 ^ y5;
y4 = pipebit2 ^ x4;
y3 = pipebit0 ^ x5 ^ x4;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
break;
case ADDR_PIPECFG_P8_16x32_8x16:
x3 = elemIdx0;
y4 = pipebit1 ^ x3;
y5 = _BIT(y,5);
x5 = _BIT(x,5);
x4 = pipebit2 ^ y5;
y3 = pipebit0 ^ x4 ^ x5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
break;
case ADDR_PIPECFG_P8_32x32_8x16:
x4 = elemIdx1;
y4 = elemIdx0 ^ x4;
x3 = pipebit1 ^ y4;
if((pitchInMacroTile % 2) == 0)
{ //even
y5 = _BIT(y,5);
x5 = _BIT(x,5);
x5 = pipebit2 ^ y5;
y3 = pipebit0 ^ x4 ^ x5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(3, x5, x4, x3);
}
else
{ //odd
x5 = _BIT(x,5);
y3 = pipebit0 ^ x4 ^ x5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
}
break;
case ADDR_PIPECFG_P8_16x32_16x16:
x3 = elemIdx0;
x5 = _BIT(x,5);
y5 = _BIT(y,5);
x4 = pipebit2 ^ y5;
y4 = pipebit1 ^ x5;
y3 = pipebit0 ^ x3 ^ x4;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
break;
case ADDR_PIPECFG_P8_32x32_16x16:
x4 = elemIdx1;
y3 = elemIdx0 ^ x4;
x3 = y3^x4^pipebit0;
y4 = pipebit1 ^ x4;
if((pitchInMacroTile % 2) == 0)
{ //even
y5 = _BIT(y,5);
x5 = pipebit2 ^ y5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(3, x5, x4, x3);
}
else
{ //odd
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
}
break;
case ADDR_PIPECFG_P8_32x32_16x32:
if((pitchInMacroTile % 2) == 0)
{ //even
y5 = _BIT(y,5);
y6 = _BIT(y,6);
x4 = pipebit1 ^ y6;
y3 = elemIdx0 ^ x4;
y4 = elemIdx1 ^ x4;
x3 = pipebit0 ^ y3 ^ x4;
x5 = pipebit2 ^ y5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(3, x5, x4, x3);
}
else
{ //odd
y6 = _BIT(y,6);
x4 = pipebit1 ^ y6;
y3 = elemIdx0 ^ x4;
y4 = elemIdx1 ^ x4;
x3 = pipebit0 ^ y3 ^ x4;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(2, x4, x3);
}
break;
case ADDR_PIPECFG_P8_32x64_32x32:
x4 = elemIdx2;
y3 = elemIdx0 ^ x4;
y4 = elemIdx1 ^ x4;
if((pitchInMacroTile % 4) == 0)
{ //multiple of 4
y5 = _BIT(y,5);
y6 = _BIT(y,6);
x5 = pipebit2 ^ y6;
x6 = pipebit1 ^ y5;
x3 = pipebit0 ^ y3 ^ x5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(4, x6, x5, x4, x3);
}
else
{
y6 = _BIT(y,6);
x5 = pipebit2 ^ y6;
x3 = pipebit0 ^ y3 ^ x5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(3, x5, x4, x3);
}
break;
case ADDR_PIPECFG_P16_32x32_8x16:
x4 = elemIdx1;
y4 = elemIdx0 ^ x4;
y3 = pipebit0 ^ x4;
x3 = pipebit1 ^ y4;
if((pitchInMacroTile % 4) == 0)
{ //multiple of 4
y5 = _BIT(y,5);
y6 = _BIT(y,6);
x5 = pipebit2 ^ y6;
x6 = pipebit3 ^ y5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(4, x6, x5,x4, x3);
}
else
{
y6 = _BIT(y,6);
x5 = pipebit2 ^ y6;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(3, x5, x4, x3);
}
break;
case ADDR_PIPECFG_P16_32x32_16x16:
x4 = elemIdx1;
y3 = elemIdx0 ^ x4;
y4 = pipebit1 ^ x4;
x3 = pipebit0 ^ y3 ^ x4;
if((pitchInMacroTile % 4) == 0)
{ //multiple of 4
y5 = _BIT(y,5);
y6 = _BIT(y,6);
x5 = pipebit2 ^ y6;
x6 = pipebit3 ^ y5;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(4, x6, x5, x4, x3);
}
else
{
y6 = _BIT(y,6);
x5 = pipebit2 ^ y6;
*pY = Bits2Number(2, y4, y3);
*pX = Bits2Number(3, x5, x4, x3);
}
break;
default:
ADDR_UNHANDLED_CASE();
}
}
/**
***************************************************************************************************
* SIAddrLib::TileCoordToMaskElementIndex
*
* @brief
* Compute element index from coordinates in tiles
* @return
* Element index
***************************************************************************************************
*/
UINT_32 SIAddrLib::TileCoordToMaskElementIndex(
UINT_32 tx, ///< [in] x coord, in Tiles
UINT_32 ty, ///< [in] y coord, in Tiles
AddrPipeCfg pipeConfig, ///< [in] pipe config
UINT_32* macroShift, ///< [out] macro shift
UINT_32* elemIdxBits ///< [out] tile offset bits
) const
{
UINT_32 elemIdx = 0;
UINT_32 elemIdx0, elemIdx1, elemIdx2;
UINT_32 tx0, tx1;
UINT_32 ty0, ty1;
tx0 = _BIT(tx,0);
tx1 = _BIT(tx,1);
ty0 = _BIT(ty,0);
ty1 = _BIT(ty,1);
switch(pipeConfig)
{
case ADDR_PIPECFG_P2:
*macroShift = 3;
*elemIdxBits =3;
elemIdx2 = tx1;
elemIdx1 = tx1 ^ ty1;
elemIdx0 = tx1 ^ ty0;
elemIdx = Bits2Number(3,elemIdx2,elemIdx1,elemIdx0);
break;
case ADDR_PIPECFG_P4_8x16:
*macroShift = 2;
*elemIdxBits =2;
elemIdx1 = tx1;
elemIdx0 = tx1 ^ ty1;
elemIdx = Bits2Number(2,elemIdx1,elemIdx0);
break;
case ADDR_PIPECFG_P4_16x16:
*macroShift = 2;
*elemIdxBits =2;
elemIdx0 = tx1^ty0;
elemIdx1 = tx1;
elemIdx = Bits2Number(2, elemIdx1, elemIdx0);
break;
case ADDR_PIPECFG_P4_16x32:
*macroShift = 2;
*elemIdxBits =2;
elemIdx0 = tx1^ty0;
elemIdx1 = tx1^ty1;
elemIdx = Bits2Number(2, elemIdx1, elemIdx0);
break;
case ADDR_PIPECFG_P4_32x32:
*macroShift = 2;
*elemIdxBits =3;
elemIdx0 = tx1^ty0;
elemIdx1 = tx1^ty1;
elemIdx2 = tx1;
elemIdx = Bits2Number(3, elemIdx2, elemIdx1, elemIdx0);
break;
case ADDR_PIPECFG_P8_16x16_8x16:
*macroShift = 1;
*elemIdxBits =1;
elemIdx0 = tx1;
elemIdx = elemIdx0;
break;
case ADDR_PIPECFG_P8_16x32_8x16:
*macroShift = 1;
*elemIdxBits =1;
elemIdx0 = tx0;
elemIdx = elemIdx0;
break;
case ADDR_PIPECFG_P8_32x32_8x16:
*macroShift = 1;
*elemIdxBits =2;
elemIdx1 = tx1;
elemIdx0 = tx1^ty1;
elemIdx = Bits2Number(2, elemIdx1, elemIdx0);
break;
case ADDR_PIPECFG_P8_16x32_16x16:
*macroShift = 1;
*elemIdxBits =1;
elemIdx0 = tx0;
elemIdx = elemIdx0;
break;
case ADDR_PIPECFG_P8_32x32_16x16:
*macroShift = 1;
*elemIdxBits =2;
elemIdx0 = tx1^ty0;
elemIdx1 = tx1;
elemIdx = Bits2Number(2, elemIdx1, elemIdx0);
break;
case ADDR_PIPECFG_P8_32x32_16x32:
*macroShift = 1;
*elemIdxBits =2;
elemIdx0 = tx1^ty0;
elemIdx1 = tx1^ty1;
elemIdx = Bits2Number(2, elemIdx1, elemIdx0);
break;
case ADDR_PIPECFG_P8_32x64_32x32:
*macroShift = 1;
*elemIdxBits =3;
elemIdx0 = tx1^ty0;
elemIdx1 = tx1^ty1;
elemIdx2 = tx1;
elemIdx = Bits2Number(3, elemIdx2, elemIdx1, elemIdx0);
break;
case ADDR_PIPECFG_P16_32x32_8x16:
*macroShift = 0;
*elemIdxBits =2;
elemIdx0 = tx1^ty1;
elemIdx1 = tx1;
elemIdx = Bits2Number(2, elemIdx1, elemIdx0);
break;
case ADDR_PIPECFG_P16_32x32_16x16:
*macroShift = 0;
*elemIdxBits =2;
elemIdx0 = tx1^ty0;
elemIdx1 = tx1;
elemIdx = Bits2Number(2, elemIdx1, elemIdx0);
break;
default:
ADDR_UNHANDLED_CASE();
break;
}
return elemIdx;
}
/**
***************************************************************************************************
* SIAddrLib::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 SIAddrLib::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 macroWidth;
UINT_32 macroHeight;
/// In linear mode, the htile or cmask buffer must be padded out to 4 tiles
/// but for P8_32x64_32x32, it must be padded out to 8 tiles
/// Actually there are more pipe configs which need 8-tile padding but SI family
/// has a bug which is fixed in CI family
if ((pTileInfo->pipeConfig == ADDR_PIPECFG_P8_32x64_32x32) ||
(pTileInfo->pipeConfig == ADDR_PIPECFG_P16_32x32_8x16) ||
(pTileInfo->pipeConfig == ADDR_PIPECFG_P8_32x32_16x16))
{
macroWidth = 8*MicroTileWidth;
macroHeight = 8*MicroTileHeight;
}
else
{
macroWidth = 4*MicroTileWidth;
macroHeight = 4*MicroTileHeight;
}
*pMacroWidth = macroWidth;
*pMacroHeight = macroHeight;
}
/**
***************************************************************************************************
* SIAddrLib::HwlComputeHtileBytes
*
* @brief
* Compute htile size in bytes
*
* @return
* Htile size in bytes
***************************************************************************************************
*/
UINT_64 SIAddrLib::HwlComputeHtileBytes(
UINT_32 pitch, ///< [in] pitch
UINT_32 height, ///< [in] height
UINT_32 bpp, ///< [in] bits per pixel
BOOL_32 isLinear, ///< [in] if it is linear mode
UINT_32 numSlices, ///< [in] number of slices
UINT_64* pSliceBytes, ///< [out] bytes per slice
UINT_32 baseAlign ///< [in] base alignments
) const
{
return ComputeHtileBytes(pitch, height, bpp, isLinear, numSlices, pSliceBytes, baseAlign);
}
/**
***************************************************************************************************
* SIAddrLib::HwlComputeXmaskAddrFromCoord
*
* @brief
* Compute address from coordinates for htile/cmask
* @return
* Byte address
***************************************************************************************************
*/
UINT_64 SIAddrLib::HwlComputeXmaskAddrFromCoord(
UINT_32 pitch, ///< [in] pitch
UINT_32 height, ///< [in] height
UINT_32 x, ///< [in] x coord
UINT_32 y, ///< [in] y coord
UINT_32 slice, ///< [in] slice/depth index
UINT_32 numSlices, ///< [in] number of slices
UINT_32 factor, ///< [in] factor that indicates cmask(2) or htile(1)
BOOL_32 isLinear, ///< [in] linear or tiled HTILE layout
BOOL_32 isWidth8, ///< [in] TRUE if width is 8, FALSE means 4. It's register value
BOOL_32 isHeight8, ///< [in] TRUE if width is 8, FALSE means 4. It's register value
ADDR_TILEINFO* pTileInfo, ///< [in] Tile info
UINT_32* pBitPosition ///< [out] bit position inside a byte
) const
{
UINT_32 tx = x / MicroTileWidth;
UINT_32 ty = y / MicroTileHeight;
UINT_32 newPitch;
UINT_32 newHeight;
UINT_64 totalBytes;
UINT_32 macroWidth;
UINT_32 macroHeight;
UINT_64 pSliceBytes;
UINT_32 pBaseAlign;
UINT_32 tileNumPerPipe;
UINT_32 elemBits;
if (factor == 2) //CMASK
{
ADDR_CMASK_FLAGS flags = {{0}};
tileNumPerPipe = 256;
ComputeCmaskInfo(flags,
pitch,
height,
numSlices,
isLinear,
pTileInfo,
&newPitch,
&newHeight,
&totalBytes,
¯oWidth,
¯oHeight);
elemBits = CmaskElemBits;
}
else //HTile
{
ADDR_HTILE_FLAGS flags = {{0}};
tileNumPerPipe = 512;
ComputeHtileInfo(flags,
pitch,
height,
numSlices,
isLinear,
TRUE,
TRUE,
pTileInfo,
&newPitch,
&newHeight,
&totalBytes,
¯oWidth,
¯oHeight,
&pSliceBytes,
&pBaseAlign);
elemBits = 32;
}
const UINT_32 pitchInTile = newPitch / MicroTileWidth;
const UINT_32 heightInTile = newHeight / MicroTileWidth;
UINT_64 macroOffset; // Per pipe starting offset of the macro tile in which this tile lies.
UINT_64 microNumber; // Per pipe starting offset of the macro tile in which this tile lies.
UINT_32 microX;
UINT_32 microY;
UINT_64 microOffset;
UINT_32 microShift;
UINT_64 totalOffset;
UINT_32 elemIdxBits;
UINT_32 elemIdx =
TileCoordToMaskElementIndex(tx, ty, pTileInfo->pipeConfig, µShift, &elemIdxBits);
UINT_32 numPipes = HwlGetPipes(pTileInfo);
if (isLinear)
{ //linear addressing
// Linear addressing is extremelly wasting memory if slice > 1, since each pipe has the full
// slice memory foot print instead of divided by numPipes.
microX = tx / 4; // Macro Tile is 4x4
microY = ty / 4 ;
microNumber = static_cast<UINT_64>(microX + microY * (pitchInTile / 4)) << microShift;
UINT_32 sliceBits = pitchInTile * heightInTile;
// do htile single slice alignment if the flag is true
if (m_configFlags.useHtileSliceAlign && (factor == 1)) //Htile
{
sliceBits = PowTwoAlign(sliceBits, BITS_TO_BYTES(HtileCacheBits) * numPipes / elemBits);
}
macroOffset = slice * (sliceBits / numPipes) * elemBits ;
}
else
{ //tiled addressing
const UINT_32 macroWidthInTile = macroWidth / MicroTileWidth; // Now in unit of Tiles
const UINT_32 macroHeightInTile = macroHeight / MicroTileHeight;
const UINT_32 pitchInCL = pitchInTile / macroWidthInTile;
const UINT_32 heightInCL = heightInTile / macroHeightInTile;
const UINT_32 macroX = x / macroWidth;
const UINT_32 macroY = y / macroHeight;
const UINT_32 macroNumber = macroX + macroY * pitchInCL + slice * pitchInCL * heightInCL;
// Per pipe starting offset of the cache line in which this tile lies.
microX = (x % macroWidth) / MicroTileWidth / 4; // Macro Tile is 4x4
microY = (y % macroHeight) / MicroTileHeight / 4 ;
microNumber = static_cast<UINT_64>(microX + microY * (macroWidth / MicroTileWidth / 4)) << microShift;
macroOffset = macroNumber * tileNumPerPipe * elemBits;
}
if(elemIdxBits == microShift)
{
microNumber += elemIdx;
}
else
{
microNumber >>= elemIdxBits;
microNumber <<= elemIdxBits;
microNumber += elemIdx;
}
microOffset = elemBits * microNumber;
totalOffset = microOffset + macroOffset;
UINT_32 pipe = ComputePipeFromCoord(x, y, 0, ADDR_TM_2D_TILED_THIN1, 0, FALSE, pTileInfo);
UINT_64 addrInBits = totalOffset % (m_pipeInterleaveBytes * 8) +
pipe * (m_pipeInterleaveBytes * 8) +
totalOffset / (m_pipeInterleaveBytes * 8) * (m_pipeInterleaveBytes * 8) * numPipes;
*pBitPosition = static_cast<UINT_32>(addrInBits) % 8;
UINT_64 addr = addrInBits / 8;
return addr;
}
/**
***************************************************************************************************
* SIAddrLib::HwlComputeXmaskCoordFromAddr
*
* @brief
* Compute the coord from an address of a cmask/htile
*
* @return
* N/A
*
* @note
* This method is reused by htile, so rename to Xmask
***************************************************************************************************
*/
VOID SIAddrLib::HwlComputeXmaskCoordFromAddr(
UINT_64 addr, ///< [in] address
UINT_32 bitPosition, ///< [in] bitPosition in a byte
UINT_32 pitch, ///< [in] pitch
UINT_32 height, ///< [in] height
UINT_32 numSlices, ///< [in] number of slices
UINT_32 factor, ///< [in] factor that indicates cmask or htile
BOOL_32 isLinear, ///< [in] linear or tiled HTILE layout
BOOL_32 isWidth8, ///< [in] Not used by SI
BOOL_32 isHeight8, ///< [in] Not used by SI
ADDR_TILEINFO* pTileInfo, ///< [in] Tile info
UINT_32* pX, ///< [out] x coord
UINT_32* pY, ///< [out] y coord
UINT_32* pSlice ///< [out] slice index
) const
{
UINT_32 newPitch;
UINT_32 newHeight;
UINT_64 totalBytes;
UINT_32 clWidth;
UINT_32 clHeight;
UINT_32 tileNumPerPipe;
UINT_64 sliceBytes;
*pX = 0;
*pY = 0;
*pSlice = 0;
if (factor == 2) //CMASK
{
ADDR_CMASK_FLAGS flags = {{0}};
tileNumPerPipe = 256;
ComputeCmaskInfo(flags,
pitch,
height,
numSlices,
isLinear,
pTileInfo,
&newPitch,
&newHeight,
&totalBytes,
&clWidth,
&clHeight);
}
else //HTile
{
ADDR_HTILE_FLAGS flags = {{0}};
tileNumPerPipe = 512;
ComputeHtileInfo(flags,
pitch,
height,
numSlices,
isLinear,
TRUE,
TRUE,
pTileInfo,
&newPitch,
&newHeight,
&totalBytes,
&clWidth,
&clHeight,
&sliceBytes);
}
const UINT_32 pitchInTile = newPitch / MicroTileWidth;
const UINT_32 heightInTile = newHeight / MicroTileWidth;
const UINT_32 pitchInMacroTile = pitchInTile / 4;
UINT_32 macroShift;
UINT_32 elemIdxBits;
// get macroShift and elemIdxBits
TileCoordToMaskElementIndex(0, 0, pTileInfo->pipeConfig, ¯oShift, &elemIdxBits);
const UINT_32 numPipes = HwlGetPipes(pTileInfo);
const UINT_32 pipe = (UINT_32)((addr / m_pipeInterleaveBytes) % numPipes);
// per pipe
UINT_64 localOffset = (addr % m_pipeInterleaveBytes) +
(addr / m_pipeInterleaveBytes / numPipes)* m_pipeInterleaveBytes;
UINT_32 tileIndex;
if (factor == 2) //CMASK
{
tileIndex = (UINT_32)(localOffset * 2 + (bitPosition != 0));
}
else
{
tileIndex = (UINT_32)(localOffset / 4);
}
UINT_32 macroOffset;
if (isLinear)
{
UINT_32 sliceSizeInTile = pitchInTile * heightInTile;
// do htile single slice alignment if the flag is true
if (m_configFlags.useHtileSliceAlign && (factor == 1)) //Htile
{
sliceSizeInTile = PowTwoAlign(sliceSizeInTile, static_cast<UINT_32>(sliceBytes) / 64);
}
*pSlice = tileIndex / (sliceSizeInTile / numPipes);
macroOffset = tileIndex % (sliceSizeInTile / numPipes);
}
else
{
const UINT_32 clWidthInTile = clWidth / MicroTileWidth; // Now in unit of Tiles
const UINT_32 clHeightInTile = clHeight / MicroTileHeight;
const UINT_32 pitchInCL = pitchInTile / clWidthInTile;
const UINT_32 heightInCL = heightInTile / clHeightInTile;
const UINT_32 clIndex = tileIndex / tileNumPerPipe;
UINT_32 clX = clIndex % pitchInCL;
UINT_32 clY = (clIndex % (heightInCL * pitchInCL)) / pitchInCL;
*pX = clX * clWidthInTile * MicroTileWidth;
*pY = clY * clHeightInTile * MicroTileHeight;
*pSlice = clIndex / (heightInCL * pitchInCL);
macroOffset = tileIndex % tileNumPerPipe;
}
UINT_32 elemIdx = macroOffset & 7;
macroOffset >>= elemIdxBits;
if (elemIdxBits != macroShift)
{
macroOffset <<= (elemIdxBits - macroShift);
UINT_32 pipebit1 = _BIT(pipe,1);
UINT_32 pipebit2 = _BIT(pipe,2);
UINT_32 pipebit3 = _BIT(pipe,3);
if (pitchInMacroTile % 2)
{ //odd
switch (pTileInfo->pipeConfig)
{
case ADDR_PIPECFG_P4_32x32:
macroOffset |= pipebit1;
break;
case ADDR_PIPECFG_P8_32x32_8x16:
case ADDR_PIPECFG_P8_32x32_16x16:
case ADDR_PIPECFG_P8_32x32_16x32:
macroOffset |= pipebit2;
break;
default:
break;
}
}
if (pitchInMacroTile % 4)
{
if (pTileInfo->pipeConfig == ADDR_PIPECFG_P8_32x64_32x32)
{
macroOffset |= (pipebit1<<1);
}
if((pTileInfo->pipeConfig == ADDR_PIPECFG_P16_32x32_8x16) ||
(pTileInfo->pipeConfig == ADDR_PIPECFG_P16_32x32_16x16))
{
macroOffset |= (pipebit3<<1);
}
}
}
UINT_32 macroX;
UINT_32 macroY;
if (isLinear)
{
macroX = macroOffset % pitchInMacroTile;
macroY = macroOffset / pitchInMacroTile;
}
else
{
const UINT_32 clWidthInMacroTile = clWidth / (MicroTileWidth * 4);
macroX = macroOffset % clWidthInMacroTile;
macroY = macroOffset / clWidthInMacroTile;
}
*pX += macroX * 4 * MicroTileWidth;
*pY += macroY * 4 * MicroTileHeight;
UINT_32 microX;
UINT_32 microY;
ComputeTileCoordFromPipeAndElemIdx(elemIdx, pipe, pTileInfo->pipeConfig, pitchInMacroTile,
*pX, *pY, µX, µY);
*pX += microX * MicroTileWidth;
*pY += microY * MicroTileWidth;
}
/**
***************************************************************************************************
* SIAddrLib::HwlGetPitchAlignmentLinear
* @brief
* Get pitch alignment
* @return
* pitch alignment
***************************************************************************************************
*/
UINT_32 SIAddrLib::HwlGetPitchAlignmentLinear(
UINT_32 bpp, ///< [in] bits per pixel
ADDR_SURFACE_FLAGS flags ///< [in] surface flags
) const
{
UINT_32 pitchAlign;
// Interleaved access requires a 256B aligned pitch, so fall back to pre-SI alignment
if (flags.interleaved)
{
pitchAlign = Max(64u, m_pipeInterleaveBytes / BITS_TO_BYTES(bpp));
}
else
{
pitchAlign = Max(8u, 64 / BITS_TO_BYTES(bpp));
}
return pitchAlign;
}
/**
***************************************************************************************************
* SIAddrLib::HwlGetSizeAdjustmentLinear
*
* @brief
* Adjust linear surface pitch and slice size
*
* @return
* Logical slice size in bytes
***************************************************************************************************
*/
UINT_64 SIAddrLib::HwlGetSizeAdjustmentLinear(
AddrTileMode tileMode, ///< [in] tile mode
UINT_32 bpp, ///< [in] bits per pixel
UINT_32 numSamples, ///< [in] number of samples
UINT_32 baseAlign, ///< [in] base alignment
UINT_32 pitchAlign, ///< [in] pitch alignment
UINT_32* pPitch, ///< [in/out] pointer to pitch
UINT_32* pHeight, ///< [in/out] pointer to height
UINT_32* pHeightAlign ///< [in/out] pointer to height align
) const
{
UINT_64 sliceSize;
if (tileMode == ADDR_TM_LINEAR_GENERAL)
{
sliceSize = BITS_TO_BYTES(static_cast<UINT_64>(*pPitch) * (*pHeight) * bpp * numSamples);
}
else
{
UINT_32 pitch = *pPitch;
UINT_32 height = *pHeight;
UINT_32 pixelsPerPipeInterleave = m_pipeInterleaveBytes / BITS_TO_BYTES(bpp);
UINT_32 sliceAlignInPixel = pixelsPerPipeInterleave < 64 ? 64 : pixelsPerPipeInterleave;
// numSamples should be 1 in real cases (no MSAA for linear but TGL may pass non 1 value)
UINT_64 pixelPerSlice = static_cast<UINT_64>(pitch) * height * numSamples;
while (pixelPerSlice % sliceAlignInPixel)
{
pitch += pitchAlign;
pixelPerSlice = static_cast<UINT_64>(pitch) * height * numSamples;
}
*pPitch = pitch;
UINT_32 heightAlign = 1;
while ((pitch * heightAlign) % sliceAlignInPixel)
{
heightAlign++;
}
*pHeightAlign = heightAlign;
sliceSize = BITS_TO_BYTES(pixelPerSlice * bpp);
}
return sliceSize;
}
/**
***************************************************************************************************
* SIAddrLib::HwlPreHandleBaseLvl3xPitch
*
* @brief
* Pre-handler of 3x pitch (96 bit) adjustment
*
* @return
* Expected pitch
***************************************************************************************************
*/
UINT_32 SIAddrLib::HwlPreHandleBaseLvl3xPitch(
const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input
UINT_32 expPitch ///< [in] pitch
) const
{
ADDR_ASSERT(pIn->width == expPitch);
// From SI, if pow2Pad is 1 the pitch is expanded 3x first, then padded to pow2, so nothing to
// do here
if (!pIn->flags.pow2Pad)
{
AddrLib::HwlPreHandleBaseLvl3xPitch(pIn, expPitch);
}
else
{
ADDR_ASSERT(IsPow2(expPitch));
}
return expPitch;
}
/**
***************************************************************************************************
* SIAddrLib::HwlPostHandleBaseLvl3xPitch
*
* @brief
* Post-handler of 3x pitch adjustment
*
* @return
* Expected pitch
***************************************************************************************************
*/
UINT_32 SIAddrLib::HwlPostHandleBaseLvl3xPitch(
const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input
UINT_32 expPitch ///< [in] pitch
) const
{
/**
* @note The pitch will be divided by 3 in the end so the value will look odd but h/w should
* be able to compute a correct pitch from it as h/w address library is doing the job.
*/
// From SI, the pitch is expanded 3x first, then padded to pow2, so no special handler here
if (!pIn->flags.pow2Pad)
{
AddrLib::HwlPostHandleBaseLvl3xPitch(pIn, expPitch);
}
return expPitch;
}
/**
***************************************************************************************************
* SIAddrLib::HwlGetPitchAlignmentMicroTiled
*
* @brief
* Compute 1D tiled surface pitch alignment
*
* @return
* pitch alignment
***************************************************************************************************
*/
UINT_32 SIAddrLib::HwlGetPitchAlignmentMicroTiled(
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
) const
{
UINT_32 pitchAlign;
if (flags.qbStereo)
{
pitchAlign = EgBasedAddrLib::HwlGetPitchAlignmentMicroTiled(tileMode,bpp,flags,numSamples);
}
else
{
pitchAlign = 8;
}
return pitchAlign;
}
/**
***************************************************************************************************
* SIAddrLib::HwlGetSizeAdjustmentMicroTiled
*
* @brief
* Adjust 1D tiled surface pitch and slice size
*
* @return
* Logical slice size in bytes
***************************************************************************************************
*/
UINT_64 SIAddrLib::HwlGetSizeAdjustmentMicroTiled(
UINT_32 thickness, ///< [in] thickness
UINT_32 bpp, ///< [in] bits per pixel
ADDR_SURFACE_FLAGS flags, ///< [in] surface flags
UINT_32 numSamples, ///< [in] number of samples
UINT_32 baseAlign, ///< [in] base alignment
UINT_32 pitchAlign, ///< [in] pitch alignment
UINT_32* pPitch, ///< [in/out] pointer to pitch
UINT_32* pHeight ///< [in/out] pointer to height
) const
{
UINT_64 logicalSliceSize;
UINT_64 physicalSliceSize;
UINT_32 pitch = *pPitch;
UINT_32 height = *pHeight;
// Logical slice: pitch * height * bpp * numSamples (no 1D MSAA so actually numSamples == 1)
logicalSliceSize = BITS_TO_BYTES(static_cast<UINT_64>(pitch) * height * bpp * numSamples);
// Physical slice: multiplied by thickness
physicalSliceSize = logicalSliceSize * thickness;
// Pitch alignment is always 8, so if slice size is not padded to base alignment
// (pipe_interleave_size), we need to increase pitch
while ((physicalSliceSize % baseAlign) != 0)
{
pitch += pitchAlign;
logicalSliceSize = BITS_TO_BYTES(static_cast<UINT_64>(pitch) * height * bpp * numSamples);
physicalSliceSize = logicalSliceSize * thickness;
}
#if !ALT_TEST
//
// Special workaround for depth/stencil buffer, use 8 bpp to align depth buffer again since
// the stencil plane may have larger pitch if the slice size is smaller than base alignment.
//
// Note: this actually does not work for mipmap but mipmap depth texture is not really
// sampled with mipmap.
//
if (flags.depth && !flags.noStencil)
{
ADDR_ASSERT(numSamples == 1);
UINT_64 logicalSiceSizeStencil = static_cast<UINT_64>(pitch) * height; // 1 byte stencil
while ((logicalSiceSizeStencil % baseAlign) != 0)
{
pitch += pitchAlign; // Stencil plane's pitch alignment is the same as depth plane's
logicalSiceSizeStencil = static_cast<UINT_64>(pitch) * height;
}
if (pitch != *pPitch)
{
// If this is a mipmap, this padded one cannot be sampled as a whole mipmap!
logicalSliceSize = logicalSiceSizeStencil * BITS_TO_BYTES(bpp);
}
}
#endif
*pPitch = pitch;
// No adjust for pHeight
return logicalSliceSize;
}
/**
***************************************************************************************************
* SIAddrLib::HwlConvertChipFamily
*
* @brief
* Convert familyID defined in atiid.h to AddrChipFamily and set m_chipFamily/m_chipRevision
* @return
* AddrChipFamily
***************************************************************************************************
*/
AddrChipFamily SIAddrLib::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_SI;
switch (uChipFamily)
{
case FAMILY_SI:
m_settings.isSouthernIsland = 1;
m_settings.isTahiti = ASICREV_IS_TAHITI_P(uChipRevision);
m_settings.isPitCairn = ASICREV_IS_PITCAIRN_PM(uChipRevision);
m_settings.isCapeVerde = ASICREV_IS_CAPEVERDE_M(uChipRevision);
m_settings.isOland = ASICREV_IS_OLAND_M(uChipRevision);
m_settings.isHainan = ASICREV_IS_HAINAN_V(uChipRevision);
break;
default:
ADDR_ASSERT(!"This should be a Fusion");
break;
}
return family;
}
/**
***************************************************************************************************
* SIAddrLib::HwlSetupTileInfo
*
* @brief
* Setup default value of tile info for SI
***************************************************************************************************
*/
VOID SIAddrLib::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;
// Fail-safe code
if (!IsLinear(tileMode))
{
// 128 bpp/thick 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
if (bpp == 128 || thickness > 1 || flags.fmask || flags.prt)
{
inTileType = ADDR_NON_DISPLAYABLE;
}
if (flags.depth || flags.stencil)
{
inTileType = ADDR_DEPTH_SAMPLE_ORDER;
}
}
// Partial valid fields are not allowed for SI.
if (IsTileInfoAllZero(pTileInfo))
{
if (IsMacroTiled(tileMode))
{
if (flags.prt)
{
if (numSamples == 1)
{
if (flags.depth)
{
switch (bpp)
{
case 16:
index = 3;
break;
case 32:
index = 6;
break;
default:
ADDR_ASSERT_ALWAYS();
break;
}
}
else
{
switch (bpp)
{
case 8:
index = 21;
break;
case 16:
index = 22;
break;
case 32:
index = 23;
break;
case 64:
index = 24;
break;
case 128:
index = 25;
break;
default:
break;
}
if (thickness > 1)
{
ADDR_ASSERT(bpp != 128);
index += 5;
}
}
}
else
{
ADDR_ASSERT(numSamples == 4);
if (flags.depth)
{
switch (bpp)
{
case 16:
index = 5;
break;
case 32:
index = 7;
break;
default:
ADDR_ASSERT_ALWAYS();
break;
}
}
else
{
switch (bpp)
{
case 8:
index = 23;
break;
case 16:
index = 24;
break;
case 32:
index = 25;
break;
case 64:
index = 30;
break;
default:
ADDR_ASSERT_ALWAYS();
break;
}
}
}
}//end of PRT part
// See table entries 0-7
else if (flags.depth || flags.stencil)
{
if (flags.compressZ)
{
if (flags.stencil)
{
index = 0;
}
else
{
// optimal tile index for compressed depth/stencil.
switch (numSamples)
{
case 1:
index = 0;
break;
case 2:
case 4:
index = 1;
break;
case 8:
index = 2;
break;
default:
break;
}
}
}
else // unCompressZ
{
index = 3;
}
}
else //non PRT & non Depth & non Stencil
{
// See table entries 9-12
if (inTileType == ADDR_DISPLAYABLE)
{
switch (bpp)
{
case 8:
index = 10;
break;
case 16:
index = 11;
break;
case 32:
index = 12;
break;
case 64:
index = 12;
break;
default:
break;
}
}
else
{
// See table entries 13-17
if (thickness == 1)
{
if (flags.fmask)
{
UINT_32 fmaskPixelSize = bpp * numSamples;
switch (fmaskPixelSize)
{
case 8:
index = 14;
break;
case 16:
index = 15;
break;
case 32:
index = 16;
break;
case 64:
index = 17;
break;
default:
ADDR_ASSERT_ALWAYS();
}
}
else
{
switch (bpp)
{
case 8:
index = 14;
break;
case 16:
index = 15;
break;
case 32:
index = 16;
break;
case 64:
index = 17;
break;
case 128:
index = 17;
break;
default:
break;
}
}
}
else // thick tiling - entries 18-20
{
switch (thickness)
{
case 4:
index = 20;
break;
case 8:
index = 19;
break;
default:
break;
}
}
}
}
}
else
{
if (tileMode == ADDR_TM_LINEAR_ALIGNED)
{
index = 8;
}
else if (tileMode == ADDR_TM_LINEAR_GENERAL)
{
index = TileIndexLinearGeneral;
}
else
{
if (flags.depth || flags.stencil)
{
index = 4;
}
else if (inTileType == ADDR_DISPLAYABLE)
{
index = 9;
}
else if (thickness == 1)
{
index = 13;
}
else
{
index = 18;
}
}
}
if (index >= 0 && index <= 31)
{
*pTileInfo = m_tileTable[index].info;
pOut->tileType = m_tileTable[index].type;
}
if (index == TileIndexLinearGeneral)
{
*pTileInfo = m_tileTable[8].info;
pOut->tileType = m_tileTable[8].type;
}
}
else
{
if (pTileInfoIn)
{
if (flags.stencil && pTileInfoIn->tileSplitBytes == 0)
{
// Stencil always uses index 0
*pTileInfo = m_tileTable[0].info;
}
}
// Pass through tile type
pOut->tileType = inTileType;
}
pOut->tileIndex = index;
}
/**
***************************************************************************************************
* SIAddrLib::DecodeGbRegs
*
* @brief
* Decodes GB_ADDR_CONFIG and noOfBanks/noOfRanks
*
* @return
* TRUE if all settings are valid
*
***************************************************************************************************
*/
BOOL_32 SIAddrLib::DecodeGbRegs(
const ADDR_REGISTER_VALUE* pRegValue) ///< [in] create input
{
GB_ADDR_CONFIG reg;
BOOL_32 valid = TRUE;
reg.val = pRegValue->gbAddrConfig;
switch (reg.f.pipe_interleave_size)
{
case ADDR_CONFIG_PIPE_INTERLEAVE_256B:
m_pipeInterleaveBytes = ADDR_PIPEINTERLEAVE_256B;
break;
case ADDR_CONFIG_PIPE_INTERLEAVE_512B:
m_pipeInterleaveBytes = ADDR_PIPEINTERLEAVE_512B;
break;
default:
valid = FALSE;
ADDR_UNHANDLED_CASE();
break;
}
switch (reg.f.row_size)
{
case ADDR_CONFIG_1KB_ROW:
m_rowSize = ADDR_ROWSIZE_1KB;
break;
case ADDR_CONFIG_2KB_ROW:
m_rowSize = ADDR_ROWSIZE_2KB;
break;
case ADDR_CONFIG_4KB_ROW:
m_rowSize = ADDR_ROWSIZE_4KB;
break;
default:
valid = FALSE;
ADDR_UNHANDLED_CASE();
break;
}
switch (pRegValue->noOfBanks)
{
case 0:
m_banks = 4;
break;
case 1:
m_banks = 8;
break;
case 2:
m_banks = 16;
break;
default:
valid = FALSE;
ADDR_UNHANDLED_CASE();
break;
}
switch (pRegValue->noOfRanks)
{
case 0:
m_ranks = 1;
break;
case 1:
m_ranks = 2;
break;
default:
valid = FALSE;
ADDR_UNHANDLED_CASE();
break;
}
m_logicalBanks = m_banks * m_ranks;
ADDR_ASSERT(m_logicalBanks <= 16);
return valid;
}
/**
***************************************************************************************************
* SIAddrLib::HwlInitGlobalParams
*
* @brief
* Initializes global parameters
*
* @return
* TRUE if all settings are valid
*
***************************************************************************************************
*/
BOOL_32 SIAddrLib::HwlInitGlobalParams(
const ADDR_CREATE_INPUT* pCreateIn) ///< [in] create input
{
BOOL_32 valid = TRUE;
const ADDR_REGISTER_VALUE* pRegValue = &pCreateIn->regValue;
valid = DecodeGbRegs(pRegValue);
if (valid)
{
if (m_settings.isTahiti || m_settings.isPitCairn)
{
m_pipes = 8;
}
else if (m_settings.isCapeVerde || m_settings.isOland)
{
m_pipes = 4;
}
else
{
// Hainan is 2-pipe (m_settings.isHainan == 1)
m_pipes = 2;
}
valid = InitTileSettingTable(pRegValue->pTileConfig, pRegValue->noOfEntries);
m_maxSamples = 16;
}
return valid;
}
/**
***************************************************************************************************
* SIAddrLib::HwlConvertTileInfoToHW
* @brief
* Entry of si's ConvertTileInfoToHW
* @return
* ADDR_E_RETURNCODE
***************************************************************************************************
*/
ADDR_E_RETURNCODE SIAddrLib::HwlConvertTileInfoToHW(
const ADDR_CONVERT_TILEINFOTOHW_INPUT* pIn, ///< [in] input structure
ADDR_CONVERT_TILEINFOTOHW_OUTPUT* pOut ///< [out] output structure
) const
{
ADDR_E_RETURNCODE retCode = ADDR_OK;
retCode = EgBasedAddrLib::HwlConvertTileInfoToHW(pIn, pOut);
if (retCode == ADDR_OK)
{
if (pIn->reverse == FALSE)
{
if (pIn->pTileInfo->pipeConfig == ADDR_PIPECFG_INVALID)
{
retCode = ADDR_INVALIDPARAMS;
}
else
{
pOut->pTileInfo->pipeConfig =
static_cast<AddrPipeCfg>(pIn->pTileInfo->pipeConfig - 1);
}
}
else
{
pOut->pTileInfo->pipeConfig =
static_cast<AddrPipeCfg>(pIn->pTileInfo->pipeConfig + 1);
}
}
return retCode;
}
/**
***************************************************************************************************
* SIAddrLib::HwlComputeXmaskCoordYFrom8Pipe
*
* @brief
* Compute the Y coord which will be added to Xmask Y
* coord.
* @return
* Y coord
***************************************************************************************************
*/
UINT_32 SIAddrLib::HwlComputeXmaskCoordYFrom8Pipe(
UINT_32 pipe, ///< [in] pipe id
UINT_32 x ///< [in] tile coord x, which is original x coord / 8
) const
{
// This function should never be called since it is 6xx/8xx specfic.
// Keep this empty implementation to avoid any mis-use.
ADDR_ASSERT_ALWAYS();
return 0;
}
/**
***************************************************************************************************
* SIAddrLib::HwlComputeSurfaceCoord2DFromBankPipe
*
* @brief
* Compute surface x,y coordinates from bank/pipe info
* @return
* N/A
***************************************************************************************************
*/
VOID SIAddrLib::HwlComputeSurfaceCoord2DFromBankPipe(
AddrTileMode tileMode, ///< [in] tile mode
UINT_32* pX, ///< [in/out] x coordinate
UINT_32* pY, ///< [in/out] y coordinate
UINT_32 slice, ///< [in] slice index
UINT_32 bank, ///< [in] bank number
UINT_32 pipe, ///< [in] pipe number
UINT_32 bankSwizzle,///< [in] bank swizzle
UINT_32 pipeSwizzle,///< [in] pipe swizzle
UINT_32 tileSlices, ///< [in] slices in a micro tile
BOOL_32 ignoreSE, ///< [in] TRUE if shader engines are ignored
ADDR_TILEINFO* pTileInfo ///< [in] bank structure. **All fields to be valid on entry**
) const
{
UINT_32 xBit;
UINT_32 yBit;
UINT_32 yBit3 = 0;
UINT_32 yBit4 = 0;
UINT_32 yBit5 = 0;
UINT_32 yBit6 = 0;
UINT_32 xBit3 = 0;
UINT_32 xBit4 = 0;
UINT_32 xBit5 = 0;
UINT_32 numPipes = GetPipePerSurf(pTileInfo->pipeConfig);
CoordFromBankPipe xyBits = {0};
ComputeSurfaceCoord2DFromBankPipe(tileMode, *pX, *pY, slice, bank, pipe,
bankSwizzle, pipeSwizzle, tileSlices, pTileInfo,
&xyBits);
yBit3 = xyBits.yBit3;
yBit4 = xyBits.yBit4;
yBit5 = xyBits.yBit5;
yBit6 = xyBits.yBit6;
xBit3 = xyBits.xBit3;
xBit4 = xyBits.xBit4;
xBit5 = xyBits.xBit5;
yBit = xyBits.yBits;
UINT_32 yBitTemp = 0;
if ((pTileInfo->pipeConfig == ADDR_PIPECFG_P4_32x32) ||
(pTileInfo->pipeConfig == ADDR_PIPECFG_P8_32x64_32x32))
{
ADDR_ASSERT(pTileInfo->bankWidth == 1 && pTileInfo->macroAspectRatio > 1);
UINT_32 yBitToCheck = QLog2(pTileInfo->banks) - 1;
ADDR_ASSERT(yBitToCheck <= 3);
yBitTemp = _BIT(yBit, yBitToCheck);
xBit3 = 0;
}
yBit = Bits2Number(4, yBit6, yBit5, yBit4, yBit3);
xBit = Bits2Number(3, xBit5, xBit4, xBit3);
*pY += yBit * pTileInfo->bankHeight * MicroTileHeight;
*pX += xBit * numPipes * pTileInfo->bankWidth * MicroTileWidth;
//calculate the bank and pipe bits in x, y
UINT_32 xTile; //x in micro tile
UINT_32 x3 = 0;
UINT_32 x4 = 0;
UINT_32 x5 = 0;
UINT_32 x6 = 0;
UINT_32 y = *pY;
UINT_32 pipeBit0 = _BIT(pipe,0);
UINT_32 pipeBit1 = _BIT(pipe,1);
UINT_32 pipeBit2 = _BIT(pipe,2);
UINT_32 y3 = _BIT(y, 3);
UINT_32 y4 = _BIT(y, 4);
UINT_32 y5 = _BIT(y, 5);
UINT_32 y6 = _BIT(y, 6);
// bankbit0 after ^x4^x5
UINT_32 bankBit00 = _BIT(bank,0);
UINT_32 bankBit0 = 0;
switch (pTileInfo->pipeConfig)
{
case ADDR_PIPECFG_P2:
x3 = pipeBit0 ^ y3;
break;
case ADDR_PIPECFG_P4_8x16:
x4 = pipeBit0 ^ y3;
x3 = pipeBit0 ^ y4;
break;
case ADDR_PIPECFG_P4_16x16:
x4 = pipeBit1 ^ y4;
x3 = pipeBit0 ^ y3 ^ x4;
break;
case ADDR_PIPECFG_P4_16x32:
x4 = pipeBit1 ^ y4;
x3 = pipeBit0 ^ y3 ^ x4;
break;
case ADDR_PIPECFG_P4_32x32:
x5 = pipeBit1 ^ y5;
x3 = pipeBit0 ^ y3 ^ x5;
bankBit0 = yBitTemp ^ x5;
x4 = bankBit00 ^ x5 ^ bankBit0;
*pX += x5 * 4 * 1 * 8; // x5 * num_pipes * bank_width * 8;
break;
case ADDR_PIPECFG_P8_16x16_8x16:
x3 = pipeBit1 ^ y5;
x4 = pipeBit2 ^ y4;
x5 = pipeBit0 ^ y3 ^ x4;
break;
case ADDR_PIPECFG_P8_16x32_8x16:
x3 = pipeBit1 ^ y4;
x4 = pipeBit2 ^ y5;
x5 = pipeBit0 ^ y3 ^ x4;
break;
case ADDR_PIPECFG_P8_32x32_8x16:
x3 = pipeBit1 ^ y4;
x5 = pipeBit2 ^ y5;
x4 = pipeBit0 ^ y3 ^ x5;
break;
case ADDR_PIPECFG_P8_16x32_16x16:
x4 = pipeBit2 ^ y5;
x5 = pipeBit1 ^ y4;
x3 = pipeBit0 ^ y3 ^ x4;
break;
case ADDR_PIPECFG_P8_32x32_16x16:
x5 = pipeBit2 ^ y5;
x4 = pipeBit1 ^ y4;
x3 = pipeBit0 ^ y3 ^ x4;
break;
case ADDR_PIPECFG_P8_32x32_16x32:
x5 = pipeBit2 ^ y5;
x4 = pipeBit1 ^ y6;
x3 = pipeBit0 ^ y3 ^ x4;
break;
case ADDR_PIPECFG_P8_32x64_32x32:
x6 = pipeBit1 ^ y5;
x5 = pipeBit2 ^ y6;
x3 = pipeBit0 ^ y3 ^ x5;
bankBit0 = yBitTemp ^ x6;
x4 = bankBit00 ^ x5 ^ bankBit0;
*pX += x6 * 8 * 1 * 8; // x6 * num_pipes * bank_width * 8;
break;
default:
ADDR_ASSERT_ALWAYS();
}
xTile = Bits2Number(3, x5, x4, x3);
*pX += xTile << 3;
}
/**
***************************************************************************************************
* SIAddrLib::HwlPreAdjustBank
*
* @brief
* Adjust bank before calculating address acoording to bank/pipe
* @return
* Adjusted bank
***************************************************************************************************
*/
UINT_32 SIAddrLib::HwlPreAdjustBank(
UINT_32 tileX, ///< [in] x coordinate in unit of tile
UINT_32 bank, ///< [in] bank
ADDR_TILEINFO* pTileInfo ///< [in] tile info
) const
{
if (((pTileInfo->pipeConfig == ADDR_PIPECFG_P4_32x32) ||
(pTileInfo->pipeConfig == ADDR_PIPECFG_P8_32x64_32x32)) && (pTileInfo->bankWidth == 1))
{
UINT_32 bankBit0 = _BIT(bank, 0);
UINT_32 x4 = _BIT(tileX, 1);
UINT_32 x5 = _BIT(tileX, 2);
bankBit0 = bankBit0 ^ x4 ^ x5;
bank |= bankBit0;
ADDR_ASSERT(pTileInfo->macroAspectRatio > 1)
}
return bank;
}
/**
***************************************************************************************************
* SIAddrLib::HwlComputeSurfaceInfo
*
* @brief
* Entry of si's ComputeSurfaceInfo
* @return
* ADDR_E_RETURNCODE
***************************************************************************************************
*/
ADDR_E_RETURNCODE SIAddrLib::HwlComputeSurfaceInfo(
const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure
ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure
) const
{
pOut->tileIndex = pIn->tileIndex;
return EgBasedAddrLib::HwlComputeSurfaceInfo(pIn,pOut);
}
/**
***************************************************************************************************
* SIAddrLib::HwlComputeMipLevel
* @brief
* Compute MipLevel info (including level 0)
* @return
* TRUE if HWL's handled
***************************************************************************************************
*/
BOOL_32 SIAddrLib::HwlComputeMipLevel(
ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn ///< [in/out] Input structure
) const
{
// basePitch is calculated from level 0 so we only check this for mipLevel > 0
if (pIn->mipLevel > 0)
{
// Note: Don't check expand 3x formats(96 bit) as the basePitch is not pow2 even if
// we explicity set pow2Pad flag. The 3x base pitch is padded to pow2 but after being
// divided by expandX factor (3) - to program texture pitch, the basePitch is never pow2.
if (!AddrElemLib::IsExpand3x(pIn->format))
{
// Sublevel pitches are generated from base level pitch instead of width on SI
// If pow2Pad is 0, we don't assert - as this is not really used for a mip chain
ADDR_ASSERT(!pIn->flags.pow2Pad || ((pIn->basePitch != 0) && IsPow2(pIn->basePitch)));
}
if (pIn->basePitch != 0)
{
pIn->width = Max(1u, pIn->basePitch >> pIn->mipLevel);
}
}
// pow2Pad is done in PostComputeMipLevel
return TRUE;
}
/**
***************************************************************************************************
* SIAddrLib::HwlCheckLastMacroTiledLvl
*
* @brief
* Sets pOut->last2DLevel to TRUE if it is
* @note
*
***************************************************************************************************
*/
VOID SIAddrLib::HwlCheckLastMacroTiledLvl(
const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] Input structure
ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [in/out] Output structure (used as input, too)
) const
{
// pow2Pad covers all mipmap cases
if (pIn->flags.pow2Pad)
{
ADDR_ASSERT(IsMacroTiled(pIn->tileMode));
UINT_32 nextPitch;
UINT_32 nextHeight;
UINT_32 nextSlices;
AddrTileMode nextTileMode;
if (pIn->mipLevel == 0 || pIn->basePitch == 0)
{
// Base level or fail-safe case (basePitch == 0)
nextPitch = pOut->pitch >> 1;
}
else
{
// Sub levels
nextPitch = pIn->basePitch >> (pIn->mipLevel + 1);
}
// nextHeight must be shifted from this level's original height rather than a pow2 padded
// one but this requires original height stored somewhere (pOut->height)
ADDR_ASSERT(pOut->height != 0);
// next level's height is just current level's >> 1 in pixels
nextHeight = pOut->height >> 1;
// Special format such as FMT_1 and FMT_32_32_32 can be linear only so we consider block
// compressed foramts
if (AddrElemLib::IsBlockCompressed(pIn->format))
{
nextHeight = (nextHeight + 3) / 4;
}
nextHeight = NextPow2(nextHeight);
// nextSlices may be 0 if this level's is 1
if (pIn->flags.volume)
{
nextSlices = Max(1u, pIn->numSlices >> 1);
}
else
{
nextSlices = pIn->numSlices;
}
nextTileMode = ComputeSurfaceMipLevelTileMode(pIn->tileMode,
pIn->bpp,
nextPitch,
nextHeight,
nextSlices,
pIn->numSamples,
pOut->pitchAlign,
pOut->heightAlign,
pOut->pTileInfo);
pOut->last2DLevel = IsMicroTiled(nextTileMode);
}
}
/**
***************************************************************************************************
* SIAddrLib::HwlDegradeThickTileMode
*
* @brief
* Degrades valid tile mode for thick modes if needed
*
* @return
* Suitable tile mode
***************************************************************************************************
*/
AddrTileMode SIAddrLib::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 EgBasedAddrLib::HwlDegradeThickTileMode(baseTileMode, numSlices, pBytesPerTile);
}
/**
***************************************************************************************************
* SIAddrLib::HwlTileInfoEqual
*
* @brief
* Return TRUE if all field are equal
* @note
* Only takes care of current HWL's data
***************************************************************************************************
*/
BOOL_32 SIAddrLib::HwlTileInfoEqual(
const ADDR_TILEINFO* pLeft, ///<[in] Left compare operand
const ADDR_TILEINFO* pRight ///<[in] Right compare operand
) const
{
BOOL_32 equal = FALSE;
if (pLeft->pipeConfig == pRight->pipeConfig)
{
equal = EgBasedAddrLib::HwlTileInfoEqual(pLeft, pRight);
}
return equal;
}
/**
***************************************************************************************************
* SIAddrLib::GetTileSettings
*
* @brief
* Get tile setting infos by index.
* @return
* Tile setting info.
***************************************************************************************************
*/
const ADDR_TILECONFIG* SIAddrLib::GetTileSetting(
UINT_32 index ///< [in] Tile index
) const
{
ADDR_ASSERT(index < m_noOfEntries);
return &m_tileTable[index];
}
/**
***************************************************************************************************
* SIAddrLib::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 SIAddrLib::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 && !HwlTileInfoEqual(pInfo, &m_tileTable[index].info))))
{
for (index = 0; index < static_cast<INT_32>(m_noOfEntries); index++)
{
if (macroTiled)
{
// macro tile modes need all to match
if (HwlTileInfoEqual(pInfo, &m_tileTable[index].info) &&
(mode == m_tileTable[index].mode) &&
(type == m_tileTable[index].type))
{
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;
}
/**
***************************************************************************************************
* SIAddrLib::HwlSetupTileCfg
*
* @brief
* Map tile index to tile setting.
* @return
* ADDR_E_RETURNCODE
***************************************************************************************************
*/
ADDR_E_RETURNCODE SIAddrLib::HwlSetupTileCfg(
INT_32 index, ///< [in] Tile index
INT_32 macroModeIndex, ///< [in] Index in macro tile mode table(CI)
ADDR_TILEINFO* pInfo, ///< [out] Tile Info
AddrTileMode* pMode, ///< [out] Tile mode
AddrTileType* pType ///< [out] Tile type
) const
{
ADDR_E_RETURNCODE returnCode = ADDR_OK;
// Global flag to control usage of tileIndex
if (UseTileIndex(index))
{
if (index == TileIndexLinearGeneral)
{
if (pMode)
{
*pMode = ADDR_TM_LINEAR_GENERAL;
}
if (pType)
{
*pType = ADDR_DISPLAYABLE;
}
if (pInfo)
{
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 ADDR_TILECONFIG* pCfgTable = GetTileSetting(index);
if (pInfo)
{
*pInfo = pCfgTable->info;
}
else
{
if (IsMacroTiled(pCfgTable->mode))
{
returnCode = ADDR_INVALIDPARAMS;
}
}
if (pMode)
{
*pMode = pCfgTable->mode;
}
if (pType)
{
*pType = pCfgTable->type;
}
}
}
return returnCode;
}
/**
***************************************************************************************************
* SIAddrLib::ReadGbTileMode
*
* @brief
* Convert GB_TILE_MODE HW value to ADDR_TILE_CONFIG.
* @return
* NA.
***************************************************************************************************
*/
VOID SIAddrLib::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);
pCfg->info.bankHeight = 1 << gbTileMode.f.bank_height;
pCfg->info.bankWidth = 1 << gbTileMode.f.bank_width;
pCfg->info.banks = 1 << (gbTileMode.f.num_banks + 1);
pCfg->info.macroAspectRatio = 1 << gbTileMode.f.macro_tile_aspect;
pCfg->info.tileSplitBytes = 64 << gbTileMode.f.tile_split;
pCfg->info.pipeConfig = static_cast<AddrPipeCfg>(gbTileMode.f.pipe_config + 1);
UINT_32 regArrayMode = gbTileMode.f.array_mode;
pCfg->mode = static_cast<AddrTileMode>(regArrayMode);
if (regArrayMode == 8) //ARRAY_2D_TILED_XTHICK
{
pCfg->mode = ADDR_TM_2D_TILED_XTHICK;
}
else if (regArrayMode >= 14) //ARRAY_3D_TILED_XTHICK
{
pCfg->mode = static_cast<AddrTileMode>(pCfg->mode + 3);
}
}
/**
***************************************************************************************************
* SIAddrLib::InitTileSettingTable
*
* @brief
* Initialize the ADDR_TILE_CONFIG table.
* @return
* TRUE if tile table is correctly initialized
***************************************************************************************************
*/
BOOL_32 SIAddrLib::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);
}
return initOk;
}
/**
***************************************************************************************************
* SIAddrLib::HwlGetTileIndex
*
* @brief
* Return the virtual/real index for given mode/type/info
* @return
* ADDR_OK if successful.
***************************************************************************************************
*/
ADDR_E_RETURNCODE SIAddrLib::HwlGetTileIndex(
const ADDR_GET_TILEINDEX_INPUT* pIn,
ADDR_GET_TILEINDEX_OUTPUT* pOut) const
{
ADDR_E_RETURNCODE returnCode = ADDR_OK;
pOut->index = HwlPostCheckTileIndex(pIn->pTileInfo, pIn->tileMode, pIn->tileType);
return returnCode;
}
/**
***************************************************************************************************
* SIAddrLib::HwlFmaskPreThunkSurfInfo
*
* @brief
* Some preparation before thunking a ComputeSurfaceInfo call for Fmask
* @return
* ADDR_E_RETURNCODE
***************************************************************************************************
*/
VOID SIAddrLib::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;
}
/**
***************************************************************************************************
* SIAddrLib::HwlFmaskPostThunkSurfInfo
*
* @brief
* Copy hwl extra field after calling thunked ComputeSurfaceInfo
* @return
* ADDR_E_RETURNCODE
***************************************************************************************************
*/
VOID SIAddrLib::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->macroModeIndex = TileIndexInvalid;
pFmaskOut->tileIndex = pSurfOut->tileIndex;
}
/**
***************************************************************************************************
* SIAddrLib::HwlComputeFmaskBits
* @brief
* Computes fmask bits
* @return
* Fmask bits
***************************************************************************************************
*/
UINT_32 SIAddrLib::HwlComputeFmaskBits(
const ADDR_COMPUTE_FMASK_INFO_INPUT* pIn,
UINT_32* pNumSamples
) const
{
UINT_32 numSamples = pIn->numSamples;
UINT_32 numFrags = GetNumFragments(numSamples, pIn->numFrags);
UINT_32 bpp;
if (numFrags != numSamples) // EQAA
{
ADDR_ASSERT(numFrags <= 8);
if (!pIn->resolved)
{
if (numFrags == 1)
{
bpp = 1;
numSamples = numSamples == 16 ? 16 : 8;
}
else if (numFrags == 2)
{
ADDR_ASSERT(numSamples >= 4);
bpp = 2;
numSamples = numSamples;
}
else if (numFrags == 4)
{
ADDR_ASSERT(numSamples >= 4);
bpp = 4;
numSamples = numSamples;
}
else // numFrags == 8
{
ADDR_ASSERT(numSamples == 16);
bpp = 4;
numSamples = numSamples;
}
}
else
{
if (numFrags == 1)
{
bpp = (numSamples == 16) ? 16 : 8;
numSamples = 1;
}
else if (numFrags == 2)
{
ADDR_ASSERT(numSamples >= 4);
bpp = numSamples*2;
numSamples = 1;
}
else if (numFrags == 4)
{
ADDR_ASSERT(numSamples >= 4);
bpp = numSamples*4;
numSamples = 1;
}
else // numFrags == 8
{
ADDR_ASSERT(numSamples >= 16);
bpp = 16*4;
numSamples = 1;
}
}
}
else // Normal AA
{
if (!pIn->resolved)
{
bpp = ComputeFmaskNumPlanesFromNumSamples(numSamples);
numSamples = numSamples == 2 ? 8 : numSamples;
}
else
{
// The same as 8XX
bpp = ComputeFmaskResolvedBppFromNumSamples(numSamples);
numSamples = 1; // 1x sample
}
}
SafeAssign(pNumSamples, numSamples);
return bpp;
}
/**
***************************************************************************************************
* SIAddrLib::HwlOverrideTileMode
*
* @brief
* Override tile modes (for PRT only, avoid client passes in an invalid PRT mode for SI.
*
* @return
* Suitable tile mode
*
***************************************************************************************************
*/
BOOL_32 SIAddrLib::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;
switch (tileMode)
{
case ADDR_TM_PRT_TILED_THIN1:
tileMode = ADDR_TM_2D_TILED_THIN1;
break;
case ADDR_TM_PRT_TILED_THICK:
tileMode = ADDR_TM_2D_TILED_THICK;
break;
case ADDR_TM_PRT_2D_TILED_THICK:
tileMode = ADDR_TM_2D_TILED_THICK;
break;
case ADDR_TM_PRT_3D_TILED_THICK:
tileMode = ADDR_TM_3D_TILED_THICK;
break;
default:
break;
}
if (tileMode != *pTileMode)
{
*pTileMode = tileMode;
bOverrided = TRUE;
ADDR_ASSERT(pIn->flags.prt == TRUE);
}
return bOverrided;
}