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