/* * Copyright © 2017 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 addrlib2.cpp * @brief Contains the implementation for the AddrLib2 base class. **************************************************************************************************** */ #include "addrinterface.h" #include "addrlib2.h" #include "addrcommon.h" namespace Addr { namespace V2 { //////////////////////////////////////////////////////////////////////////////////////////////////// // Static Const Member //////////////////////////////////////////////////////////////////////////////////////////////////// const SwizzleModeFlags Lib::SwizzleModeTable[ADDR_SW_MAX_TYPE] = {//Linear 256B 4KB 64KB Var Z Std Disp Rot XOR T {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//ADDR_SW_LINEAR {0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0},//ADDR_SW_256B_S {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0},//ADDR_SW_256B_D {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0},//ADDR_SW_256B_R {0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0},//ADDR_SW_4KB_Z {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},//ADDR_SW_4KB_S {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0},//ADDR_SW_4KB_D {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0},//ADDR_SW_4KB_R {0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0},//ADDR_SW_64KB_Z {0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0},//ADDR_SW_64KB_S {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},//ADDR_SW_64KB_D {0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0},//ADDR_SW_64KB_R {0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0},//ADDR_SW_VAR_Z {0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0},//ADDR_SW_VAR_S {0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0},//ADDR_SW_VAR_D {0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0},//ADDR_SW_VAR_R {0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1},//ADDR_SW_64KB_Z_T {0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1},//ADDR_SW_64KB_S_T {0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1},//ADDR_SW_64KB_D_T {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1},//ADDR_SW_64KB_R_T {0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0},//ADDR_SW_4KB_Z_x {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0},//ADDR_SW_4KB_S_x {0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0},//ADDR_SW_4KB_D_x {0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0},//ADDR_SW_4KB_R_x {0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0},//ADDR_SW_64KB_Z_X {0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0},//ADDR_SW_64KB_S_X {0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0},//ADDR_SW_64KB_D_X {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0},//ADDR_SW_64KB_R_X {0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0},//ADDR_SW_VAR_Z_X {0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0},//ADDR_SW_VAR_S_X {0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0},//ADDR_SW_VAR_D_X {0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0},//ADDR_SW_VAR_R_X {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//ADDR_SW_LINEAR_GENERAL }; const Dim2d Lib::Block256b[] = {{16, 16}, {16, 8}, {8, 8}, {8, 4}, {4, 4}}; const Dim3d Lib::Block1kb[] = {{16, 8, 8}, {8, 8, 8}, {8, 8, 4}, {8, 4, 4}, {4, 4, 4}}; const Dim2d Lib::CompressBlock2d[] = {{16, 16}, {16, 8}, {8, 8}, {8, 4}, {4, 4}}; const Dim3d Lib::CompressBlock3dS[] = {{16, 4, 4}, {8, 4, 4}, {4, 4, 4}, {2, 4, 4}, {1, 4, 4}}; const Dim3d Lib::CompressBlock3dZ[] = {{8, 4, 8}, {4, 4, 8}, {4, 4, 4}, {4, 2, 4}, {2, 2, 4}}; const UINT_32 Lib::MaxMacroBits = 20; const UINT_32 Lib::MipTailOffset[] = {2048, 1024, 512, 256, 128, 64, 32, 16, 8, 6, 5, 4, 3, 2, 1, 0}; //////////////////////////////////////////////////////////////////////////////////////////////////// // Constructor/Destructor //////////////////////////////////////////////////////////////////////////////////////////////////// /** **************************************************************************************************** * Lib::Lib * * @brief * Constructor for the Addr::V2::Lib class * **************************************************************************************************** */ Lib::Lib() : Addr::Lib() { } /** **************************************************************************************************** * Lib::Lib * * @brief * Constructor for the AddrLib2 class with hClient as parameter * **************************************************************************************************** */ Lib::Lib(const Client* pClient) : Addr::Lib(pClient) { } /** **************************************************************************************************** * Lib::~Lib * * @brief * Destructor for the AddrLib2 class * **************************************************************************************************** */ Lib::~Lib() { } /** **************************************************************************************************** * Lib::GetLib * * @brief * Get Addr::V2::Lib pointer * * @return * An Addr::V2::Lib class pointer **************************************************************************************************** */ Lib* Lib::GetLib( ADDR_HANDLE hLib) ///< [in] handle of ADDR_HANDLE { Addr::Lib* pAddrLib = Addr::Lib::GetLib(hLib); if ((pAddrLib != NULL) && (pAddrLib->GetChipFamily() <= ADDR_CHIP_FAMILY_VI)) { // only valid and GFX9+ AISC can use AddrLib2 function. ADDR_ASSERT_ALWAYS(); hLib = NULL; } return static_cast(hLib); } //////////////////////////////////////////////////////////////////////////////////////////////////// // Surface Methods //////////////////////////////////////////////////////////////////////////////////////////////////// /** **************************************************************************************************** * Lib::ComputeSurfaceInfo * * @brief * Interface function stub of AddrComputeSurfaceInfo. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceInfo( const ADDR2_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_OK; if (GetFillSizeFieldsFlags() == TRUE) { if ((pIn->size != sizeof(ADDR2_COMPUTE_SURFACE_INFO_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_SURFACE_INFO_OUTPUT))) { returnCode = ADDR_PARAMSIZEMISMATCH; } } // Adjust coming parameters. ADDR2_COMPUTE_SURFACE_INFO_INPUT localIn = *pIn; localIn.width = Max(pIn->width, 1u); localIn.height = Max(pIn->height, 1u); localIn.numMipLevels = Max(pIn->numMipLevels, 1u); localIn.numSlices = Max(pIn->numSlices, 1u); localIn.numSamples = Max(pIn->numSamples, 1u); localIn.numFrags = (localIn.numFrags == 0) ? localIn.numSamples : pIn->numFrags; UINT_32 expandX = 1; UINT_32 expandY = 1; ElemMode elemMode = ADDR_UNCOMPRESSED; if (returnCode == ADDR_OK) { // Set format to INVALID will skip this conversion if (localIn.format != ADDR_FMT_INVALID) { // Get compression/expansion factors and element mode which indicates compression/expansion localIn.bpp = GetElemLib()->GetBitsPerPixel(localIn.format, &elemMode, &expandX, &expandY); // Special flag for 96 bit surface. 96 (or 48 if we support) bit surface's width is // pre-multiplied by 3 and bpp is divided by 3. So pitch alignment for linear- // aligned does not meet 64-pixel in real. We keep special handling in hwl since hw // restrictions are different. // Also Mip 1+ needs an element pitch of 32 bits so we do not need this workaround // but we use this flag to skip RestoreSurfaceInfo below if ((elemMode == ADDR_EXPANDED) && (expandX > 1)) { ADDR_ASSERT((localIn.swizzleMode == ADDR_SW_LINEAR) || (localIn.height == 1)); } UINT_32 basePitch = 0; GetElemLib()->AdjustSurfaceInfo(elemMode, expandX, expandY, &localIn.bpp, &basePitch, &localIn.width, &localIn.height); // Overwrite these parameters if we have a valid format } if (localIn.bpp != 0) { localIn.width = Max(localIn.width, 1u); localIn.height = Max(localIn.height, 1u); } else // Rule out some invalid parameters { ADDR_ASSERT_ALWAYS(); returnCode = ADDR_INVALIDPARAMS; } } if (returnCode == ADDR_OK) { returnCode = ComputeSurfaceInfoSanityCheck(&localIn); } if (returnCode == ADDR_OK) { VerifyMipLevelInfo(pIn); if (IsLinear(pIn->swizzleMode)) { // linear mode returnCode = ComputeSurfaceInfoLinear(&localIn, pOut); } else { // tiled mode returnCode = ComputeSurfaceInfoTiled(&localIn, pOut); } if (returnCode == ADDR_OK) { pOut->bpp = localIn.bpp; pOut->pixelPitch = pOut->pitch; pOut->pixelHeight = pOut->height; pOut->pixelMipChainPitch = pOut->mipChainPitch; pOut->pixelMipChainHeight = pOut->mipChainHeight; pOut->pixelBits = localIn.bpp; if (localIn.format != ADDR_FMT_INVALID) { UINT_32 pixelBits = pOut->pixelBits; GetElemLib()->RestoreSurfaceInfo(elemMode, expandX, expandY, &pOut->pixelBits, &pOut->pixelPitch, &pOut->pixelHeight); GetElemLib()->RestoreSurfaceInfo(elemMode, expandX, expandY, &pixelBits, &pOut->pixelMipChainPitch, &pOut->pixelMipChainHeight); } if (localIn.flags.needEquation && (Log2(localIn.numFrags) == 0)) { pOut->equationIndex = GetEquationIndex(&localIn, pOut); } } } return returnCode; } /** **************************************************************************************************** * Lib::ComputeSurfaceInfo * * @brief * Interface function stub of AddrComputeSurfaceInfo. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceAddrFromCoord( const ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_OK; if (GetFillSizeFieldsFlags() == TRUE) { if ((pIn->size != sizeof(ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT))) { returnCode = ADDR_PARAMSIZEMISMATCH; } } ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT localIn = *pIn; localIn.unalignedWidth = Max(pIn->unalignedWidth, 1u); localIn.unalignedHeight = Max(pIn->unalignedHeight, 1u); localIn.numMipLevels = Max(pIn->numMipLevels, 1u); localIn.numSlices = Max(pIn->numSlices, 1u); localIn.numSamples = Max(pIn->numSamples, 1u); localIn.numFrags = Max(pIn->numFrags, 1u); if ((localIn.bpp < 8) || (localIn.bpp > 128) || ((localIn.bpp % 8) != 0) || (localIn.sample >= localIn.numSamples) || (localIn.slice >= localIn.numSlices) || (localIn.mipId >= localIn.numMipLevels) || (IsTex3d(localIn.resourceType) && (Valid3DMipSliceIdConstraint(localIn.numSlices, localIn.mipId, localIn.slice) == FALSE))) { returnCode = ADDR_INVALIDPARAMS; } if (returnCode == ADDR_OK) { if (IsLinear(localIn.swizzleMode)) { returnCode = ComputeSurfaceAddrFromCoordLinear(&localIn, pOut); } else { returnCode = ComputeSurfaceAddrFromCoordTiled(&localIn, pOut); } } return returnCode; } /** **************************************************************************************************** * Lib::ComputeSurfaceCoordFromAddr * * @brief * Interface function stub of ComputeSurfaceCoordFromAddr. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceCoordFromAddr( const ADDR2_COMPUTE_SURFACE_COORDFROMADDR_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_SURFACE_COORDFROMADDR_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_OK; if (GetFillSizeFieldsFlags() == TRUE) { if ((pIn->size != sizeof(ADDR2_COMPUTE_SURFACE_COORDFROMADDR_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_SURFACE_COORDFROMADDR_OUTPUT))) { returnCode = ADDR_PARAMSIZEMISMATCH; } } if ((pIn->bpp < 8) || (pIn->bpp > 128) || ((pIn->bpp % 8) != 0) || (pIn->bitPosition >= 8)) { returnCode = ADDR_INVALIDPARAMS; } if (returnCode == ADDR_OK) { if (IsLinear(pIn->swizzleMode)) { returnCode = ComputeSurfaceCoordFromAddrLinear(pIn, pOut); } else { returnCode = ComputeSurfaceCoordFromAddrTiled(pIn, pOut); } } return returnCode; } //////////////////////////////////////////////////////////////////////////////////////////////////// // CMASK/HTILE //////////////////////////////////////////////////////////////////////////////////////////////////// /** **************************************************************************************************** * Lib::ComputeHtileInfo * * @brief * Interface function stub of AddrComputeHtilenfo * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeHtileInfo( const ADDR2_COMPUTE_HTILE_INFO_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_HTILE_INFO_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode; if ((GetFillSizeFieldsFlags() == TRUE) && ((pIn->size != sizeof(ADDR2_COMPUTE_HTILE_INFO_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_HTILE_INFO_OUTPUT)))) { returnCode = ADDR_INVALIDPARAMS; } else { returnCode = HwlComputeHtileInfo(pIn, pOut); } return returnCode; } /** **************************************************************************************************** * Lib::ComputeHtileAddrFromCoord * * @brief * Interface function stub of AddrComputeHtileAddrFromCoord * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeHtileAddrFromCoord( const ADDR2_COMPUTE_HTILE_ADDRFROMCOORD_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_HTILE_ADDRFROMCOORD_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode; if ((GetFillSizeFieldsFlags() == TRUE) && ((pIn->size != sizeof(ADDR2_COMPUTE_HTILE_ADDRFROMCOORD_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_HTILE_ADDRFROMCOORD_OUTPUT)))) { returnCode = ADDR_INVALIDPARAMS; } else { returnCode = HwlComputeHtileAddrFromCoord(pIn, pOut); } return returnCode; } /** **************************************************************************************************** * Lib::ComputeHtileCoordFromAddr * * @brief * Interface function stub of AddrComputeHtileCoordFromAddr * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeHtileCoordFromAddr( const ADDR2_COMPUTE_HTILE_COORDFROMADDR_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_HTILE_COORDFROMADDR_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode; if ((GetFillSizeFieldsFlags() == TRUE) && ((pIn->size != sizeof(ADDR2_COMPUTE_HTILE_COORDFROMADDR_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_HTILE_COORDFROMADDR_OUTPUT)))) { returnCode = ADDR_INVALIDPARAMS; } else { returnCode = HwlComputeHtileCoordFromAddr(pIn, pOut); } return returnCode; } /** **************************************************************************************************** * Lib::ComputeCmaskInfo * * @brief * Interface function stub of AddrComputeCmaskInfo * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeCmaskInfo( const ADDR2_COMPUTE_CMASK_INFO_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_CMASK_INFO_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode; if ((GetFillSizeFieldsFlags() == TRUE) && ((pIn->size != sizeof(ADDR2_COMPUTE_CMASK_INFO_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_CMASK_INFO_OUTPUT)))) { returnCode = ADDR_INVALIDPARAMS; } else if (pIn->cMaskFlags.linear) { returnCode = ADDR_INVALIDPARAMS; } else { returnCode = HwlComputeCmaskInfo(pIn, pOut); } return returnCode; } /** **************************************************************************************************** * Lib::ComputeCmaskAddrFromCoord * * @brief * Interface function stub of AddrComputeCmaskAddrFromCoord * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeCmaskAddrFromCoord( const ADDR2_COMPUTE_CMASK_ADDRFROMCOORD_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_CMASK_ADDRFROMCOORD_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode; if ((GetFillSizeFieldsFlags() == TRUE) && ((pIn->size != sizeof(ADDR2_COMPUTE_CMASK_ADDRFROMCOORD_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_CMASK_ADDRFROMCOORD_OUTPUT)))) { returnCode = ADDR_INVALIDPARAMS; } else { returnCode = HwlComputeCmaskAddrFromCoord(pIn, pOut); } return returnCode; } /** **************************************************************************************************** * Lib::ComputeCmaskCoordFromAddr * * @brief * Interface function stub of AddrComputeCmaskCoordFromAddr * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeCmaskCoordFromAddr( const ADDR2_COMPUTE_CMASK_COORDFROMADDR_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_CMASK_COORDFROMADDR_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_NOTIMPLEMENTED; ADDR_NOT_IMPLEMENTED(); return returnCode; } /** **************************************************************************************************** * Lib::ComputeFmaskInfo * * @brief * Interface function stub of ComputeFmaskInfo. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeFmaskInfo( const ADDR2_COMPUTE_FMASK_INFO_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_FMASK_INFO_OUTPUT* pOut ///< [out] output structure ) { ADDR_E_RETURNCODE returnCode; BOOL_32 valid = (IsZOrderSwizzle(pIn->swizzleMode) == TRUE) && ((pIn->numSamples > 0) || (pIn->numFrags > 0)); if (GetFillSizeFieldsFlags()) { if ((pIn->size != sizeof(ADDR2_COMPUTE_FMASK_INFO_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_FMASK_INFO_OUTPUT))) { valid = FALSE; } } if (valid == FALSE) { returnCode = ADDR_INVALIDPARAMS; } else { ADDR2_COMPUTE_SURFACE_INFO_INPUT localIn = {0}; ADDR2_COMPUTE_SURFACE_INFO_OUTPUT localOut = {0}; localIn.size = sizeof(ADDR2_COMPUTE_SURFACE_INFO_INPUT); localOut.size = sizeof(ADDR2_COMPUTE_SURFACE_INFO_OUTPUT); localIn.swizzleMode = pIn->swizzleMode; localIn.numSlices = Max(pIn->numSlices, 1u); localIn.width = Max(pIn->unalignedWidth, 1u); localIn.height = Max(pIn->unalignedHeight, 1u); localIn.bpp = GetFmaskBpp(pIn->numSamples, pIn->numFrags); localIn.flags.fmask = 1; localIn.numFrags = 1; localIn.numSamples = 1; localIn.resourceType = ADDR_RSRC_TEX_2D; if (localIn.bpp == 8) { localIn.format = ADDR_FMT_8; } else if (localIn.bpp == 16) { localIn.format = ADDR_FMT_16; } else if (localIn.bpp == 32) { localIn.format = ADDR_FMT_32; } else { localIn.format = ADDR_FMT_32_32; } returnCode = ComputeSurfaceInfo(&localIn, &localOut); if (returnCode == ADDR_OK) { pOut->pitch = localOut.pitch; pOut->height = localOut.height; pOut->baseAlign = localOut.baseAlign; pOut->numSlices = localOut.numSlices; pOut->fmaskBytes = static_cast(localOut.surfSize); pOut->sliceSize = localOut.sliceSize; pOut->bpp = localIn.bpp; pOut->numSamples = 1; } } return returnCode; } /** **************************************************************************************************** * Lib::ComputeFmaskAddrFromCoord * * @brief * Interface function stub of ComputeFmaskAddrFromCoord. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeFmaskAddrFromCoord( const ADDR2_COMPUTE_FMASK_ADDRFROMCOORD_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_FMASK_ADDRFROMCOORD_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_NOTIMPLEMENTED; ADDR_NOT_IMPLEMENTED(); return returnCode; } /** **************************************************************************************************** * Lib::ComputeFmaskCoordFromAddr * * @brief * Interface function stub of ComputeFmaskAddrFromCoord. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeFmaskCoordFromAddr( const ADDR2_COMPUTE_FMASK_COORDFROMADDR_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_FMASK_COORDFROMADDR_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_NOTIMPLEMENTED; ADDR_NOT_IMPLEMENTED(); return returnCode; } /** **************************************************************************************************** * Lib::GetMetaMiptailInfo * * @brief * Get mip tail coordinate information. * * @return * N/A **************************************************************************************************** */ VOID Lib::GetMetaMiptailInfo( ADDR2_META_MIP_INFO* pInfo, ///< [out] output structure to store per mip coord Dim3d mipCoord, ///< [in] mip tail base coord UINT_32 numMipInTail, ///< [in] number of mips in tail Dim3d* pMetaBlkDim ///< [in] meta block width/height/depth ) const { BOOL_32 isThick = (pMetaBlkDim->d > 1); UINT_32 mipWidth = pMetaBlkDim->w; UINT_32 mipHeight = pMetaBlkDim->h >> 1; UINT_32 mipDepth = pMetaBlkDim->d; UINT_32 minInc; if (isThick) { minInc = (pMetaBlkDim->h >= 512) ? 128 : ((pMetaBlkDim->h == 256) ? 64 : 32); } else if (pMetaBlkDim->h >= 1024) { minInc = 256; } else if (pMetaBlkDim->h == 512) { minInc = 128; } else { minInc = 64; } UINT_32 blk32MipId = 0xFFFFFFFF; for (UINT_32 mip = 0; mip < numMipInTail; mip++) { pInfo[mip].inMiptail = TRUE; pInfo[mip].startX = mipCoord.w; pInfo[mip].startY = mipCoord.h; pInfo[mip].startZ = mipCoord.d; pInfo[mip].width = mipWidth; pInfo[mip].height = mipHeight; pInfo[mip].depth = mipDepth; if (mipWidth <= 32) { if (blk32MipId == 0xFFFFFFFF) { blk32MipId = mip; } mipCoord.w = pInfo[blk32MipId].startX; mipCoord.h = pInfo[blk32MipId].startY; mipCoord.d = pInfo[blk32MipId].startZ; switch (mip - blk32MipId) { case 0: mipCoord.w += 32; // 16x16 break; case 1: mipCoord.h += 32; // 8x8 break; case 2: mipCoord.h += 32; // 4x4 mipCoord.w += 16; break; case 3: mipCoord.h += 32; // 2x2 mipCoord.w += 32; break; case 4: mipCoord.h += 32; // 1x1 mipCoord.w += 48; break; // The following are for BC/ASTC formats case 5: mipCoord.h += 48; // 1/2 x 1/2 break; case 6: mipCoord.h += 48; // 1/4 x 1/4 mipCoord.w += 16; break; case 7: mipCoord.h += 48; // 1/8 x 1/8 mipCoord.w += 32; break; case 8: mipCoord.h += 48; // 1/16 x 1/16 mipCoord.w += 48; break; default: ADDR_ASSERT_ALWAYS(); break; } mipWidth = ((mip - blk32MipId) == 0) ? 16 : 8; mipHeight = mipWidth; if (isThick) { mipDepth = mipWidth; } } else { if (mipWidth <= minInc) { // if we're below the minimal increment... if (isThick) { // For 3d, just go in z direction mipCoord.d += mipDepth; } else { // For 2d, first go across, then down if ((mipWidth * 2) == minInc) { // if we're 2 mips below, that's when we go back in x, and down in y mipCoord.w -= minInc; mipCoord.h += minInc; } else { // otherwise, just go across in x mipCoord.w += minInc; } } } else { // On even mip, go down, otherwise, go across if (mip & 1) { mipCoord.w += mipWidth; } else { mipCoord.h += mipHeight; } } // Divide the width by 2 mipWidth >>= 1; // After the first mip in tail, the mip is always a square mipHeight = mipWidth; // ...or for 3d, a cube if (isThick) { mipDepth = mipWidth; } } } } /** **************************************************************************************************** * Lib::ComputeDccInfo * * @brief * Interface function to compute DCC key info * * @return * return code of HwlComputeDccInfo **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeDccInfo( const ADDR2_COMPUTE_DCCINFO_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_DCCINFO_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode; if ((GetFillSizeFieldsFlags() == TRUE) && ((pIn->size != sizeof(ADDR2_COMPUTE_DCCINFO_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_DCCINFO_OUTPUT)))) { returnCode = ADDR_INVALIDPARAMS; } else { returnCode = HwlComputeDccInfo(pIn, pOut); } return returnCode; } /** **************************************************************************************************** * Lib::ComputePipeBankXor * * @brief * Interface function stub of Addr2ComputePipeBankXor. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputePipeBankXor( const ADDR2_COMPUTE_PIPEBANKXOR_INPUT* pIn, ADDR2_COMPUTE_PIPEBANKXOR_OUTPUT* pOut) { ADDR_E_RETURNCODE returnCode; if ((GetFillSizeFieldsFlags() == TRUE) && ((pIn->size != sizeof(ADDR2_COMPUTE_PIPEBANKXOR_INPUT)) || (pOut->size != sizeof(ADDR2_COMPUTE_PIPEBANKXOR_OUTPUT)))) { returnCode = ADDR_INVALIDPARAMS; } else { UINT_32 macroBlockBits = GetBlockSizeLog2(pIn->swizzleMode); UINT_32 pipeBits = GetPipeXorBits(macroBlockBits); UINT_32 bankBits = GetBankXorBits(macroBlockBits); UINT_32 pipeXor = 0; UINT_32 bankXor = 0; if (bankBits > 0) { UINT_32 bankMask = (1 << bankBits) - 1; UINT_32 bankIncrease = (1 << (bankBits - 1)) - 1; bankIncrease = (bankIncrease == 0) ? 1 : bankIncrease; bankXor = ((pIn->surfIndex & bankMask) * bankIncrease) & bankMask; } if (pipeBits > 0) { UINT_32 pipeMask = (1 << pipeBits) - 1; UINT_32 pipeIncrease = ((1 << (pipeBits - 1)) + 1) & pipeMask; pipeIncrease = (pipeIncrease == 0) ? 1 : pipeIncrease; pipeXor = ((pIn->surfIndex & pipeMask) * pipeIncrease) & pipeMask; } // Todo - pOut->pipeBankXor = pOut->pipeBankXor << (PipeInterleaveLog2 - 8) pOut->pipeBankXor = (bankXor << pipeBits) | pipeXor; returnCode = ADDR_OK; } return returnCode; } /** **************************************************************************************************** * Lib::ExtractPipeBankXor * * @brief * Internal function to extract bank and pipe xor bits from combined xor bits. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ExtractPipeBankXor( UINT_32 pipeBankXor, UINT_32 bankBits, UINT_32 pipeBits, UINT_32* pBankX, UINT_32* pPipeX) { ADDR_E_RETURNCODE returnCode; if (pipeBankXor < (1u << (pipeBits + bankBits))) { *pPipeX = pipeBankXor % (1 << pipeBits); *pBankX = pipeBankXor >> pipeBits; returnCode = ADDR_OK; } else { ADDR_ASSERT_ALWAYS(); returnCode = ADDR_INVALIDPARAMS; } return returnCode; } /** **************************************************************************************************** * Lib::ComputeSurfaceInfoSanityCheck * * @brief * Internal function to do basic sanity check before compute surface info * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceInfoSanityCheck( const ADDR2_COMPUTE_SURFACE_INFO_INPUT* pIn ///< [in] input structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_OK; BOOL_32 invalid = FALSE; if ((pIn->bpp > 128) || (pIn->width == 0) || (pIn->numFrags > 8) || (pIn->numSamples > 16)) { invalid = TRUE; } else if ((pIn->swizzleMode >= ADDR_SW_MAX_TYPE) || (pIn->resourceType >= ADDR_RSRC_MAX_TYPE)) { invalid = TRUE; } BOOL_32 mipmap = (pIn->numMipLevels > 1); BOOL_32 msaa = (pIn->numFrags > 1); ADDR2_SURFACE_FLAGS flags = pIn->flags; BOOL_32 zbuffer = (flags.depth || flags.stencil); BOOL_32 color = flags.color; BOOL_32 display = flags.display || flags.rotated; AddrResourceType rsrcType = pIn->resourceType; BOOL_32 tex3d = IsTex3d(rsrcType); AddrSwizzleMode swizzle = pIn->swizzleMode; BOOL_32 linear = IsLinear(swizzle); BOOL_32 blk256B = IsBlock256b(swizzle); BOOL_32 blkVar = IsBlockVariable(swizzle); BOOL_32 isNonPrtXor = IsNonPrtXor(swizzle); BOOL_32 prt = pIn->flags.prt; if (invalid == FALSE) { if ((pIn->numFrags > 1) && (GetBlockSize(swizzle) < (m_pipeInterleaveBytes * pIn->numFrags))) { // MSAA surface must have blk_bytes/pipe_interleave >= num_samples invalid = TRUE; } } if (invalid == FALSE) { switch (rsrcType) { case ADDR_RSRC_TEX_1D: invalid = msaa || zbuffer || display || (linear == FALSE); break; case ADDR_RSRC_TEX_2D: invalid = msaa && mipmap; break; case ADDR_RSRC_TEX_3D: invalid = msaa || zbuffer || display; break; default: invalid = TRUE; break; } } if (invalid == FALSE) { if (display) { invalid = (IsValidDisplaySwizzleMode(pIn) == FALSE); } } if (invalid == FALSE) { if (linear) { invalid = prt || zbuffer || msaa || (pIn->bpp == 0) || ((pIn->bpp % 8) != 0); } else { if (blk256B || blkVar || isNonPrtXor) { invalid = prt; if (blk256B) { invalid = invalid || zbuffer || tex3d || mipmap || msaa; } } if (invalid == FALSE) { if (IsZOrderSwizzle(swizzle)) { invalid = color && msaa; } else if (IsStandardSwizzle(rsrcType, swizzle)) { invalid = zbuffer; } else if (IsDisplaySwizzle(rsrcType, swizzle)) { invalid = zbuffer; } else if (IsRotateSwizzle(swizzle)) { invalid = zbuffer || (pIn->bpp > 64); } else { ADDR_ASSERT(!"invalid swizzle mode"); invalid = TRUE; } } } } if (invalid) { returnCode = ADDR_INVALIDPARAMS; } return returnCode; } /** **************************************************************************************************** * Lib::ApplyCustomizedPitchHeight * * @brief * Helper function to override hw required row pitch/slice pitch by customrized one * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ApplyCustomizedPitchHeight( const ADDR2_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure UINT_32 elementBytes, ///< [in] element bytes per element UINT_32 widthAlignInElement, ///< [in] pitch alignment in element UINT_32* pPitch, ///< [in/out] pitch UINT_32* pHeight ///< [in/out] height ) const { ADDR_E_RETURNCODE returnCode = ADDR_OK; if (pIn->numMipLevels <= 1) { if (pIn->pitchInElement > 0) { if ((pIn->pitchInElement % widthAlignInElement) != 0) { returnCode = ADDR_INVALIDPARAMS; } else if (pIn->pitchInElement < (*pPitch)) { returnCode = ADDR_INVALIDPARAMS; } else { *pPitch = pIn->pitchInElement; } } if (returnCode == ADDR_OK) { if (pIn->sliceAlign > 0) { UINT_32 customizedHeight = pIn->sliceAlign / elementBytes / (*pPitch); if (customizedHeight * elementBytes * (*pPitch) != pIn->sliceAlign) { returnCode = ADDR_INVALIDPARAMS; } else if ((pIn->numSlices > 1) && ((*pHeight) != customizedHeight)) { returnCode = ADDR_INVALIDPARAMS; } else { *pHeight = customizedHeight; } } } } return returnCode; } /** **************************************************************************************************** * Lib::ComputeSurfaceInfoLinear * * @brief * Internal function to calculate alignment for linear swizzle surface * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceInfoLinear( const ADDR2_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_OK; UINT_32 pitch = 0; UINT_32 actualHeight = 0; UINT_32 elementBytes = pIn->bpp >> 3; if (IsTex1d(pIn->resourceType)) { if (pIn->height > 1) { returnCode = ADDR_INVALIDPARAMS; } else { const UINT_32 widthAlignInElement = 256 / elementBytes; pitch = PowTwoAlign(pIn->width, widthAlignInElement); actualHeight = pIn->numMipLevels; returnCode = ApplyCustomizedPitchHeight(pIn, elementBytes, widthAlignInElement, &pitch, &actualHeight); if (returnCode == ADDR_OK) { if (pOut->pMipInfo != NULL) { for (UINT_32 i = 0; i < pIn->numMipLevels; i++) { pOut->pMipInfo[i].offset = pitch * elementBytes * i; pOut->pMipInfo[i].pitch = pitch; pOut->pMipInfo[i].height = 1; pOut->pMipInfo[i].depth = 1; } } } } } else { returnCode = ComputeSurfaceLinearPadding(pIn, &pitch, &actualHeight, pOut->pMipInfo); } if ((pitch == 0) || (actualHeight == 0)) { returnCode = ADDR_INVALIDPARAMS; } if (returnCode == ADDR_OK) { pOut->pitch = pitch; pOut->height = pIn->height; pOut->numSlices = pIn->numSlices; pOut->mipChainPitch = pitch; pOut->mipChainHeight = actualHeight; pOut->mipChainSlice = pOut->numSlices; pOut->epitchIsHeight = (pIn->numMipLevels > 1) ? TRUE : FALSE; pOut->sliceSize = pOut->pitch * actualHeight * elementBytes; pOut->surfSize = pOut->sliceSize * pOut->numSlices; pOut->baseAlign = (pIn->swizzleMode == ADDR_SW_LINEAR_GENERAL) ? (pIn->bpp / 8) : 256; pOut->blockWidth = (pIn->swizzleMode == ADDR_SW_LINEAR_GENERAL) ? 1 : (256 * 8 / pIn->bpp); pOut->blockHeight = 1; pOut->blockSlices = 1; } // Post calculation validate ADDR_ASSERT((pOut->sliceSize > 0)); return returnCode; } /** **************************************************************************************************** * Lib::ComputeSurfaceInfoTiled * * @brief * Internal function to calculate alignment for tiled swizzle surface * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceInfoTiled( const ADDR2_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ComputeBlockDimensionForSurf(&pOut->blockWidth, &pOut->blockHeight, &pOut->blockSlices, pIn->bpp, pIn->numFrags, pIn->resourceType, pIn->swizzleMode); if (returnCode == ADDR_OK) { const UINT_32 widthAlignInElement = pOut->blockWidth; pOut->pitch = PowTwoAlign(pIn->width, widthAlignInElement); if ((pIn->numMipLevels <= 1) && (pIn->pitchInElement > 0)) { if ((pIn->pitchInElement % widthAlignInElement) != 0) { returnCode = ADDR_INVALIDPARAMS; } else if (pIn->pitchInElement < pOut->pitch) { returnCode = ADDR_INVALIDPARAMS; } else { pOut->pitch = pIn->pitchInElement; } } if (returnCode == ADDR_OK) { pOut->height = PowTwoAlign(pIn->height, pOut->blockHeight); pOut->numSlices = PowTwoAlign(pIn->numSlices, pOut->blockSlices); pOut->epitchIsHeight = FALSE; pOut->firstMipInTail = FALSE; pOut->mipChainPitch = pOut->pitch; pOut->mipChainHeight = pOut->height; pOut->mipChainSlice = pOut->numSlices; if (pIn->numMipLevels > 1) { UINT_32 numMipLevel; ADDR2_MIP_INFO *pMipInfo; ADDR2_MIP_INFO mipInfo[4]; if (pOut->pMipInfo != NULL) { pMipInfo = pOut->pMipInfo; numMipLevel = pIn->numMipLevels; } else { pMipInfo = mipInfo; numMipLevel = Min(pIn->numMipLevels, 4u); } UINT_32 endingMip = GetMipChainInfo(pIn->resourceType, pIn->swizzleMode, pIn->bpp, pIn->width, pIn->height, pIn->numSlices, pOut->blockWidth, pOut->blockHeight, pOut->blockSlices, numMipLevel, pMipInfo); if (endingMip == 0) { pOut->epitchIsHeight = TRUE; pOut->pitch = pMipInfo[0].pitch; pOut->height = pMipInfo[0].height; pOut->numSlices = pMipInfo[0].depth; pOut->firstMipInTail = TRUE; } else { UINT_32 mip0WidthInBlk = pOut->pitch / pOut->blockWidth; UINT_32 mip0HeightInBlk = pOut->height / pOut->blockHeight; AddrMajorMode majorMode = GetMajorMode(pIn->resourceType, pIn->swizzleMode, mip0WidthInBlk, mip0HeightInBlk, pOut->numSlices / pOut->blockSlices); if (majorMode == ADDR_MAJOR_Y) { UINT_32 mip1WidthInBlk = RoundHalf(mip0WidthInBlk); if ((mip1WidthInBlk == 1) && (endingMip > 2)) { mip1WidthInBlk++; } pOut->mipChainPitch += (mip1WidthInBlk * pOut->blockWidth); pOut->epitchIsHeight = FALSE; } else { UINT_32 mip1HeightInBlk = RoundHalf(mip0HeightInBlk); if ((mip1HeightInBlk == 1) && (endingMip > 2)) { mip1HeightInBlk++; } pOut->mipChainHeight += (mip1HeightInBlk * pOut->blockHeight); pOut->epitchIsHeight = TRUE; } } } else if (pOut->pMipInfo != NULL) { pOut->pMipInfo[0].pitch = pOut->pitch; pOut->pMipInfo[0].height = pOut->height; pOut->pMipInfo[0].depth = IsTex3d(pIn->resourceType)? pOut->numSlices : 1; pOut->pMipInfo[0].offset = 0; } pOut->sliceSize = pOut->mipChainPitch *pOut->mipChainHeight * (pIn->bpp >> 3) * pIn->numFrags; pOut->surfSize = pOut->sliceSize * pOut->mipChainSlice; pOut->baseAlign = ComputeSurfaceBaseAlign(pIn->swizzleMode); } } return returnCode; } /** **************************************************************************************************** * Lib::ComputeSurfaceAddrFromCoordLinear * * @brief * Internal function to calculate address from coord for linear swizzle surface * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceAddrFromCoordLinear( const ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_OK; BOOL_32 valid = (pIn->numSamples <= 1) && (pIn->numFrags <= 1) && (pIn->pipeBankXor == 0); if (valid) { if (IsTex1d(pIn->resourceType)) { valid = (pIn->y == 0); } } if (valid) { ADDR2_COMPUTE_SURFACE_INFO_INPUT localIn = {0}; ADDR2_COMPUTE_SURFACE_INFO_OUTPUT localOut = {0}; localIn.bpp = pIn->bpp; localIn.width = Max(pIn->unalignedWidth, 1u); localIn.height = Max(pIn->unalignedHeight, 1u); localIn.numSlices = Max(pIn->numSlices, 1u); localIn.numMipLevels = Max(pIn->numMipLevels, 1u); localIn.resourceType = pIn->resourceType; if (localIn.numMipLevels <= 1) { localIn.pitchInElement = pIn->pitchInElement; } returnCode = ComputeSurfaceInfoLinear(&localIn, &localOut); if (returnCode == ADDR_OK) { UINT_32 elementBytes = pIn->bpp >> 3; UINT_64 sliceOffsetInSurf = static_cast(pIn->slice) * localOut.sliceSize; UINT_64 mipOffsetInSlice = 0; UINT_64 offsetInMip = 0; if (IsTex1d(pIn->resourceType)) { offsetInMip = static_cast(pIn->x) * elementBytes; mipOffsetInSlice = static_cast(pIn->mipId) * localOut.pitch * elementBytes; } else { UINT_64 mipStartHeight = SumGeo(localIn.height, pIn->mipId); mipOffsetInSlice = static_cast(mipStartHeight) * localOut.pitch * elementBytes; offsetInMip = (pIn->y * localOut.pitch + pIn->x) * elementBytes; } pOut->addr = sliceOffsetInSurf + mipOffsetInSlice + offsetInMip; pOut->bitPosition = 0; } else { valid = FALSE; } } if (valid == FALSE) { returnCode = ADDR_INVALIDPARAMS; } return returnCode; } /** **************************************************************************************************** * Lib::ComputeSurfaceAddrFromCoordTiled * * @brief * Internal function to calculate address from coord for tiled swizzle surface * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceAddrFromCoordTiled( const ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT* pOut ///< [out] output structure ) const { ADDR2_COMPUTE_SURFACE_INFO_INPUT localIn = {0}; localIn.swizzleMode = pIn->swizzleMode; localIn.flags = pIn->flags; localIn.resourceType = pIn->resourceType; localIn.bpp = pIn->bpp; localIn.width = Max(pIn->unalignedWidth, 1u); localIn.height = Max(pIn->unalignedHeight, 1u); localIn.numSlices = Max(pIn->numSlices, 1u); localIn.numMipLevels = Max(pIn->numMipLevels, 1u); if (localIn.numMipLevels <= 1) { localIn.pitchInElement = pIn->pitchInElement; } ADDR2_COMPUTE_SURFACE_INFO_OUTPUT localOut = {0}; ADDR_E_RETURNCODE returnCode = ComputeSurfaceInfoTiled(&localIn, &localOut); BOOL_32 valid = (returnCode == ADDR_OK) && (IsThin(pIn->resourceType, pIn->swizzleMode) || IsThick(pIn->resourceType, pIn->swizzleMode)) && ((pIn->pipeBankXor == 0) || (IsXor(pIn->swizzleMode))); if (valid) { Dim3d mipStartPos = {0}; UINT_32 mipTailOffset = 0; if (pIn->numMipLevels > 1) { // Mip-map chain cannot be MSAA surface ADDR_ASSERT((pIn->numSamples <= 1) && (pIn->numFrags<= 1)); mipStartPos = GetMipStartPos(pIn->resourceType, pIn->swizzleMode, localOut.pitch, localOut.height, localOut.numSlices, localOut.blockWidth, localOut.blockHeight, localOut.blockSlices, pIn->mipId, &mipTailOffset); } UINT_32 interleaveOffset = 0; UINT_32 pipeBits = 0; UINT_32 pipeXor = 0; UINT_32 bankBits = 0; UINT_32 bankXor = 0; if (IsThin(pIn->resourceType, pIn->swizzleMode)) { UINT_32 blockOffset = 0; UINT_32 log2blkSize = GetBlockSizeLog2(pIn->swizzleMode); UINT_32 log2ElementBytes = Log2(pIn->bpp >> 3); if (IsZOrderSwizzle(pIn->swizzleMode)) { // Morton generation if ((log2ElementBytes == 0) || (log2ElementBytes == 2)) { UINT_32 totalLowBits = 6 - log2ElementBytes; UINT_32 mortBits = totalLowBits / 2; UINT_32 lowBitsValue = MortonGen2d(pIn->y, pIn->x, mortBits); // Are 9 bits enough? UINT_32 highBitsValue = MortonGen2d(pIn->x >> mortBits, pIn->y >> mortBits, 9) << totalLowBits; blockOffset = lowBitsValue | highBitsValue; ADDR_ASSERT(blockOffset == lowBitsValue + highBitsValue); } else { blockOffset = MortonGen2d(pIn->y, pIn->x, 13); } // Fill LSBs with sample bits if (pIn->numSamples > 1) { blockOffset *= pIn->numSamples; blockOffset |= pIn->sample; } // Shift according to BytesPP blockOffset <<= log2ElementBytes; } else { // Micro block offset UINT_32 microBlockOffset = ComputeSurface2DMicroBlockOffset(pIn); blockOffset = microBlockOffset; // Micro block dimension ADDR_ASSERT(log2ElementBytes < sizeof(Block256b) / sizeof(Block256b[0])); Dim2d microBlockDim = Block256b[log2ElementBytes]; // Morton generation, does 12 bit enough? blockOffset |= MortonGen2d((pIn->x / microBlockDim.w), (pIn->y / microBlockDim.h), 12) << 8; // Sample bits start location UINT_32 sampleStart = log2blkSize - Log2(pIn->numSamples); // Join sample bits information to the highest Macro block bits if (IsNonPrtXor(pIn->swizzleMode)) { // Non-prt-Xor : xor highest Macro block bits with sample bits blockOffset = blockOffset ^ (pIn->sample << sampleStart); } else { // Non-Xor or prt-Xor: replace highest Macro block bits with sample bits // after this op, the blockOffset only contains log2 Macro block size bits blockOffset %= (1 << sampleStart); blockOffset |= (pIn->sample << sampleStart); ADDR_ASSERT((blockOffset >> log2blkSize) == 0); } } if (IsXor(pIn->swizzleMode)) { // Mask off bits above Macro block bits to keep page synonyms working for prt if (IsPrt(pIn->swizzleMode)) { blockOffset &= ((1 << log2blkSize) - 1); } // Preserve offset inside pipe interleave interleaveOffset = blockOffset & ((1 << m_pipeInterleaveLog2) - 1); blockOffset >>= m_pipeInterleaveLog2; // Pipe/Se xor bits pipeBits = GetPipeXorBits(log2blkSize); // Pipe xor pipeXor = FoldXor2d(blockOffset, pipeBits); blockOffset >>= pipeBits; // Bank xor bits bankBits = GetBankXorBits(log2blkSize); // Bank Xor bankXor = FoldXor2d(blockOffset, bankBits); blockOffset >>= bankBits; // Put all the part back together blockOffset <<= bankBits; blockOffset |= bankXor; blockOffset <<= pipeBits; blockOffset |= pipeXor; blockOffset <<= m_pipeInterleaveLog2; blockOffset |= interleaveOffset; } ADDR_ASSERT((blockOffset | mipTailOffset) == (blockOffset + mipTailOffset)); blockOffset |= mipTailOffset; if (IsNonPrtXor(pIn->swizzleMode) && (pIn->numSamples <= 1)) { // Apply slice xor if not MSAA/PRT blockOffset ^= (ReverseBitVector(pIn->slice, pipeBits) << m_pipeInterleaveLog2); blockOffset ^= (ReverseBitVector(pIn->slice >> pipeBits, bankBits) << (m_pipeInterleaveLog2 + pipeBits)); } returnCode = ApplyCustomerPipeBankXor(pIn->swizzleMode, pIn->pipeBankXor, bankBits, pipeBits, &blockOffset); blockOffset %= (1 << log2blkSize); UINT_32 pitchInMacroBlock = localOut.mipChainPitch / localOut.blockWidth; UINT_32 paddedHeightInMacroBlock = localOut.mipChainHeight / localOut.blockHeight; UINT_32 sliceSizeInMacroBlock = pitchInMacroBlock * paddedHeightInMacroBlock; UINT_32 macroBlockIndex = (pIn->slice + mipStartPos.d) * sliceSizeInMacroBlock + ((pIn->y / localOut.blockHeight) + mipStartPos.h) * pitchInMacroBlock + ((pIn->x / localOut.blockWidth) + mipStartPos.w); UINT_64 macroBlockOffset = (static_cast(macroBlockIndex) << GetBlockSizeLog2(pIn->swizzleMode)); pOut->addr = blockOffset | macroBlockOffset; } else { UINT_32 log2blkSize = GetBlockSizeLog2(pIn->swizzleMode); UINT_32 log2ElementBytes = Log2(pIn->bpp >> 3); Dim3d microBlockDim = Block1kb[log2ElementBytes]; UINT_32 blockOffset = MortonGen3d((pIn->x / microBlockDim.w), (pIn->y / microBlockDim.h), (pIn->slice / microBlockDim.d), 8); blockOffset <<= 10; blockOffset |= ComputeSurface3DMicroBlockOffset(pIn); if (IsXor(pIn->swizzleMode)) { // Mask off bits above Macro block bits to keep page synonyms working for prt if (IsPrt(pIn->swizzleMode)) { blockOffset &= ((1 << log2blkSize) - 1); } // Preserve offset inside pipe interleave interleaveOffset = blockOffset & ((1 << m_pipeInterleaveLog2) - 1); blockOffset >>= m_pipeInterleaveLog2; // Pipe/Se xor bits pipeBits = GetPipeXorBits(log2blkSize); // Pipe xor pipeXor = FoldXor3d(blockOffset, pipeBits); blockOffset >>= pipeBits; // Bank xor bits bankBits = GetBankXorBits(log2blkSize); // Bank Xor bankXor = FoldXor3d(blockOffset, bankBits); blockOffset >>= bankBits; // Put all the part back together blockOffset <<= bankBits; blockOffset |= bankXor; blockOffset <<= pipeBits; blockOffset |= pipeXor; blockOffset <<= m_pipeInterleaveLog2; blockOffset |= interleaveOffset; } ADDR_ASSERT((blockOffset | mipTailOffset) == (blockOffset + mipTailOffset)); blockOffset |= mipTailOffset; returnCode = ApplyCustomerPipeBankXor(pIn->swizzleMode, pIn->pipeBankXor, bankBits, pipeBits, &blockOffset); blockOffset %= (1 << log2blkSize); UINT_32 xb = (pIn->x + mipStartPos.w) / localOut.blockWidth; UINT_32 yb = (pIn->y + mipStartPos.h) / localOut.blockHeight; UINT_32 zb = (pIn->slice + mipStartPos.d) / localOut.blockSlices; UINT_32 pitchInBlock = localOut.mipChainPitch / localOut.blockWidth; UINT_32 sliceSizeInBlock = (localOut.mipChainHeight / localOut.blockHeight) * pitchInBlock; UINT_32 blockIndex = zb * sliceSizeInBlock + yb * pitchInBlock + xb; pOut->addr = blockOffset | (blockIndex << log2blkSize); } } else { returnCode = ADDR_INVALIDPARAMS; } return returnCode; } /** **************************************************************************************************** * Lib::ComputeSurfaceCoordFromAddrLinear * * @brief * Internal function to calculate coord from address for linear swizzle surface * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceCoordFromAddrLinear( const ADDR2_COMPUTE_SURFACE_COORDFROMADDR_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_SURFACE_COORDFROMADDR_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_OK; BOOL_32 valid = (pIn->numSamples <= 1) && (pIn->numFrags <= 1); if (valid) { if (IsTex1d(pIn->resourceType)) { valid = (pIn->unalignedHeight == 1); } } if (valid) { ADDR2_COMPUTE_SURFACE_INFO_INPUT localIn = {0}; ADDR2_COMPUTE_SURFACE_INFO_OUTPUT localOut = {0}; localIn.bpp = pIn->bpp; localIn.width = Max(pIn->unalignedWidth, 1u); localIn.height = Max(pIn->unalignedHeight, 1u); localIn.numSlices = Max(pIn->numSlices, 1u); localIn.numMipLevels = Max(pIn->numMipLevels, 1u); localIn.resourceType = pIn->resourceType; if (localIn.numMipLevels <= 1) { localIn.pitchInElement = pIn->pitchInElement; } returnCode = ComputeSurfaceInfoLinear(&localIn, &localOut); if (returnCode == ADDR_OK) { pOut->slice = static_cast(pIn->addr / localOut.sliceSize); pOut->sample = 0; UINT_32 offsetInSlice = static_cast(pIn->addr % localOut.sliceSize); UINT_32 elementBytes = pIn->bpp >> 3; UINT_32 mipOffsetInSlice = 0; UINT_32 mipSize = 0; UINT_32 mipId = 0; for (; mipId < pIn->numMipLevels ; mipId++) { if (IsTex1d(pIn->resourceType)) { mipSize = localOut.pitch * elementBytes; } else { UINT_32 currentMipHeight = (PowTwoAlign(localIn.height, (1 << mipId))) >> mipId; mipSize = currentMipHeight * localOut.pitch * elementBytes; } if (mipSize == 0) { valid = FALSE; break; } else if ((mipSize + mipOffsetInSlice) > offsetInSlice) { break; } else { mipOffsetInSlice += mipSize; if ((mipId == (pIn->numMipLevels - 1)) || (mipOffsetInSlice >= localOut.sliceSize)) { valid = FALSE; } } } if (valid) { pOut->mipId = mipId; UINT_32 elemOffsetInMip = (offsetInSlice - mipOffsetInSlice) / elementBytes; if (IsTex1d(pIn->resourceType)) { if (elemOffsetInMip < localOut.pitch) { pOut->x = elemOffsetInMip; pOut->y = 0; } else { valid = FALSE; } } else { pOut->y = elemOffsetInMip / localOut.pitch; pOut->x = elemOffsetInMip % localOut.pitch; } if ((pOut->slice >= pIn->numSlices) || (pOut->mipId >= pIn->numMipLevels) || (pOut->x >= Max((pIn->unalignedWidth >> pOut->mipId), 1u)) || (pOut->y >= Max((pIn->unalignedHeight >> pOut->mipId), 1u)) || (IsTex3d(pIn->resourceType) && (FALSE == Valid3DMipSliceIdConstraint(pIn->numSlices, pOut->mipId, pOut->slice)))) { valid = FALSE; } } } else { valid = FALSE; } } if (valid == FALSE) { returnCode = ADDR_INVALIDPARAMS; } return returnCode; } /** **************************************************************************************************** * Lib::ComputeSurfaceCoordFromAddrTiled * * @brief * Internal function to calculate coord from address for tiled swizzle surface * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceCoordFromAddrTiled( const ADDR2_COMPUTE_SURFACE_COORDFROMADDR_INPUT* pIn, ///< [in] input structure ADDR2_COMPUTE_SURFACE_COORDFROMADDR_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE returnCode = ADDR_NOTIMPLEMENTED; ADDR_NOT_IMPLEMENTED(); return returnCode; } /** **************************************************************************************************** * Lib::ComputeSurfaceInfoLinear * * @brief * Internal function to calculate padding for linear swizzle 2D/3D surface * * @return * N/A **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeSurfaceLinearPadding( const ADDR2_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input srtucture UINT_32* pMipmap0PaddedWidth, ///< [out] padded width in element UINT_32* pSlice0PaddedHeight, ///< [out] padded height for HW ADDR2_MIP_INFO* pMipInfo ///< [out] per mip information ) const { ADDR_E_RETURNCODE returnCode = ADDR_OK; UINT_32 elementBytes = pIn->bpp >> 3; UINT_32 widthAlignInElement = 0; if (pIn->swizzleMode == ADDR_SW_LINEAR_GENERAL) { ADDR_ASSERT(pIn->numMipLevels <= 1); ADDR_ASSERT(pIn->numSlices <= 1); widthAlignInElement = 1; } else { widthAlignInElement = (256 / elementBytes); } UINT_32 mipChainWidth = PowTwoAlign(pIn->width, widthAlignInElement); UINT_32 slice0PaddedHeight = pIn->height; returnCode = ApplyCustomizedPitchHeight(pIn, elementBytes, widthAlignInElement, &mipChainWidth, &slice0PaddedHeight); if (returnCode == ADDR_OK) { UINT_32 mipChainHeight = 0; UINT_32 mipHeight = pIn->height; for (UINT_32 i = 0; i < pIn->numMipLevels; i++) { if (pMipInfo != NULL) { pMipInfo[i].offset = mipChainWidth * mipChainHeight * elementBytes; pMipInfo[i].pitch = mipChainWidth; pMipInfo[i].height = mipHeight; pMipInfo[i].depth = 1; } mipChainHeight += mipHeight; mipHeight = RoundHalf(mipHeight); mipHeight = Max(mipHeight, 1u); } *pMipmap0PaddedWidth = mipChainWidth; *pSlice0PaddedHeight = (pIn->numMipLevels > 1) ? mipChainHeight : slice0PaddedHeight; } return returnCode; } /** **************************************************************************************************** * Lib::ComputeBlockDimensionForSurf * * @brief * Internal function to get block width/height/depth in element from surface input params. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeBlockDimensionForSurf( Dim3d* pDim, UINT_32 bpp, UINT_32 numSamples, AddrResourceType resourceType, AddrSwizzleMode swizzleMode) const { return ComputeBlockDimensionForSurf(&pDim->w, &pDim->h, &pDim->d, bpp, numSamples, resourceType, swizzleMode); } /** **************************************************************************************************** * Lib::ComputeBlockDimensionForSurf * * @brief * Internal function to get block width/height/depth in element from surface input params. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeBlockDimensionForSurf( UINT_32* pWidth, UINT_32* pHeight, UINT_32* pDepth, UINT_32 bpp, UINT_32 numSamples, AddrResourceType resourceType, AddrSwizzleMode swizzleMode) const { ADDR_E_RETURNCODE returnCode = ComputeBlockDimension(pWidth, pHeight, pDepth, bpp, resourceType, swizzleMode); if ((returnCode == ADDR_OK) && (numSamples > 1) && IsThin(resourceType, swizzleMode)) { UINT_32 log2blkSize = GetBlockSizeLog2(swizzleMode); UINT_32 sample = numSamples; UINT_32 log2sample = Log2(sample); *pWidth >>= (log2sample / 2); *pHeight >>= (log2sample / 2); if ((log2blkSize % 2) == 0) { *pWidth >>= (sample % 2); } else { *pHeight >>= (sample % 2); } } return returnCode; } /** **************************************************************************************************** * Lib::ComputeBlockDimension * * @brief * Internal function to get block width/height/depth in element without considering MSAA case * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeBlockDimension( UINT_32* pWidth, UINT_32* pHeight, UINT_32* pDepth, UINT_32 bpp, AddrResourceType resourceType, AddrSwizzleMode swizzleMode) const { ADDR_E_RETURNCODE returnCode = ADDR_OK; UINT_32 eleBytes = bpp >> 3; UINT_32 microBlockSizeTableIndex = Log2(eleBytes); UINT_32 log2blkSize = GetBlockSizeLog2(swizzleMode); if (IsThin(resourceType, swizzleMode)) { if (pDepth != NULL) { *pDepth = 1; } UINT_32 log2blkSizeIn256B = log2blkSize - 8; UINT_32 widthAmp = log2blkSizeIn256B / 2; UINT_32 heightAmp = log2blkSizeIn256B - widthAmp; ADDR_ASSERT(microBlockSizeTableIndex < sizeof(Block256b) / sizeof(Block256b[0])); *pWidth = (Block256b[microBlockSizeTableIndex].w << widthAmp); *pHeight = (Block256b[microBlockSizeTableIndex].h << heightAmp); } else if (IsThick(resourceType, swizzleMode)) { UINT_32 log2blkSizeIn1KB = log2blkSize - 10; UINT_32 averageAmp = log2blkSizeIn1KB / 3; UINT_32 restAmp = log2blkSizeIn1KB % 3; ADDR_ASSERT(microBlockSizeTableIndex < sizeof(Block1kb) / sizeof(Block1kb[0])); *pWidth = Block1kb[microBlockSizeTableIndex].w << averageAmp; *pHeight = Block1kb[microBlockSizeTableIndex].h << (averageAmp + (restAmp / 2)); *pDepth = Block1kb[microBlockSizeTableIndex].d << (averageAmp + ((restAmp != 0) ? 1 : 0)); } else { ADDR_ASSERT_ALWAYS(); returnCode = ADDR_INVALIDPARAMS; } return returnCode; } /** **************************************************************************************************** * Lib::GetMipChainInfo * * @brief * Internal function to get out information about mip chain * * @return * Smaller value between Id of first mip fitted in mip tail and max Id of mip being created **************************************************************************************************** */ UINT_32 Lib::GetMipChainInfo( AddrResourceType resourceType, AddrSwizzleMode swizzleMode, UINT_32 bpp, UINT_32 mip0Width, UINT_32 mip0Height, UINT_32 mip0Depth, UINT_32 blockWidth, UINT_32 blockHeight, UINT_32 blockDepth, UINT_32 numMipLevel, ADDR2_MIP_INFO* pMipInfo) const { const Dim3d tailMaxDim = GetMipTailDim(resourceType, swizzleMode, blockWidth, blockHeight, blockDepth); UINT_32 mipPitch = mip0Width; UINT_32 mipHeight = mip0Height; UINT_32 mipDepth = IsTex3d(resourceType) ? mip0Depth : 1; UINT_32 offset = 0; UINT_32 endingMip = numMipLevel - 1; BOOL_32 inTail = FALSE; BOOL_32 finalDim = FALSE; BOOL_32 is3dThick = IsThick(resourceType, swizzleMode); BOOL_32 is3dThin = IsTex3d(resourceType) && SwizzleModeTable[swizzleMode].isDisp; for (UINT_32 mipId = 0; mipId < numMipLevel; mipId++) { if (inTail) { if (finalDim == FALSE) { UINT_32 mipSize; if (is3dThick) { mipSize = mipPitch * mipHeight * mipDepth * (bpp >> 3); } else { mipSize = mipPitch * mipHeight * (bpp >> 3); } if (mipSize <= 256) { UINT_32 index = Log2(bpp >> 3); if (is3dThick) { mipPitch = CompressBlock3dZ[index].w; mipHeight = CompressBlock3dZ[index].h; mipDepth = CompressBlock3dZ[index].d; } else { mipPitch = CompressBlock2d[index].w; mipHeight = CompressBlock2d[index].h; } finalDim = TRUE; } } } else { inTail = IsInMipTail(resourceType, swizzleMode, tailMaxDim, mipPitch, mipHeight, mipDepth); if (inTail) { endingMip = mipId; mipPitch = tailMaxDim.w; mipHeight = tailMaxDim.h; if (is3dThick) { mipDepth = tailMaxDim.d; } } else { mipPitch = PowTwoAlign(mipPitch, blockWidth); mipHeight = PowTwoAlign(mipHeight, blockHeight); if (is3dThick) { mipDepth = PowTwoAlign(mipDepth, blockDepth); } } } pMipInfo[mipId].pitch = mipPitch; pMipInfo[mipId].height = mipHeight; pMipInfo[mipId].depth = mipDepth; pMipInfo[mipId].offset = offset; offset += (mipPitch * mipHeight * mipDepth * (bpp >> 3)); if (finalDim) { if (is3dThin) { mipDepth = Max(mipDepth >> 1, 1u); } } else { mipPitch = Max(mipPitch >> 1, 1u); mipHeight = Max(mipHeight >> 1, 1u); if (is3dThick || is3dThin) { mipDepth = Max(mipDepth >> 1, 1u); } } } return endingMip; } /** **************************************************************************************************** * Lib::GetMipStartPos * * @brief * Internal function to get out information about mip logical start position * * @return * logical start position in macro block width/heith/depth of one mip level within one slice **************************************************************************************************** */ Dim3d Lib::GetMipStartPos( AddrResourceType resourceType, AddrSwizzleMode swizzleMode, UINT_32 width, UINT_32 height, UINT_32 depth, UINT_32 blockWidth, UINT_32 blockHeight, UINT_32 blockDepth, UINT_32 mipId, UINT_32* pMipTailOffset) const { Dim3d mipStartPos = {0}; const Dim3d tailMaxDim = GetMipTailDim(resourceType, swizzleMode, blockWidth, blockHeight, blockDepth); // Report mip in tail if Mip0 is already in mip tail BOOL_32 inMipTail = IsInMipTail(resourceType, swizzleMode, tailMaxDim, width, height, depth); UINT_32 log2blkSize = GetBlockSizeLog2(swizzleMode); if (inMipTail == FALSE) { // Mip 0 dimension, unit in block UINT_32 mipWidthInBlk = width / blockWidth; UINT_32 mipHeightInBlk = height / blockHeight; UINT_32 mipDepthInBlk = depth / blockDepth; AddrMajorMode majorMode = GetMajorMode(resourceType, swizzleMode, mipWidthInBlk, mipHeightInBlk, mipDepthInBlk); UINT_32 endingMip = mipId + 1; for (UINT_32 i = 1; i <= mipId; i++) { if ((i == 1) || (i == 3)) { if (majorMode == ADDR_MAJOR_Y) { mipStartPos.w += mipWidthInBlk; } else { mipStartPos.h += mipHeightInBlk; } } else { if (majorMode == ADDR_MAJOR_X) { mipStartPos.w += mipWidthInBlk; } else if (majorMode == ADDR_MAJOR_Y) { mipStartPos.h += mipHeightInBlk; } else { mipStartPos.d += mipDepthInBlk; } } BOOL_32 inTail = FALSE; if (IsThick(resourceType, swizzleMode)) { UINT_32 dim = log2blkSize % 3; if (dim == 0) { inTail = (mipWidthInBlk <= 2) && (mipHeightInBlk == 1) && (mipDepthInBlk <= 2); } else if (dim == 1) { inTail = (mipWidthInBlk == 1) && (mipHeightInBlk <= 2) && (mipDepthInBlk <= 2); } else { inTail = (mipWidthInBlk <= 2) && (mipHeightInBlk <= 2) && (mipDepthInBlk == 1); } } else { if (log2blkSize & 1) { inTail = (mipWidthInBlk <= 2) && (mipHeightInBlk == 1); } else { inTail = (mipWidthInBlk == 1) && (mipHeightInBlk <= 2); } } if (inTail) { endingMip = i; break; } mipWidthInBlk = RoundHalf(mipWidthInBlk); mipHeightInBlk = RoundHalf(mipHeightInBlk); mipDepthInBlk = RoundHalf(mipDepthInBlk); } if (mipId >= endingMip) { inMipTail = TRUE; UINT_32 index = mipId - endingMip + MaxMacroBits - log2blkSize; ADDR_ASSERT(index < sizeof(MipTailOffset) / sizeof(UINT_32)); *pMipTailOffset = MipTailOffset[index] << 8; } } else { UINT_32 index = mipId + MaxMacroBits - log2blkSize; ADDR_ASSERT(index < sizeof(MipTailOffset) / sizeof(UINT_32)); *pMipTailOffset = MipTailOffset[index] << 8; } return mipStartPos; } /** **************************************************************************************************** * Lib::GetMipTailDim * * @brief * Internal function to get out max dimension of first level in mip tail * * @return * Max Width/Height/Depth value of the first mip fitted in mip tail **************************************************************************************************** */ Dim3d Lib::GetMipTailDim( AddrResourceType resourceType, AddrSwizzleMode swizzleMode, UINT_32 blockWidth, UINT_32 blockHeight, UINT_32 blockDepth) const { Dim3d out = {blockWidth, blockHeight, blockDepth}; UINT_32 log2blkSize = GetBlockSizeLog2(swizzleMode); if (IsThick(resourceType, swizzleMode)) { UINT_32 dim = log2blkSize % 3; if (dim == 0) { out.h >>= 1; } else if (dim == 1) { out.w >>= 1; } else { out.d >>= 1; } } else { if (log2blkSize & 1) { out.h >>= 1; } else { out.w >>= 1; } } return out; } /** **************************************************************************************************** * Lib::ComputeSurface2DMicroBlockOffset * * @brief * Internal function to calculate micro block (256B) offset from coord for 2D resource * * @return * micro block (256B) offset for 2D resource **************************************************************************************************** */ UINT_32 Lib::ComputeSurface2DMicroBlockOffset( const _ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT* pIn) const { ADDR_ASSERT(IsThin(pIn->resourceType, pIn->swizzleMode)); UINT_32 log2ElementBytes = Log2(pIn->bpp >> 3); UINT_32 microBlockOffset = 0; if (IsStandardSwizzle(pIn->resourceType, pIn->swizzleMode)) { UINT_32 xBits = pIn->x << log2ElementBytes; microBlockOffset = (xBits & 0xf) | ((pIn->y & 0x3) << 4); if (log2ElementBytes < 3) { microBlockOffset |= (pIn->y & 0x4) << 4; if (log2ElementBytes == 0) { microBlockOffset |= (pIn->y & 0x8) << 4; } else { microBlockOffset |= (xBits & 0x10) << 3; } } else { microBlockOffset |= (xBits & 0x30) << 2; } } else if (IsDisplaySwizzle(pIn->resourceType, pIn->swizzleMode)) { if (log2ElementBytes == 4) { microBlockOffset = (GetBit(pIn->x, 0) << 4) | (GetBit(pIn->y, 0) << 5) | (GetBit(pIn->x, 1) << 6) | (GetBit(pIn->y, 1) << 7); } else { microBlockOffset = GetBits(pIn->x, 0, 3, log2ElementBytes) | GetBits(pIn->y, 1, 2, 3 + log2ElementBytes) | GetBits(pIn->x, 3, 1, 5 + log2ElementBytes) | GetBits(pIn->y, 3, 1, 6 + log2ElementBytes); microBlockOffset = GetBits(microBlockOffset, 0, 4, 0) | (GetBit(pIn->y, 0) << 4) | GetBits(microBlockOffset, 4, 3, 5); } } else if (IsRotateSwizzle(pIn->swizzleMode)) { microBlockOffset = GetBits(pIn->y, 0, 3, log2ElementBytes) | GetBits(pIn->x, 1, 2, 3 + log2ElementBytes) | GetBits(pIn->x, 3, 1, 5 + log2ElementBytes) | GetBits(pIn->y, 3, 1, 6 + log2ElementBytes); microBlockOffset = GetBits(microBlockOffset, 0, 4, 0) | (GetBit(pIn->x, 0) << 4) | GetBits(microBlockOffset, 4, 3, 5); if (log2ElementBytes == 3) { microBlockOffset = GetBits(microBlockOffset, 0, 6, 0) | GetBits(pIn->x, 1, 2, 6); } } return microBlockOffset; } /** **************************************************************************************************** * Lib::ComputeSurface3DMicroBlockOffset * * @brief * Internal function to calculate micro block (1KB) offset from coord for 3D resource * * @return * micro block (1KB) offset for 3D resource **************************************************************************************************** */ UINT_32 Lib::ComputeSurface3DMicroBlockOffset( const _ADDR2_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT* pIn) const { ADDR_ASSERT(IsThick(pIn->resourceType, pIn->swizzleMode)); UINT_32 log2ElementBytes = Log2(pIn->bpp >> 3); UINT_32 microBlockOffset = 0; if (IsStandardSwizzle(pIn->resourceType, pIn->swizzleMode)) { if (log2ElementBytes == 0) { microBlockOffset = ((pIn->slice & 4) >> 2) | ((pIn->y & 4) >> 1); } else if (log2ElementBytes == 1) { microBlockOffset = ((pIn->slice & 4) >> 2) | ((pIn->y & 4) >> 1); } else if (log2ElementBytes == 2) { microBlockOffset = ((pIn->y & 4) >> 2) | ((pIn->x & 4) >> 1); } else if (log2ElementBytes == 3) { microBlockOffset = (pIn->x & 6) >> 1; } else { microBlockOffset = pIn->x & 3; } microBlockOffset <<= 8; UINT_32 xBits = pIn->x << log2ElementBytes; microBlockOffset |= (xBits & 0xf) | ((pIn->y & 0x3) << 4) | ((pIn->slice & 0x3) << 6); } else if (IsZOrderSwizzle(pIn->swizzleMode)) { UINT_32 xh, yh, zh; if (log2ElementBytes == 0) { microBlockOffset = (pIn->x & 1) | ((pIn->y & 1) << 1) | ((pIn->x & 2) << 1) | ((pIn->y & 2) << 2); microBlockOffset = microBlockOffset | ((pIn->slice & 3) << 4) | ((pIn->x & 4) << 4); xh = pIn->x >> 3; yh = pIn->y >> 2; zh = pIn->slice >> 2; } else if (log2ElementBytes == 1) { microBlockOffset = (pIn->x & 1) | ((pIn->y & 1) << 1) | ((pIn->x & 2) << 1) | ((pIn->y & 2) << 2); microBlockOffset = (microBlockOffset << 1) | ((pIn->slice & 3) << 5); xh = pIn->x >> 2; yh = pIn->y >> 2; zh = pIn->slice >> 2; } else if (log2ElementBytes == 2) { microBlockOffset = (pIn->x & 1) | ((pIn->y & 1) << 1) | ((pIn->x & 2) << 1) | ((pIn->slice & 1) << 3); microBlockOffset = (microBlockOffset << 2) | ((pIn->y & 2) << 5); xh = pIn->x >> 2; yh = pIn->y >> 2; zh = pIn->slice >> 1; } else if (log2ElementBytes == 3) { microBlockOffset = (pIn->x & 1) | ((pIn->y & 1) << 1) | ((pIn->slice & 1) << 2) | ((pIn->x & 2) << 2); microBlockOffset <<= 3; xh = pIn->x >> 2; yh = pIn->y >> 1; zh = pIn->slice >> 1; } else { microBlockOffset = (((pIn->x & 1) | ((pIn->y & 1) << 1) | ((pIn->slice & 1) << 2)) << 4); xh = pIn->x >> 1; yh = pIn->y >> 1; zh = pIn->slice >> 1; } microBlockOffset |= ((MortonGen3d(xh, yh, zh, 1) << 7) & 0x380); } return microBlockOffset; } /** **************************************************************************************************** * Lib::GetPipeXorBits * * @brief * Internal function to get bits number for pipe/se xor operation * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ UINT_32 Lib::GetPipeXorBits( UINT_32 macroBlockBits) const { ADDR_ASSERT(macroBlockBits >= m_pipeInterleaveLog2); // Total available xor bits UINT_32 xorBits = macroBlockBits - m_pipeInterleaveLog2; // Pipe/Se xor bits UINT_32 pipeBits = Min(xorBits, m_pipesLog2 + m_seLog2); return pipeBits; } /** **************************************************************************************************** * Lib::GetBankXorBits * * @brief * Internal function to get bits number for pipe/se xor operation * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ UINT_32 Lib::GetBankXorBits( UINT_32 macroBlockBits) const { UINT_32 pipeBits = GetPipeXorBits(macroBlockBits); // Bank xor bits UINT_32 bankBits = Min(macroBlockBits - pipeBits - m_pipeInterleaveLog2, m_banksLog2); return bankBits; } /** **************************************************************************************************** * Lib::Addr2GetPreferredSurfaceSetting * * @brief * Internal function to get suggested surface information for cliet to use * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::Addr2GetPreferredSurfaceSetting( const ADDR2_GET_PREFERRED_SURF_SETTING_INPUT* pIn, ADDR2_GET_PREFERRED_SURF_SETTING_OUTPUT* pOut) const { // Macro define resource block type enum AddrBlockType { AddrBlockMicro = 0, // Resource uses 256B block AddrBlock4KB = 1, // Resource uses 4KB block AddrBlock64KB = 2, // Resource uses 64KB block AddrBlockVar = 3, // Resource uses var blcok AddrBlockLinear = 4, // Resource uses linear swizzle mode AddrBlockMaxTiledType = AddrBlock64KB + 1, }; enum AddrBlockSet { AddrBlockSetMicro = 1 << AddrBlockMicro, AddrBlockSetMacro4KB = 1 << AddrBlock4KB, AddrBlockSetMacro64KB = 1 << AddrBlock64KB, AddrBlockSetVar = 1 << AddrBlockVar, AddrBlockSetLinear = 1 << AddrBlockLinear, AddrBlockSetMacro = AddrBlockSetMacro4KB | AddrBlockSetMacro64KB, }; ADDR_E_RETURNCODE returnCode = ADDR_OK; ElemLib* pElemLib = GetElemLib(); // Set format to INVALID will skip this conversion UINT_32 expandX = 1; UINT_32 expandY = 1; UINT_32 bpp = pIn->bpp; if (pIn->format != ADDR_FMT_INVALID) { // Don't care for this case ElemMode elemMode = ADDR_UNCOMPRESSED; // Get compression/expansion factors and element mode which indicates compression/expansion bpp = pElemLib->GetBitsPerPixel(pIn->format, &elemMode, &expandX, &expandY); } UINT_32 numSamples = Max(pIn->numSamples, 1u); UINT_32 numFrags = (pIn->numFrags == 0) ? numSamples : pIn->numFrags; UINT_32 width = Max(pIn->width / expandX, 1u); UINT_32 height = Max(pIn->height / expandY, 1u); UINT_32 slice = Max(pIn->numSlices, 1u); UINT_32 numMipLevels = Max(pIn->numMipLevels, 1u); if (pIn->flags.fmask) { bpp = GetFmaskBpp(numSamples, numFrags); numFrags = 1; numSamples = 1; pOut->resourceType = ADDR_RSRC_TEX_2D; } else { // The output may get changed for volume(3D) texture resource in future pOut->resourceType = pIn->resourceType; } if (IsTex1d(pOut->resourceType)) { pOut->swizzleMode = ADDR_SW_LINEAR; pOut->validBlockSet.value = AddrBlockSetLinear; pOut->canXor = FALSE; } else { ADDR2_BLOCK_SET blockSet; AddrSwType swType; blockSet.value = 0; BOOL_32 tryPrtXor = pIn->flags.prt; // Filter out improper swType and blockSet by HW restriction if (pIn->flags.fmask || pIn->flags.depth || pIn->flags.stencil) { ADDR_ASSERT(IsTex2d(pOut->resourceType)); blockSet.value = AddrBlockSetMacro; swType = ADDR_SW_Z; } else if (pElemLib->IsBlockCompressed(pIn->format)) { // block compressed formats (BCx, ASTC, ETC2) must be either S or D modes. Not sure // under what circumstances "_D" would be appropriate as these formats are not // displayable. blockSet.value = AddrBlockSetMacro; swType = ADDR_SW_S; } else if (IsTex3d(pOut->resourceType)) { blockSet.value = AddrBlockSetLinear | AddrBlockSetMacro; swType = (slice >= 8) ? ADDR_SW_Z : ADDR_SW_S; } else if (numMipLevels > 1) { ADDR_ASSERT(numFrags == 1); blockSet.value = AddrBlockSetLinear | AddrBlockSetMacro; swType = pIn->flags.display ? ADDR_SW_D : ADDR_SW_S; } else if ((numFrags > 1) || (numSamples > 1)) { ADDR_ASSERT(IsTex2d(pOut->resourceType)); blockSet.value = AddrBlockSetMacro; swType = pIn->flags.display ? ADDR_SW_D : ADDR_SW_S; } else { ADDR_ASSERT(IsTex2d(pOut->resourceType)); blockSet.value = AddrBlockSetLinear | AddrBlockSetMicro | AddrBlockSetMacro; if (pIn->flags.rotated || pIn->flags.display) { swType = pIn->flags.rotated ? ADDR_SW_R : ADDR_SW_D; if (IsDce12()) { if (pIn->bpp != 32) { blockSet.micro = FALSE; } // DCE12 does not support display surface to be _T swizzle mode tryPrtXor = FALSE; } else { ADDR_NOT_IMPLEMENTED(); } } else if (pIn->flags.overlay) { swType = ADDR_SW_D; } else { swType = ADDR_SW_S; } } if ((numFrags > 1) && (GetBlockSize(ADDR_SW_4KB) < (m_pipeInterleaveBytes * numFrags))) { // MSAA surface must have blk_bytes/pipe_interleave >= num_samples blockSet.macro4KB = FALSE; } if (pIn->flags.prt) { blockSet.value &= AddrBlock64KB; } // Apply customized forbidden setting blockSet.value &= ~pIn->forbiddenBlock.value; if (pIn->maxAlign > 0) { if (pIn->maxAlign < GetBlockSize(ADDR_SW_64KB)) { blockSet.macro64KB = FALSE; } if (pIn->maxAlign < GetBlockSize(ADDR_SW_4KB)) { blockSet.macro4KB = FALSE; } if (pIn->maxAlign < GetBlockSize(ADDR_SW_256B)) { blockSet.micro = FALSE; } } Dim3d blkDim[AddrBlockMaxTiledType] = {{0}, {0}, {0}}; Dim3d padDim[AddrBlockMaxTiledType] = {{0}, {0}, {0}}; UINT_64 padSize[AddrBlockMaxTiledType] = {0}; if (blockSet.micro) { returnCode = ComputeBlockDimensionForSurf(&blkDim[AddrBlockMicro], bpp, numFrags, pOut->resourceType, ADDR_SW_256B); if (returnCode == ADDR_OK) { if ((blkDim[AddrBlockMicro].w >= width) && (blkDim[AddrBlockMicro].h >= height)) { // If one 256B block can contain the surface, don't bother bigger block type blockSet.macro4KB = FALSE; blockSet.macro64KB = FALSE; blockSet.var = FALSE; } padSize[AddrBlockMicro] = ComputePadSize(&blkDim[AddrBlockMicro], width, height, slice, &padDim[AddrBlockMicro]); } } if ((returnCode == ADDR_OK) && (blockSet.macro4KB)) { returnCode = ComputeBlockDimensionForSurf(&blkDim[AddrBlock4KB], bpp, numFrags, pOut->resourceType, ADDR_SW_4KB); if (returnCode == ADDR_OK) { padSize[AddrBlock4KB] = ComputePadSize(&blkDim[AddrBlock4KB], width, height, slice, &padDim[AddrBlock4KB]); ADDR_ASSERT(padSize[AddrBlock4KB] >= padSize[AddrBlockMicro]); } } if ((returnCode == ADDR_OK) && (blockSet.macro64KB)) { returnCode = ComputeBlockDimensionForSurf(&blkDim[AddrBlock64KB], bpp, numFrags, pOut->resourceType, ADDR_SW_64KB); if (returnCode == ADDR_OK) { padSize[AddrBlock64KB] = ComputePadSize(&blkDim[AddrBlock64KB], width, height, slice, &padDim[AddrBlock64KB]); ADDR_ASSERT(padSize[AddrBlock64KB] >= padSize[AddrBlock4KB]); ADDR_ASSERT(padSize[AddrBlock64KB] >= padSize[AddrBlockMicro]); if ((padSize[AddrBlock64KB] >= static_cast(width) * height * slice * 2) && ((blockSet.value & ~AddrBlockSetMacro64KB) != 0)) { // If 64KB block waste more than half memory on padding, filter it out from // candidate list when it is not the only choice left blockSet.macro64KB = FALSE; } } } if (returnCode == ADDR_OK) { // Use minimum block type which meets all conditions above if flag minimizeAlign was set if (pIn->flags.minimizeAlign) { // If padded size of 64KB block is larger than padded size of 256B block or 4KB // block, filter out 64KB block from candidate list if (blockSet.macro64KB && ((blockSet.micro && (padSize[AddrBlockMicro] < padSize[AddrBlock64KB])) || (blockSet.macro4KB && (padSize[AddrBlock4KB] < padSize[AddrBlock64KB])))) { blockSet.macro64KB = FALSE; } // If padded size of 4KB block is larger than padded size of 256B block, // filter out 4KB block from candidate list if (blockSet.macro4KB && blockSet.micro && (padSize[AddrBlockMicro] < padSize[AddrBlock4KB])) { blockSet.macro4KB = FALSE; } } // Filter out 64KB/4KB block if a smaller block type has 2/3 or less memory footprint else if (pIn->flags.opt4space) { UINT_64 threshold = blockSet.micro ? padSize[AddrBlockMicro] : (blockSet.macro4KB ? padSize[AddrBlock4KB] : padSize[AddrBlock64KB]); threshold += threshold >> 1; if (blockSet.macro64KB && (padSize[AddrBlock64KB] > threshold)) { blockSet.macro64KB = FALSE; } if (blockSet.macro4KB && (padSize[AddrBlock4KB] > threshold)) { blockSet.macro4KB = FALSE; } } if (blockSet.value == 0) { // Bad things happen, client will not get any useful information from AddrLib. // Maybe we should fill in some output earlier instead of outputing nothing? ADDR_ASSERT_ALWAYS(); returnCode = ADDR_INVALIDPARAMS; } else { pOut->validBlockSet = blockSet; pOut->canXor = (pIn->flags.prt == FALSE) && (blockSet.macro4KB || blockSet.macro64KB || blockSet.var); if (blockSet.macro64KB || blockSet.macro4KB) { if (swType == ADDR_SW_Z) { pOut->swizzleMode = blockSet.macro64KB ? ADDR_SW_64KB_Z : ADDR_SW_4KB_Z; } else if (swType == ADDR_SW_S) { pOut->swizzleMode = blockSet.macro64KB ? ADDR_SW_64KB_S : ADDR_SW_4KB_S; } else if (swType == ADDR_SW_D) { pOut->swizzleMode = blockSet.macro64KB ? ADDR_SW_64KB_D : ADDR_SW_4KB_D; } else { ADDR_ASSERT(swType == ADDR_SW_R); pOut->swizzleMode = blockSet.macro64KB ? ADDR_SW_64KB_R : ADDR_SW_4KB_R; } if (pIn->noXor == FALSE) { if (tryPrtXor && blockSet.macro64KB) { // Client wants PRTXOR, give back _T swizzle mode if 64KB is available static const UINT_32 PrtGap = ADDR_SW_64KB_Z_T - ADDR_SW_64KB_Z; pOut->swizzleMode = static_cast(pOut->swizzleMode + PrtGap); } else if (pOut->canXor) { // Client wants XOR and this is allowed, return XOR version swizzle mode static const UINT_32 XorGap = ADDR_SW_4KB_Z_X - ADDR_SW_4KB_Z; pOut->swizzleMode = static_cast(pOut->swizzleMode + XorGap); } } } else if (blockSet.var) { // Designer consider this swizzle is usless for most cases ADDR_UNHANDLED_CASE(); } else if (blockSet.micro) { if (swType == ADDR_SW_S) { pOut->swizzleMode = ADDR_SW_256B_S; } else if (swType == ADDR_SW_D) { pOut->swizzleMode = ADDR_SW_256B_D; } else { ADDR_ASSERT(swType == ADDR_SW_R); pOut->swizzleMode = ADDR_SW_256B_R; } } else { ADDR_ASSERT(blockSet.linear); // Fall into this branch doesn't mean linear is suitable, only no other choices! pOut->swizzleMode = ADDR_SW_LINEAR; } #if DEBUG // Post sanity check, at least AddrLib should accept the output generated by its own if (pOut->swizzleMode != ADDR_SW_LINEAR) { ADDR2_COMPUTE_SURFACE_INFO_INPUT localIn = {0}; localIn.flags = pIn->flags; localIn.swizzleMode = pOut->swizzleMode; localIn.resourceType = pOut->resourceType; localIn.format = pIn->format; localIn.bpp = bpp; localIn.width = width; localIn.height = height; localIn.numSlices = slice; localIn.numMipLevels = numMipLevels; localIn.numSamples = numSamples; localIn.numFrags = numFrags; ADDR_E_RETURNCODE coherentCheck = ComputeSurfaceInfoSanityCheck(&localIn); ADDR_ASSERT(coherentCheck == ADDR_OK); // TODO : check all valid block type available in validBlockSet? } #endif } } } return returnCode; } /** **************************************************************************************************** * Lib::ComputeBlock256Equation * * @brief * Compute equation for block 256B * * @return * If equation computed successfully * **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeBlock256Equation( AddrResourceType rsrcType, AddrSwizzleMode swMode, UINT_32 elementBytesLog2, ADDR_EQUATION* pEquation) const { ADDR_E_RETURNCODE ret; if (IsBlock256b(swMode)) { ret = HwlComputeBlock256Equation(rsrcType, swMode, elementBytesLog2, pEquation); } else { ADDR_ASSERT_ALWAYS(); ret = ADDR_INVALIDPARAMS; } return ret; } /** **************************************************************************************************** * Lib::ComputeThinEquation * * @brief * Compute equation for 2D/3D resource which use THIN mode * * @return * If equation computed successfully * **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeThinEquation( AddrResourceType rsrcType, AddrSwizzleMode swMode, UINT_32 elementBytesLog2, ADDR_EQUATION* pEquation) const { ADDR_E_RETURNCODE ret; if (IsThin(rsrcType, swMode)) { ret = HwlComputeThinEquation(rsrcType, swMode, elementBytesLog2, pEquation); } else { ADDR_ASSERT_ALWAYS(); ret = ADDR_INVALIDPARAMS; } return ret; } /** **************************************************************************************************** * Lib::ComputeThickEquation * * @brief * Compute equation for 3D resource which use THICK mode * * @return * If equation computed successfully * **************************************************************************************************** */ ADDR_E_RETURNCODE Lib::ComputeThickEquation( AddrResourceType rsrcType, AddrSwizzleMode swMode, UINT_32 elementBytesLog2, ADDR_EQUATION* pEquation) const { ADDR_E_RETURNCODE ret; if (IsThick(rsrcType, swMode)) { ret = HwlComputeThickEquation(rsrcType, swMode, elementBytesLog2, pEquation); } else { ADDR_ASSERT_ALWAYS(); ret = ADDR_INVALIDPARAMS; } return ret; } } // V2 } // Addr