/* * 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 egbaddrlib.cpp * @brief Contains the EgBasedLib class implementation. **************************************************************************************************** */ #include "egbaddrlib.h" namespace Addr { namespace V1 { /** **************************************************************************************************** * EgBasedLib::EgBasedLib * * @brief * Constructor * * @note * **************************************************************************************************** */ EgBasedLib::EgBasedLib(const Client* pClient) : Lib(pClient), m_ranks(0), m_logicalBanks(0), m_bankInterleave(1) { } /** **************************************************************************************************** * EgBasedLib::~EgBasedLib * * @brief * Destructor **************************************************************************************************** */ EgBasedLib::~EgBasedLib() { } /** **************************************************************************************************** * EgBasedLib::DispatchComputeSurfaceInfo * * @brief * Compute surface sizes include padded pitch,height,slices,total size in bytes, * meanwhile output suitable tile mode and base alignment might be changed in this * call as well. Results are returned through output parameters. * * @return * TRUE if no error occurs **************************************************************************************************** */ BOOL_32 EgBasedLib::DispatchComputeSurfaceInfo( const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure ) const { AddrTileMode tileMode = pIn->tileMode; UINT_32 bpp = pIn->bpp; UINT_32 numSamples = pIn->numSamples; UINT_32 numFrags = ((pIn->numFrags == 0) ? numSamples : pIn->numFrags); UINT_32 pitch = pIn->width; UINT_32 height = pIn->height; UINT_32 numSlices = pIn->numSlices; UINT_32 mipLevel = pIn->mipLevel; ADDR_SURFACE_FLAGS flags = pIn->flags; ADDR_TILEINFO tileInfoDef = {0}; ADDR_TILEINFO* pTileInfo = &tileInfoDef; UINT_32 padDims = 0; BOOL_32 valid; tileMode = DegradeLargeThickTile(tileMode, bpp); // Only override numSamples for NI above if (m_chipFamily >= ADDR_CHIP_FAMILY_NI) { if (numFrags != numSamples) // This means EQAA { // The real surface size needed is determined by number of fragments numSamples = numFrags; } // Save altered numSamples in pOut pOut->numSamples = numSamples; } // Caller makes sure pOut->pTileInfo is not NULL, see HwlComputeSurfaceInfo ADDR_ASSERT(pOut->pTileInfo); if (pOut->pTileInfo != NULL) { pTileInfo = pOut->pTileInfo; } // Set default values if (pIn->pTileInfo != NULL) { if (pTileInfo != pIn->pTileInfo) { *pTileInfo = *pIn->pTileInfo; } } else { memset(pTileInfo, 0, sizeof(ADDR_TILEINFO)); } // For macro tile mode, we should calculate default tiling parameters HwlSetupTileInfo(tileMode, flags, bpp, pitch, height, numSamples, pIn->pTileInfo, pTileInfo, pIn->tileType, pOut); if (flags.cube) { if (mipLevel == 0) { padDims = 2; } if (numSlices == 1) { // This is calculating one face, remove cube flag flags.cube = 0; } } switch (tileMode) { case ADDR_TM_LINEAR_GENERAL://fall through case ADDR_TM_LINEAR_ALIGNED: valid = ComputeSurfaceInfoLinear(pIn, pOut, padDims); break; case ADDR_TM_1D_TILED_THIN1://fall through case ADDR_TM_1D_TILED_THICK: valid = ComputeSurfaceInfoMicroTiled(pIn, pOut, padDims, tileMode); break; case ADDR_TM_2D_TILED_THIN1: //fall through case ADDR_TM_2D_TILED_THICK: //fall through case ADDR_TM_3D_TILED_THIN1: //fall through case ADDR_TM_3D_TILED_THICK: //fall through case ADDR_TM_2D_TILED_XTHICK: //fall through case ADDR_TM_3D_TILED_XTHICK: //fall through case ADDR_TM_PRT_TILED_THIN1: //fall through case ADDR_TM_PRT_2D_TILED_THIN1://fall through case ADDR_TM_PRT_3D_TILED_THIN1://fall through case ADDR_TM_PRT_TILED_THICK: //fall through case ADDR_TM_PRT_2D_TILED_THICK://fall through case ADDR_TM_PRT_3D_TILED_THICK: valid = ComputeSurfaceInfoMacroTiled(pIn, pOut, padDims, tileMode); break; default: valid = FALSE; ADDR_ASSERT_ALWAYS(); break; } return valid; } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceInfoLinear * * @brief * Compute linear surface sizes include padded pitch, height, slices, total size in * bytes, meanwhile alignments as well. Since it is linear mode, so output tile mode * will not be changed here. Results are returned through output parameters. * * @return * TRUE if no error occurs **************************************************************************************************** */ BOOL_32 EgBasedLib::ComputeSurfaceInfoLinear( const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] Input structure ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut, ///< [out] Output structure UINT_32 padDims ///< [in] Dimensions to padd ) const { UINT_32 expPitch = pIn->width; UINT_32 expHeight = pIn->height; UINT_32 expNumSlices = pIn->numSlices; // No linear MSAA on real H/W, keep this for TGL UINT_32 numSamples = pOut->numSamples; const UINT_32 microTileThickness = 1; // // Compute the surface alignments. // ComputeSurfaceAlignmentsLinear(pIn->tileMode, pIn->bpp, pIn->flags, &pOut->baseAlign, &pOut->pitchAlign, &pOut->heightAlign); if ((pIn->tileMode == ADDR_TM_LINEAR_GENERAL) && pIn->flags.color && (pIn->height > 1)) { #if !ALT_TEST // When linear_general surface is accessed in multiple lines, it requires 8 pixels in pitch // alignment since PITCH_TILE_MAX is in unit of 8 pixels. // It is OK if it is accessed per line. ADDR_ASSERT((pIn->width % 8) == 0); #endif } pOut->depthAlign = microTileThickness; expPitch = HwlPreHandleBaseLvl3xPitch(pIn, expPitch); // // Pad pitch and height to the required granularities. // PadDimensions(pIn->tileMode, pIn->bpp, pIn->flags, numSamples, pOut->pTileInfo, padDims, pIn->mipLevel, &expPitch, &pOut->pitchAlign, &expHeight, pOut->heightAlign, &expNumSlices, microTileThickness); expPitch = HwlPostHandleBaseLvl3xPitch(pIn, expPitch); // // Adjust per HWL // UINT_64 logicalSliceSize; logicalSliceSize = HwlGetSizeAdjustmentLinear(pIn->tileMode, pIn->bpp, numSamples, pOut->baseAlign, pOut->pitchAlign, &expPitch, &expHeight, &pOut->heightAlign); if ((pIn->pitchAlign != 0) || (pIn->heightAlign != 0)) { if (pIn->pitchAlign != 0) { ADDR_ASSERT((pIn->pitchAlign % pOut->pitchAlign) == 0); pOut->pitchAlign = pIn->pitchAlign; if (IsPow2(pOut->pitchAlign)) { expPitch = PowTwoAlign(expPitch, pOut->pitchAlign); } else { expPitch += pOut->pitchAlign - 1; expPitch /= pOut->pitchAlign; expPitch *= pOut->pitchAlign; } } if (pIn->heightAlign != 0) { ADDR_ASSERT((pIn->heightAlign % pOut->heightAlign) == 0); pOut->heightAlign = pIn->heightAlign; if (IsPow2(pOut->heightAlign)) { expHeight = PowTwoAlign(expHeight, pOut->heightAlign); } else { expHeight += pOut->heightAlign - 1; expHeight /= pOut->heightAlign; expHeight *= pOut->heightAlign; } } logicalSliceSize = BITS_TO_BYTES(expPitch * expHeight * pIn->bpp); } pOut->pitch = expPitch; pOut->height = expHeight; pOut->depth = expNumSlices; pOut->surfSize = logicalSliceSize * expNumSlices; pOut->tileMode = pIn->tileMode; return TRUE; } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceInfoMicroTiled * * @brief * Compute 1D/Micro Tiled surface sizes include padded pitch, height, slices, total * size in bytes, meanwhile alignments as well. Results are returned through output * parameters. * * @return * TRUE if no error occurs **************************************************************************************************** */ BOOL_32 EgBasedLib::ComputeSurfaceInfoMicroTiled( const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] Input structure ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut, ///< [out] Output structure UINT_32 padDims, ///< [in] Dimensions to padd AddrTileMode expTileMode ///< [in] Expected tile mode ) const { BOOL_32 valid = TRUE; UINT_32 microTileThickness; UINT_32 expPitch = pIn->width; UINT_32 expHeight = pIn->height; UINT_32 expNumSlices = pIn->numSlices; // No 1D MSAA on real H/W, keep this for TGL UINT_32 numSamples = pOut->numSamples; // // Compute the micro tile thickness. // microTileThickness = Thickness(expTileMode); // // Extra override for mip levels // if (pIn->mipLevel > 0) { // // Reduce tiling mode from thick to thin if the number of slices is less than the // micro tile thickness. // if ((expTileMode == ADDR_TM_1D_TILED_THICK) && (expNumSlices < ThickTileThickness)) { expTileMode = HwlDegradeThickTileMode(ADDR_TM_1D_TILED_THICK, expNumSlices, NULL); if (expTileMode != ADDR_TM_1D_TILED_THICK) { microTileThickness = 1; } } } // // Compute the surface restrictions. // ComputeSurfaceAlignmentsMicroTiled(expTileMode, pIn->bpp, pIn->flags, pIn->mipLevel, numSamples, &pOut->baseAlign, &pOut->pitchAlign, &pOut->heightAlign); pOut->depthAlign = microTileThickness; // // Pad pitch and height to the required granularities. // Compute surface size. // Return parameters. // PadDimensions(expTileMode, pIn->bpp, pIn->flags, numSamples, pOut->pTileInfo, padDims, pIn->mipLevel, &expPitch, &pOut->pitchAlign, &expHeight, pOut->heightAlign, &expNumSlices, microTileThickness); // // Get HWL specific pitch adjustment // UINT_64 logicalSliceSize = HwlGetSizeAdjustmentMicroTiled(microTileThickness, pIn->bpp, pIn->flags, numSamples, pOut->baseAlign, pOut->pitchAlign, &expPitch, &expHeight); pOut->pitch = expPitch; pOut->height = expHeight; pOut->depth = expNumSlices; pOut->surfSize = logicalSliceSize * expNumSlices; pOut->tileMode = expTileMode; return valid; } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceInfoMacroTiled * * @brief * Compute 2D/macro tiled surface sizes include padded pitch, height, slices, total * size in bytes, meanwhile output suitable tile mode and alignments might be changed * in this call as well. Results are returned through output parameters. * * @return * TRUE if no error occurs **************************************************************************************************** */ BOOL_32 EgBasedLib::ComputeSurfaceInfoMacroTiled( const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] Input structure ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut, ///< [out] Output structure UINT_32 padDims, ///< [in] Dimensions to padd AddrTileMode expTileMode ///< [in] Expected tile mode ) const { BOOL_32 valid = TRUE; AddrTileMode origTileMode = expTileMode; UINT_32 microTileThickness; UINT_32 paddedPitch; UINT_32 paddedHeight; UINT_64 bytesPerSlice; UINT_32 expPitch = pIn->width; UINT_32 expHeight = pIn->height; UINT_32 expNumSlices = pIn->numSlices; UINT_32 numSamples = pOut->numSamples; // // Compute the surface restrictions as base // SanityCheckMacroTiled is called in ComputeSurfaceAlignmentsMacroTiled // valid = ComputeSurfaceAlignmentsMacroTiled(expTileMode, pIn->bpp, pIn->flags, pIn->mipLevel, numSamples, pOut); if (valid) { // // Compute the micro tile thickness. // microTileThickness = Thickness(expTileMode); // // Find the correct tiling mode for mip levels // if (pIn->mipLevel > 0) { // // Try valid tile mode // expTileMode = ComputeSurfaceMipLevelTileMode(expTileMode, pIn->bpp, expPitch, expHeight, expNumSlices, numSamples, pOut->blockWidth, pOut->blockHeight, pOut->pTileInfo); if (!IsMacroTiled(expTileMode)) // Downgraded to micro-tiled { return ComputeSurfaceInfoMicroTiled(pIn, pOut, padDims, expTileMode); } else if (microTileThickness != Thickness(expTileMode)) { // // Re-compute if thickness changed since bank-height may be changed! // return ComputeSurfaceInfoMacroTiled(pIn, pOut, padDims, expTileMode); } } paddedPitch = expPitch; paddedHeight = expHeight; // // Re-cal alignment // if (expTileMode != origTileMode) // Tile mode is changed but still macro-tiled { valid = ComputeSurfaceAlignmentsMacroTiled(expTileMode, pIn->bpp, pIn->flags, pIn->mipLevel, numSamples, pOut); } // // Do padding // PadDimensions(expTileMode, pIn->bpp, pIn->flags, numSamples, pOut->pTileInfo, padDims, pIn->mipLevel, &paddedPitch, &pOut->pitchAlign, &paddedHeight, pOut->heightAlign, &expNumSlices, microTileThickness); if (pIn->flags.qbStereo && (pOut->pStereoInfo != NULL)) { UINT_32 stereoHeightAlign = HwlStereoCheckRightOffsetPadding(pOut->pTileInfo); if (stereoHeightAlign != 0) { paddedHeight = PowTwoAlign(paddedHeight, stereoHeightAlign); } } if ((pIn->flags.needEquation == TRUE) && (m_chipFamily == ADDR_CHIP_FAMILY_SI) && (pIn->numMipLevels > 1) && (pIn->mipLevel == 0)) { BOOL_32 convertTo1D = FALSE; ADDR_ASSERT(Thickness(expTileMode) == 1); for (UINT_32 i = 1; i < pIn->numMipLevels; i++) { UINT_32 mipPitch = Max(1u, paddedPitch >> i); UINT_32 mipHeight = Max(1u, pIn->height >> i); UINT_32 mipSlices = pIn->flags.volume ? Max(1u, pIn->numSlices >> i) : pIn->numSlices; expTileMode = ComputeSurfaceMipLevelTileMode(expTileMode, pIn->bpp, mipPitch, mipHeight, mipSlices, numSamples, pOut->blockWidth, pOut->blockHeight, pOut->pTileInfo); if (IsMacroTiled(expTileMode)) { if (PowTwoAlign(mipPitch, pOut->blockWidth) != PowTwoAlign(mipPitch, pOut->pitchAlign)) { convertTo1D = TRUE; break; } } else { break; } } if (convertTo1D) { return ComputeSurfaceInfoMicroTiled(pIn, pOut, padDims, ADDR_TM_1D_TILED_THIN1); } } pOut->pitch = paddedPitch; // Put this check right here to workaround special mipmap cases which the original height // is needed. // The original height is pre-stored in pOut->height in PostComputeMipLevel and // pOut->pitch is needed in HwlCheckLastMacroTiledLvl, too. if (m_configFlags.checkLast2DLevel && (numSamples == 1)) // Don't check MSAA { // Set a TRUE in pOut if next Level is the first 1D sub level HwlCheckLastMacroTiledLvl(pIn, pOut); } pOut->height = paddedHeight; pOut->depth = expNumSlices; // // Compute the size of a slice. // bytesPerSlice = BITS_TO_BYTES(static_cast(paddedPitch) * paddedHeight * NextPow2(pIn->bpp) * numSamples); pOut->surfSize = bytesPerSlice * expNumSlices; pOut->tileMode = expTileMode; pOut->depthAlign = microTileThickness; } // if (valid) return valid; } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceAlignmentsLinear * * @brief * Compute linear surface alignment, calculation results are returned through * output parameters. * * @return * TRUE if no error occurs **************************************************************************************************** */ BOOL_32 EgBasedLib::ComputeSurfaceAlignmentsLinear( AddrTileMode tileMode, ///< [in] tile mode UINT_32 bpp, ///< [in] bits per pixel ADDR_SURFACE_FLAGS flags, ///< [in] surface flags UINT_32* pBaseAlign, ///< [out] base address alignment in bytes UINT_32* pPitchAlign, ///< [out] pitch alignment in pixels UINT_32* pHeightAlign ///< [out] height alignment in pixels ) const { BOOL_32 valid = TRUE; switch (tileMode) { case ADDR_TM_LINEAR_GENERAL: // // The required base alignment and pitch and height granularities is to 1 element. // *pBaseAlign = (bpp > 8) ? bpp / 8 : 1; *pPitchAlign = 1; *pHeightAlign = 1; break; case ADDR_TM_LINEAR_ALIGNED: // // The required alignment for base is the pipe interleave size. // The required granularity for pitch is hwl dependent. // The required granularity for height is one row. // *pBaseAlign = m_pipeInterleaveBytes; *pPitchAlign = HwlGetPitchAlignmentLinear(bpp, flags); *pHeightAlign = 1; break; default: *pBaseAlign = 1; *pPitchAlign = 1; *pHeightAlign = 1; ADDR_UNHANDLED_CASE(); break; } AdjustPitchAlignment(flags, pPitchAlign); return valid; } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceAlignmentsMicroTiled * * @brief * Compute 1D tiled surface alignment, calculation results are returned through * output parameters. * * @return * TRUE if no error occurs **************************************************************************************************** */ BOOL_32 EgBasedLib::ComputeSurfaceAlignmentsMicroTiled( AddrTileMode tileMode, ///< [in] tile mode UINT_32 bpp, ///< [in] bits per pixel ADDR_SURFACE_FLAGS flags, ///< [in] surface flags UINT_32 mipLevel, ///< [in] mip level UINT_32 numSamples, ///< [in] number of samples UINT_32* pBaseAlign, ///< [out] base address alignment in bytes UINT_32* pPitchAlign, ///< [out] pitch alignment in pixels UINT_32* pHeightAlign ///< [out] height alignment in pixels ) const { BOOL_32 valid = TRUE; // // The required alignment for base is the pipe interleave size. // *pBaseAlign = m_pipeInterleaveBytes; *pPitchAlign = HwlGetPitchAlignmentMicroTiled(tileMode, bpp, flags, numSamples); *pHeightAlign = MicroTileHeight; AdjustPitchAlignment(flags, pPitchAlign); // Workaround 2 for 1D tiling - There is HW bug for Carrizo, // where it requires the following alignments for 1D tiling. if (flags.czDispCompatible && (mipLevel == 0)) { *pBaseAlign = PowTwoAlign(*pBaseAlign, 4096); //Base address MOD 4096 = 0 *pPitchAlign = PowTwoAlign(*pPitchAlign, 512 / (BITS_TO_BYTES(bpp))); //(8 lines * pitch * bytes per pixel) MOD 4096 = 0 } // end Carrizo workaround for 1D tilling return valid; } /** **************************************************************************************************** * EgBasedLib::HwlReduceBankWidthHeight * * @brief * Additional checks, reduce bankHeight/bankWidth if needed and possible * tileSize*BANK_WIDTH*BANK_HEIGHT <= ROW_SIZE * * @return * TRUE if no error occurs **************************************************************************************************** */ BOOL_32 EgBasedLib::HwlReduceBankWidthHeight( UINT_32 tileSize, ///< [in] tile size UINT_32 bpp, ///< [in] bits per pixel ADDR_SURFACE_FLAGS flags, ///< [in] surface flags UINT_32 numSamples, ///< [in] number of samples UINT_32 bankHeightAlign, ///< [in] bank height alignment UINT_32 pipes, ///< [in] pipes ADDR_TILEINFO* pTileInfo ///< [in,out] bank structure. ) const { UINT_32 macroAspectAlign; BOOL_32 valid = TRUE; if (tileSize * pTileInfo->bankWidth * pTileInfo->bankHeight > m_rowSize) { BOOL_32 stillGreater = TRUE; // Try reducing bankWidth first if (stillGreater && pTileInfo->bankWidth > 1) { while (stillGreater && pTileInfo->bankWidth > 0) { pTileInfo->bankWidth >>= 1; if (pTileInfo->bankWidth == 0) { pTileInfo->bankWidth = 1; break; } stillGreater = tileSize * pTileInfo->bankWidth * pTileInfo->bankHeight > m_rowSize; } // bankWidth is reduced above, so we need to recalculate bankHeight and ratio bankHeightAlign = Max(1u, m_pipeInterleaveBytes * m_bankInterleave / (tileSize * pTileInfo->bankWidth) ); // We cannot increase bankHeight so just assert this case. ADDR_ASSERT((pTileInfo->bankHeight % bankHeightAlign) == 0); if (numSamples == 1) { macroAspectAlign = Max(1u, m_pipeInterleaveBytes * m_bankInterleave / (tileSize * pipes * pTileInfo->bankWidth) ); pTileInfo->macroAspectRatio = PowTwoAlign(pTileInfo->macroAspectRatio, macroAspectAlign); } } // Early quit bank_height degradation for "64" bit z buffer if (flags.depth && bpp >= 64) { stillGreater = FALSE; } // Then try reducing bankHeight if (stillGreater && pTileInfo->bankHeight > bankHeightAlign) { while (stillGreater && pTileInfo->bankHeight > bankHeightAlign) { pTileInfo->bankHeight >>= 1; if (pTileInfo->bankHeight < bankHeightAlign) { pTileInfo->bankHeight = bankHeightAlign; break; } stillGreater = tileSize * pTileInfo->bankWidth * pTileInfo->bankHeight > m_rowSize; } } valid = !stillGreater; // Generate a warning if we still fail to meet this constraint if (valid == FALSE) { ADDR_WARN( 0, ("TILE_SIZE(%d)*BANK_WIDTH(%d)*BANK_HEIGHT(%d) <= ROW_SIZE(%d)", tileSize, pTileInfo->bankWidth, pTileInfo->bankHeight, m_rowSize)); } } return valid; } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceAlignmentsMacroTiled * * @brief * Compute 2D tiled surface alignment, calculation results are returned through * output parameters. * * @return * TRUE if no error occurs **************************************************************************************************** */ BOOL_32 EgBasedLib::ComputeSurfaceAlignmentsMacroTiled( AddrTileMode tileMode, ///< [in] tile mode UINT_32 bpp, ///< [in] bits per pixel ADDR_SURFACE_FLAGS flags, ///< [in] surface flags UINT_32 mipLevel, ///< [in] mip level UINT_32 numSamples, ///< [in] number of samples ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [in,out] Surface output ) const { ADDR_TILEINFO* pTileInfo = pOut->pTileInfo; BOOL_32 valid = SanityCheckMacroTiled(pTileInfo); if (valid) { UINT_32 macroTileWidth; UINT_32 macroTileHeight; UINT_32 tileSize; UINT_32 bankHeightAlign; UINT_32 macroAspectAlign; UINT_32 thickness = Thickness(tileMode); UINT_32 pipes = HwlGetPipes(pTileInfo); // // Align bank height first according to latest h/w spec // // tile_size = MIN(tile_split, 64 * tile_thickness * element_bytes * num_samples) tileSize = Min(pTileInfo->tileSplitBytes, BITS_TO_BYTES(64 * thickness * bpp * numSamples)); // bank_height_align = // MAX(1, (pipe_interleave_bytes * bank_interleave)/(tile_size*bank_width)) bankHeightAlign = Max(1u, m_pipeInterleaveBytes * m_bankInterleave / (tileSize * pTileInfo->bankWidth) ); pTileInfo->bankHeight = PowTwoAlign(pTileInfo->bankHeight, bankHeightAlign); // num_pipes * bank_width * macro_tile_aspect >= // (pipe_interleave_size * bank_interleave) / tile_size if (numSamples == 1) { // this restriction is only for mipmap (mipmap's numSamples must be 1) macroAspectAlign = Max(1u, m_pipeInterleaveBytes * m_bankInterleave / (tileSize * pipes * pTileInfo->bankWidth) ); pTileInfo->macroAspectRatio = PowTwoAlign(pTileInfo->macroAspectRatio, macroAspectAlign); } valid = HwlReduceBankWidthHeight(tileSize, bpp, flags, numSamples, bankHeightAlign, pipes, pTileInfo); // // The required granularity for pitch is the macro tile width. // macroTileWidth = MicroTileWidth * pTileInfo->bankWidth * pipes * pTileInfo->macroAspectRatio; pOut->pitchAlign = macroTileWidth; pOut->blockWidth = macroTileWidth; AdjustPitchAlignment(flags, &pOut->pitchAlign); // // The required granularity for height is the macro tile height. // macroTileHeight = MicroTileHeight * pTileInfo->bankHeight * pTileInfo->banks / pTileInfo->macroAspectRatio; pOut->heightAlign = macroTileHeight; pOut->blockHeight = macroTileHeight; // // Compute base alignment // pOut->baseAlign = pipes * pTileInfo->bankWidth * pTileInfo->banks * pTileInfo->bankHeight * tileSize; HwlComputeSurfaceAlignmentsMacroTiled(tileMode, bpp, flags, mipLevel, numSamples, pOut); } return valid; } /** **************************************************************************************************** * EgBasedLib::SanityCheckMacroTiled * * @brief * Check if macro-tiled parameters are valid * @return * TRUE if valid **************************************************************************************************** */ BOOL_32 EgBasedLib::SanityCheckMacroTiled( ADDR_TILEINFO* pTileInfo ///< [in] macro-tiled parameters ) const { BOOL_32 valid = TRUE; UINT_32 numPipes = HwlGetPipes(pTileInfo); switch (pTileInfo->banks) { case 2: //fall through case 4: //fall through case 8: //fall through case 16: break; default: valid = FALSE; break; } if (valid) { switch (pTileInfo->bankWidth) { case 1: //fall through case 2: //fall through case 4: //fall through case 8: break; default: valid = FALSE; break; } } if (valid) { switch (pTileInfo->bankHeight) { case 1: //fall through case 2: //fall through case 4: //fall through case 8: break; default: valid = FALSE; break; } } if (valid) { switch (pTileInfo->macroAspectRatio) { case 1: //fall through case 2: //fall through case 4: //fall through case 8: break; default: valid = FALSE; break; } } if (valid) { if (pTileInfo->banks < pTileInfo->macroAspectRatio) { // This will generate macro tile height <= 1 valid = FALSE; } } if (valid) { if (pTileInfo->tileSplitBytes > m_rowSize) { ADDR_WARN(0, ("tileSplitBytes is bigger than row size")); } } if (valid) { valid = HwlSanityCheckMacroTiled(pTileInfo); } ADDR_ASSERT(valid == TRUE); // Add this assert for guidance ADDR_ASSERT(numPipes * pTileInfo->banks >= 4); return valid; } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceMipLevelTileMode * * @brief * Compute valid tile mode for surface mipmap sub-levels * * @return * Suitable tile mode **************************************************************************************************** */ AddrTileMode EgBasedLib::ComputeSurfaceMipLevelTileMode( AddrTileMode baseTileMode, ///< [in] base tile mode UINT_32 bpp, ///< [in] bits per pixels UINT_32 pitch, ///< [in] current level pitch UINT_32 height, ///< [in] current level height UINT_32 numSlices, ///< [in] current number of slices UINT_32 numSamples, ///< [in] number of samples UINT_32 pitchAlign, ///< [in] pitch alignment UINT_32 heightAlign, ///< [in] height alignment ADDR_TILEINFO* pTileInfo ///< [in] ptr to bank structure ) const { UINT_64 bytesPerSlice; (void)bytesPerSlice; UINT_32 bytesPerTile; AddrTileMode expTileMode = baseTileMode; UINT_32 microTileThickness = Thickness(expTileMode); UINT_32 interleaveSize = m_pipeInterleaveBytes * m_bankInterleave; // // Compute the size of a slice. // bytesPerSlice = BITS_TO_BYTES(static_cast(pitch) * height * bpp * numSamples); bytesPerTile = BITS_TO_BYTES(MicroTilePixels * microTileThickness * NextPow2(bpp) * numSamples); // // Reduce tiling mode from thick to thin if the number of slices is less than the // micro tile thickness. // if (numSlices < microTileThickness) { expTileMode = HwlDegradeThickTileMode(expTileMode, numSlices, &bytesPerTile); } if (bytesPerTile > pTileInfo->tileSplitBytes) { bytesPerTile = pTileInfo->tileSplitBytes; } UINT_32 threshold1 = bytesPerTile * HwlGetPipes(pTileInfo) * pTileInfo->bankWidth * pTileInfo->macroAspectRatio; UINT_32 threshold2 = bytesPerTile * pTileInfo->bankWidth * pTileInfo->bankHeight; // // Reduce the tile mode from 2D/3D to 1D in following conditions // switch (expTileMode) { case ADDR_TM_2D_TILED_THIN1: //fall through case ADDR_TM_3D_TILED_THIN1: case ADDR_TM_PRT_TILED_THIN1: case ADDR_TM_PRT_2D_TILED_THIN1: case ADDR_TM_PRT_3D_TILED_THIN1: if ((pitch < pitchAlign) || (height < heightAlign) || (interleaveSize > threshold1) || (interleaveSize > threshold2)) { expTileMode = ADDR_TM_1D_TILED_THIN1; } break; case ADDR_TM_2D_TILED_THICK: //fall through case ADDR_TM_3D_TILED_THICK: case ADDR_TM_2D_TILED_XTHICK: case ADDR_TM_3D_TILED_XTHICK: case ADDR_TM_PRT_TILED_THICK: case ADDR_TM_PRT_2D_TILED_THICK: case ADDR_TM_PRT_3D_TILED_THICK: if ((pitch < pitchAlign) || (height < heightAlign)) { expTileMode = ADDR_TM_1D_TILED_THICK; } break; default: break; } return expTileMode; } /** **************************************************************************************************** * EgBasedLib::HwlGetAlignmentInfoMacroTiled * @brief * Get alignment info for giving tile mode * @return * TRUE if getting alignment is OK **************************************************************************************************** */ BOOL_32 EgBasedLib::HwlGetAlignmentInfoMacroTiled( const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] create surface info UINT_32* pPitchAlign, ///< [out] pitch alignment UINT_32* pHeightAlign, ///< [out] height alignment UINT_32* pSizeAlign ///< [out] size alignment ) const { BOOL_32 valid = TRUE; ADDR_ASSERT(IsMacroTiled(pIn->tileMode)); UINT_32 numSamples = (pIn->numFrags == 0) ? pIn->numSamples : pIn->numFrags; ADDR_ASSERT(pIn->pTileInfo); ADDR_TILEINFO tileInfo = *pIn->pTileInfo; ADDR_COMPUTE_SURFACE_INFO_OUTPUT out = {0}; out.pTileInfo = &tileInfo; if (UseTileIndex(pIn->tileIndex)) { out.tileIndex = pIn->tileIndex; out.macroModeIndex = TileIndexInvalid; } HwlSetupTileInfo(pIn->tileMode, pIn->flags, pIn->bpp, pIn->width, pIn->height, numSamples, &tileInfo, &tileInfo, pIn->tileType, &out); valid = ComputeSurfaceAlignmentsMacroTiled(pIn->tileMode, pIn->bpp, pIn->flags, pIn->mipLevel, numSamples, &out); if (valid) { *pPitchAlign = out.pitchAlign; *pHeightAlign = out.heightAlign; *pSizeAlign = out.baseAlign; } return valid; } /** **************************************************************************************************** * EgBasedLib::HwlDegradeThickTileMode * * @brief * Degrades valid tile mode for thick modes if needed * * @return * Suitable tile mode **************************************************************************************************** */ AddrTileMode EgBasedLib::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 { ADDR_ASSERT(numSlices < Thickness(baseTileMode)); // if pBytesPerTile is NULL, this is a don't-care.... UINT_32 bytesPerTile = pBytesPerTile != NULL ? *pBytesPerTile : 64; AddrTileMode expTileMode = baseTileMode; switch (baseTileMode) { case ADDR_TM_1D_TILED_THICK: expTileMode = ADDR_TM_1D_TILED_THIN1; bytesPerTile >>= 2; break; case ADDR_TM_2D_TILED_THICK: expTileMode = ADDR_TM_2D_TILED_THIN1; bytesPerTile >>= 2; break; case ADDR_TM_3D_TILED_THICK: expTileMode = ADDR_TM_3D_TILED_THIN1; bytesPerTile >>= 2; break; case ADDR_TM_2D_TILED_XTHICK: if (numSlices < ThickTileThickness) { expTileMode = ADDR_TM_2D_TILED_THIN1; bytesPerTile >>= 3; } else { expTileMode = ADDR_TM_2D_TILED_THICK; bytesPerTile >>= 1; } break; case ADDR_TM_3D_TILED_XTHICK: if (numSlices < ThickTileThickness) { expTileMode = ADDR_TM_3D_TILED_THIN1; bytesPerTile >>= 3; } else { expTileMode = ADDR_TM_3D_TILED_THICK; bytesPerTile >>= 1; } break; default: ADDR_ASSERT_ALWAYS(); break; } if (pBytesPerTile != NULL) { *pBytesPerTile = bytesPerTile; } return expTileMode; } /** **************************************************************************************************** * EgBasedLib::DispatchComputeSurfaceAddrFromCoord * * @brief * Compute surface address from given coord (x, y, slice,sample) * * @return * Address in bytes **************************************************************************************************** */ UINT_64 EgBasedLib::DispatchComputeSurfaceAddrFromCoord( const ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT* pIn, ///< [in] input structure ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT* pOut ///< [out] output structure ) const { UINT_32 x = pIn->x; UINT_32 y = pIn->y; UINT_32 slice = pIn->slice; UINT_32 sample = pIn->sample; UINT_32 bpp = pIn->bpp; UINT_32 pitch = pIn->pitch; UINT_32 height = pIn->height; UINT_32 numSlices = pIn->numSlices; UINT_32 numSamples = ((pIn->numSamples == 0) ? 1 : pIn->numSamples); UINT_32 numFrags = ((pIn->numFrags == 0) ? numSamples : pIn->numFrags); AddrTileMode tileMode = pIn->tileMode; AddrTileType microTileType = pIn->tileType; BOOL_32 ignoreSE = pIn->ignoreSE; BOOL_32 isDepthSampleOrder = pIn->isDepth; ADDR_TILEINFO* pTileInfo = pIn->pTileInfo; UINT_32* pBitPosition = &pOut->bitPosition; UINT_64 addr; // ADDR_DEPTH_SAMPLE_ORDER = non-disp + depth-sample-order if (microTileType == ADDR_DEPTH_SAMPLE_ORDER) { isDepthSampleOrder = TRUE; } if (m_chipFamily >= ADDR_CHIP_FAMILY_NI) { if (numFrags != numSamples) { numSamples = numFrags; ADDR_ASSERT(sample < numSamples); } /// @note /// 128 bit/thick tiled surface doesn't support display tiling and /// mipmap chain must have the same tileType, so please fill tileType correctly if (IsLinear(pIn->tileMode) == FALSE) { if (bpp >= 128 || Thickness(tileMode) > 1) { ADDR_ASSERT(microTileType != ADDR_DISPLAYABLE); } } } switch (tileMode) { case ADDR_TM_LINEAR_GENERAL://fall through case ADDR_TM_LINEAR_ALIGNED: addr = ComputeSurfaceAddrFromCoordLinear(x, y, slice, sample, bpp, pitch, height, numSlices, pBitPosition); break; case ADDR_TM_1D_TILED_THIN1://fall through case ADDR_TM_1D_TILED_THICK: addr = ComputeSurfaceAddrFromCoordMicroTiled(x, y, slice, sample, bpp, pitch, height, numSamples, tileMode, microTileType, isDepthSampleOrder, pBitPosition); break; case ADDR_TM_2D_TILED_THIN1: //fall through case ADDR_TM_2D_TILED_THICK: //fall through case ADDR_TM_3D_TILED_THIN1: //fall through case ADDR_TM_3D_TILED_THICK: //fall through case ADDR_TM_2D_TILED_XTHICK: //fall through case ADDR_TM_3D_TILED_XTHICK: //fall through case ADDR_TM_PRT_TILED_THIN1: //fall through case ADDR_TM_PRT_2D_TILED_THIN1://fall through case ADDR_TM_PRT_3D_TILED_THIN1://fall through case ADDR_TM_PRT_TILED_THICK: //fall through case ADDR_TM_PRT_2D_TILED_THICK://fall through case ADDR_TM_PRT_3D_TILED_THICK: UINT_32 pipeSwizzle; UINT_32 bankSwizzle; if (m_configFlags.useCombinedSwizzle) { ExtractBankPipeSwizzle(pIn->tileSwizzle, pIn->pTileInfo, &bankSwizzle, &pipeSwizzle); } else { pipeSwizzle = pIn->pipeSwizzle; bankSwizzle = pIn->bankSwizzle; } addr = ComputeSurfaceAddrFromCoordMacroTiled(x, y, slice, sample, bpp, pitch, height, numSamples, tileMode, microTileType, ignoreSE, isDepthSampleOrder, pipeSwizzle, bankSwizzle, pTileInfo, pBitPosition); break; default: addr = 0; ADDR_ASSERT_ALWAYS(); break; } return addr; } /** **************************************************************************************************** * EgBasedLib::ComputeMacroTileEquation * * @brief * Computes the address equation in macro tile * @return * If equation can be computed **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::ComputeMacroTileEquation( UINT_32 log2BytesPP, ///< [in] log2 of bytes per pixel AddrTileMode tileMode, ///< [in] tile mode AddrTileType microTileType, ///< [in] micro tiling type ADDR_TILEINFO* pTileInfo, ///< [in] bank structure ADDR_EQUATION* pEquation ///< [out] Equation for addressing in macro tile ) const { ADDR_E_RETURNCODE retCode; // Element equation within a tile retCode = ComputeMicroTileEquation(log2BytesPP, tileMode, microTileType, pEquation); if (retCode == ADDR_OK) { // Tile equesiton with signle pipe bank UINT_32 numPipes = HwlGetPipes(pTileInfo); UINT_32 numPipeBits = Log2(numPipes); for (UINT_32 i = 0; i < Log2(pTileInfo->bankWidth); i++) { pEquation->addr[pEquation->numBits].valid = 1; pEquation->addr[pEquation->numBits].channel = 0; pEquation->addr[pEquation->numBits].index = i + log2BytesPP + 3 + numPipeBits; pEquation->numBits++; } for (UINT_32 i = 0; i < Log2(pTileInfo->bankHeight); i++) { pEquation->addr[pEquation->numBits].valid = 1; pEquation->addr[pEquation->numBits].channel = 1; pEquation->addr[pEquation->numBits].index = i + 3; pEquation->numBits++; } ADDR_EQUATION equation; memset(&equation, 0, sizeof(ADDR_EQUATION)); UINT_32 thresholdX = 32; UINT_32 thresholdY = 32; if (IsPrtNoRotationTileMode(tileMode)) { UINT_32 macroTilePitch = (MicroTileWidth * pTileInfo->bankWidth * numPipes) * pTileInfo->macroAspectRatio; UINT_32 macroTileHeight = (MicroTileHeight * pTileInfo->bankHeight * pTileInfo->banks) / pTileInfo->macroAspectRatio; thresholdX = Log2(macroTilePitch); thresholdY = Log2(macroTileHeight); } // Pipe equation retCode = ComputePipeEquation(log2BytesPP, thresholdX, thresholdY, pTileInfo, &equation); if (retCode == ADDR_OK) { UINT_32 pipeBitStart = Log2(m_pipeInterleaveBytes); if (pEquation->numBits > pipeBitStart) { UINT_32 numLeftShift = pEquation->numBits - pipeBitStart; for (UINT_32 i = 0; i < numLeftShift; i++) { pEquation->addr[pEquation->numBits + equation.numBits - i - 1] = pEquation->addr[pEquation->numBits - i - 1]; pEquation->xor1[pEquation->numBits + equation.numBits - i - 1] = pEquation->xor1[pEquation->numBits - i - 1]; pEquation->xor2[pEquation->numBits + equation.numBits - i - 1] = pEquation->xor2[pEquation->numBits - i - 1]; } } for (UINT_32 i = 0; i < equation.numBits; i++) { pEquation->addr[pipeBitStart + i] = equation.addr[i]; pEquation->xor1[pipeBitStart + i] = equation.xor1[i]; pEquation->xor2[pipeBitStart + i] = equation.xor2[i]; pEquation->numBits++; } // Bank equation memset(&equation, 0, sizeof(ADDR_EQUATION)); retCode = ComputeBankEquation(log2BytesPP, thresholdX, thresholdY, pTileInfo, &equation); if (retCode == ADDR_OK) { UINT_32 bankBitStart = pipeBitStart + numPipeBits + Log2(m_bankInterleave); if (pEquation->numBits > bankBitStart) { UINT_32 numLeftShift = pEquation->numBits - bankBitStart; for (UINT_32 i = 0; i < numLeftShift; i++) { pEquation->addr[pEquation->numBits + equation.numBits - i - 1] = pEquation->addr[pEquation->numBits - i - 1]; pEquation->xor1[pEquation->numBits + equation.numBits - i - 1] = pEquation->xor1[pEquation->numBits - i - 1]; pEquation->xor2[pEquation->numBits + equation.numBits - i - 1] = pEquation->xor2[pEquation->numBits - i - 1]; } } for (UINT_32 i = 0; i < equation.numBits; i++) { pEquation->addr[bankBitStart + i] = equation.addr[i]; pEquation->xor1[bankBitStart + i] = equation.xor1[i]; pEquation->xor2[bankBitStart + i] = equation.xor2[i]; pEquation->numBits++; } } } } return retCode; } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceAddrFromCoordMicroTiled * * @brief * Computes the surface address and bit position from a * coordinate for 2D tilied (macro tiled) * @return * The byte address **************************************************************************************************** */ UINT_64 EgBasedLib::ComputeSurfaceAddrFromCoordMacroTiled( UINT_32 x, ///< [in] x coordinate UINT_32 y, ///< [in] y coordinate UINT_32 slice, ///< [in] slice index UINT_32 sample, ///< [in] sample index UINT_32 bpp, ///< [in] bits per pixel UINT_32 pitch, ///< [in] surface pitch, in pixels UINT_32 height, ///< [in] surface height, in pixels UINT_32 numSamples, ///< [in] number of samples AddrTileMode tileMode, ///< [in] tile mode AddrTileType microTileType, ///< [in] micro tiling type BOOL_32 ignoreSE, ///< [in] TRUE if shader enginers can be ignored BOOL_32 isDepthSampleOrder, ///< [in] TRUE if it depth sample ordering is used UINT_32 pipeSwizzle, ///< [in] pipe swizzle UINT_32 bankSwizzle, ///< [in] bank swizzle ADDR_TILEINFO* pTileInfo, ///< [in] bank structure /// **All fields to be valid on entry** UINT_32* pBitPosition ///< [out] bit position, e.g. FMT_1 will use this ) const { UINT_64 addr; UINT_32 microTileBytes; UINT_32 microTileBits; UINT_32 sampleOffset; UINT_32 pixelIndex; UINT_32 pixelOffset; UINT_32 elementOffset; UINT_32 tileSplitSlice; UINT_32 pipe; UINT_32 bank; UINT_64 sliceBytes; UINT_64 sliceOffset; UINT_32 macroTilePitch; UINT_32 macroTileHeight; UINT_32 macroTilesPerRow; UINT_32 macroTilesPerSlice; UINT_64 macroTileBytes; UINT_32 macroTileIndexX; UINT_32 macroTileIndexY; UINT_64 macroTileOffset; UINT_64 totalOffset; UINT_64 pipeInterleaveMask; UINT_64 bankInterleaveMask; UINT_64 pipeInterleaveOffset; UINT_32 bankInterleaveOffset; UINT_64 offset; UINT_32 tileRowIndex; UINT_32 tileColumnIndex; UINT_32 tileIndex; UINT_32 tileOffset; UINT_32 microTileThickness = Thickness(tileMode); // // Compute the number of group, pipe, and bank bits. // UINT_32 numPipes = HwlGetPipes(pTileInfo); UINT_32 numPipeInterleaveBits = Log2(m_pipeInterleaveBytes); UINT_32 numPipeBits = Log2(numPipes); UINT_32 numBankInterleaveBits = Log2(m_bankInterleave); UINT_32 numBankBits = Log2(pTileInfo->banks); // // Compute the micro tile size. // microTileBits = MicroTilePixels * microTileThickness * bpp * numSamples; microTileBytes = microTileBits / 8; // // Compute the pixel index within the micro tile. // pixelIndex = ComputePixelIndexWithinMicroTile(x, y, slice, bpp, tileMode, microTileType); // // Compute the sample offset and pixel offset. // if (isDepthSampleOrder) { // // For depth surfaces, samples are stored contiguously for each element, so the sample // offset is the sample number times the element size. // sampleOffset = sample * bpp; pixelOffset = pixelIndex * bpp * numSamples; } else { // // For color surfaces, all elements for a particular sample are stored contiguously, so // the sample offset is the sample number times the micro tile size divided yBit the number // of samples. // sampleOffset = sample * (microTileBits / numSamples); pixelOffset = pixelIndex * bpp; } // // Compute the element offset. // elementOffset = pixelOffset + sampleOffset; *pBitPosition = static_cast(elementOffset % 8); elementOffset /= 8; //bit-to-byte // // Determine if tiles need to be split across slices. // // If the size of the micro tile is larger than the tile split size, then the tile will be // split across multiple slices. // UINT_32 slicesPerTile = 1; if ((microTileBytes > pTileInfo->tileSplitBytes) && (microTileThickness == 1)) { //don't support for thick mode // // Compute the number of slices per tile. // slicesPerTile = microTileBytes / pTileInfo->tileSplitBytes; // // Compute the tile split slice number for use in rotating the bank. // tileSplitSlice = elementOffset / pTileInfo->tileSplitBytes; // // Adjust the element offset to account for the portion of the tile that is being moved to // a new slice.. // elementOffset %= pTileInfo->tileSplitBytes; // // Adjust the microTileBytes size to tileSplitBytes size since // a new slice.. // microTileBytes = pTileInfo->tileSplitBytes; } else { tileSplitSlice = 0; } // // Compute macro tile pitch and height. // macroTilePitch = (MicroTileWidth * pTileInfo->bankWidth * numPipes) * pTileInfo->macroAspectRatio; macroTileHeight = (MicroTileHeight * pTileInfo->bankHeight * pTileInfo->banks) / pTileInfo->macroAspectRatio; // // Compute the number of bytes per macro tile. Note: bytes of the same bank/pipe actually // macroTileBytes = static_cast(microTileBytes) * (macroTilePitch / MicroTileWidth) * (macroTileHeight / MicroTileHeight) / (numPipes * pTileInfo->banks); // // Compute the number of macro tiles per row. // macroTilesPerRow = pitch / macroTilePitch; // // Compute the offset to the macro tile containing the specified coordinate. // macroTileIndexX = x / macroTilePitch; macroTileIndexY = y / macroTileHeight; macroTileOffset = ((macroTileIndexY * macroTilesPerRow) + macroTileIndexX) * macroTileBytes; // // Compute the number of macro tiles per slice. // macroTilesPerSlice = macroTilesPerRow * (height / macroTileHeight); // // Compute the slice size. // sliceBytes = macroTilesPerSlice * macroTileBytes; // // Compute the slice offset. // sliceOffset = sliceBytes * (tileSplitSlice + slicesPerTile * (slice / microTileThickness)); // // Compute tile offest // tileRowIndex = (y / MicroTileHeight) % pTileInfo->bankHeight; tileColumnIndex = ((x / MicroTileWidth) / numPipes) % pTileInfo->bankWidth; tileIndex = (tileRowIndex * pTileInfo->bankWidth) + tileColumnIndex; tileOffset = tileIndex * microTileBytes; // // Combine the slice offset and macro tile offset with the pixel and sample offsets, accounting // for the pipe and bank bits in the middle of the address. // totalOffset = sliceOffset + macroTileOffset + elementOffset + tileOffset; // // Get the pipe and bank. // // when the tileMode is PRT type, then adjust x and y coordinates if (IsPrtNoRotationTileMode(tileMode)) { x = x % macroTilePitch; y = y % macroTileHeight; } pipe = ComputePipeFromCoord(x, y, slice, tileMode, pipeSwizzle, ignoreSE, pTileInfo); bank = ComputeBankFromCoord(x, y, slice, tileMode, bankSwizzle, tileSplitSlice, pTileInfo); // // Split the offset to put some bits below the pipe+bank bits and some above. // pipeInterleaveMask = (1 << numPipeInterleaveBits) - 1; bankInterleaveMask = (1 << numBankInterleaveBits) - 1; pipeInterleaveOffset = totalOffset & pipeInterleaveMask; bankInterleaveOffset = static_cast((totalOffset >> numPipeInterleaveBits) & bankInterleaveMask); offset = totalOffset >> (numPipeInterleaveBits + numBankInterleaveBits); // // Assemble the address from its components. // addr = pipeInterleaveOffset; // This is to remove /analyze warnings UINT_32 pipeBits = pipe << numPipeInterleaveBits; UINT_32 bankInterleaveBits = bankInterleaveOffset << (numPipeInterleaveBits + numPipeBits); UINT_32 bankBits = bank << (numPipeInterleaveBits + numPipeBits + numBankInterleaveBits); UINT_64 offsetBits = offset << (numPipeInterleaveBits + numPipeBits + numBankInterleaveBits + numBankBits); addr |= pipeBits; addr |= bankInterleaveBits; addr |= bankBits; addr |= offsetBits; return addr; } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceAddrFromCoordMicroTiled * * @brief * Computes the surface address and bit position from a coordinate for 1D tilied * (micro tiled) * @return * The byte address **************************************************************************************************** */ UINT_64 EgBasedLib::ComputeSurfaceAddrFromCoordMicroTiled( UINT_32 x, ///< [in] x coordinate UINT_32 y, ///< [in] y coordinate UINT_32 slice, ///< [in] slice index UINT_32 sample, ///< [in] sample index 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 AddrTileMode tileMode, ///< [in] tile mode AddrTileType microTileType, ///< [in] micro tiling type BOOL_32 isDepthSampleOrder, ///< [in] TRUE if depth sample ordering is used UINT_32* pBitPosition ///< [out] bit position, e.g. FMT_1 will use this ) const { UINT_64 addr = 0; UINT_32 microTileBytes; UINT_64 sliceBytes; UINT_32 microTilesPerRow; UINT_32 microTileIndexX; UINT_32 microTileIndexY; UINT_32 microTileIndexZ; UINT_64 sliceOffset; UINT_64 microTileOffset; UINT_32 sampleOffset; UINT_32 pixelIndex; UINT_32 pixelOffset; UINT_32 microTileThickness = Thickness(tileMode); // // Compute the micro tile size. // microTileBytes = BITS_TO_BYTES(MicroTilePixels * microTileThickness * bpp * numSamples); // // Compute the slice size. // sliceBytes = BITS_TO_BYTES(static_cast(pitch) * height * microTileThickness * bpp * numSamples); // // Compute the number of micro tiles per row. // microTilesPerRow = pitch / MicroTileWidth; // // Compute the micro tile index. // microTileIndexX = x / MicroTileWidth; microTileIndexY = y / MicroTileHeight; microTileIndexZ = slice / microTileThickness; // // Compute the slice offset. // sliceOffset = static_cast(microTileIndexZ) * sliceBytes; // // Compute the offset to the micro tile containing the specified coordinate. // microTileOffset = (static_cast(microTileIndexY) * microTilesPerRow + microTileIndexX) * microTileBytes; // // Compute the pixel index within the micro tile. // pixelIndex = ComputePixelIndexWithinMicroTile(x, y, slice, bpp, tileMode, microTileType); // Compute the sample offset. // if (isDepthSampleOrder) { // // For depth surfaces, samples are stored contiguously for each element, so the sample // offset is the sample number times the element size. // sampleOffset = sample * bpp; pixelOffset = pixelIndex * bpp * numSamples; } else { // // For color surfaces, all elements for a particular sample are stored contiguously, so // the sample offset is the sample number times the micro tile size divided yBit the number // of samples. // sampleOffset = sample * (microTileBytes*8 / numSamples); pixelOffset = pixelIndex * bpp; } // // Compute the bit position of the pixel. Each element is stored with one bit per sample. // UINT_32 elemOffset = sampleOffset + pixelOffset; *pBitPosition = elemOffset % 8; elemOffset /= 8; // // Combine the slice offset, micro tile offset, sample offset, and pixel offsets. // addr = sliceOffset + microTileOffset + elemOffset; return addr; } /** **************************************************************************************************** * EgBasedLib::HwlComputePixelCoordFromOffset * * @brief * Compute pixel coordinate from offset inside a micro tile * @return * N/A **************************************************************************************************** */ VOID EgBasedLib::HwlComputePixelCoordFromOffset( UINT_32 offset, ///< [in] offset inside micro tile in bits UINT_32 bpp, ///< [in] bits per pixel UINT_32 numSamples, ///< [in] number of samples AddrTileMode tileMode, ///< [in] tile mode UINT_32 tileBase, ///< [in] base offset within a tile UINT_32 compBits, ///< [in] component bits actually needed(for planar surface) UINT_32* pX, ///< [out] x coordinate UINT_32* pY, ///< [out] y coordinate UINT_32* pSlice, ///< [out] slice index UINT_32* pSample, ///< [out] sample index AddrTileType microTileType, ///< [in] micro tiling type BOOL_32 isDepthSampleOrder ///< [in] TRUE if depth sample order in microtile is used ) const { UINT_32 x = 0; UINT_32 y = 0; UINT_32 z = 0; UINT_32 thickness = Thickness(tileMode); // For planar surface, we adjust offset acoording to tile base if ((bpp != compBits) && (compBits != 0) && isDepthSampleOrder) { offset -= tileBase; ADDR_ASSERT(microTileType == ADDR_NON_DISPLAYABLE || microTileType == ADDR_DEPTH_SAMPLE_ORDER); bpp = compBits; } UINT_32 sampleTileBits; UINT_32 samplePixelBits; UINT_32 pixelIndex; if (isDepthSampleOrder) { samplePixelBits = bpp * numSamples; pixelIndex = offset / samplePixelBits; *pSample = (offset % samplePixelBits) / bpp; } else { sampleTileBits = MicroTilePixels * bpp * thickness; *pSample = offset / sampleTileBits; pixelIndex = (offset % sampleTileBits) / bpp; } if (microTileType != ADDR_THICK) { if (microTileType == ADDR_DISPLAYABLE) // displayable { switch (bpp) { case 8: x = pixelIndex & 0x7; y = Bits2Number(3, _BIT(pixelIndex,5),_BIT(pixelIndex,3),_BIT(pixelIndex,4)); break; case 16: x = pixelIndex & 0x7; y = Bits2Number(3, _BIT(pixelIndex,5),_BIT(pixelIndex,4),_BIT(pixelIndex,3)); break; case 32: x = Bits2Number(3, _BIT(pixelIndex,3),_BIT(pixelIndex,1),_BIT(pixelIndex,0)); y = Bits2Number(3, _BIT(pixelIndex,5),_BIT(pixelIndex,4),_BIT(pixelIndex,2)); break; case 64: x = Bits2Number(3, _BIT(pixelIndex,3),_BIT(pixelIndex,2),_BIT(pixelIndex,0)); y = Bits2Number(3, _BIT(pixelIndex,5),_BIT(pixelIndex,4),_BIT(pixelIndex,1)); break; case 128: x = Bits2Number(3, _BIT(pixelIndex,3),_BIT(pixelIndex,2),_BIT(pixelIndex,1)); y = Bits2Number(3, _BIT(pixelIndex,5),_BIT(pixelIndex,4),_BIT(pixelIndex,0)); break; default: break; } } else if (microTileType == ADDR_NON_DISPLAYABLE || microTileType == ADDR_DEPTH_SAMPLE_ORDER) { x = Bits2Number(3, _BIT(pixelIndex,4),_BIT(pixelIndex,2),_BIT(pixelIndex,0)); y = Bits2Number(3, _BIT(pixelIndex,5),_BIT(pixelIndex,3),_BIT(pixelIndex,1)); } else if (microTileType == ADDR_ROTATED) { /* 8-Bit Elements element_index[5:0] = { x[2], x[0], x[1], y[2], y[1], y[0] } 16-Bit Elements element_index[5:0] = { x[2], x[1], x[0], y[2], y[1], y[0] } 32-Bit Elements element_index[5:0] = { x[2], x[1], y[2], x[0], y[1], y[0] } 64-Bit Elements element_index[5:0] = { y[2], x[2], x[1], y[1], x[0], y[0] } */ switch(bpp) { case 8: x = Bits2Number(3, _BIT(pixelIndex,5),_BIT(pixelIndex,3),_BIT(pixelIndex,4)); y = pixelIndex & 0x7; break; case 16: x = Bits2Number(3, _BIT(pixelIndex,5),_BIT(pixelIndex,4),_BIT(pixelIndex,3)); y = pixelIndex & 0x7; break; case 32: x = Bits2Number(3, _BIT(pixelIndex,5),_BIT(pixelIndex,4),_BIT(pixelIndex,2)); y = Bits2Number(3, _BIT(pixelIndex,3),_BIT(pixelIndex,1),_BIT(pixelIndex,0)); break; case 64: x = Bits2Number(3, _BIT(pixelIndex,4),_BIT(pixelIndex,3),_BIT(pixelIndex,1)); y = Bits2Number(3, _BIT(pixelIndex,5),_BIT(pixelIndex,2),_BIT(pixelIndex,0)); break; default: ADDR_ASSERT_ALWAYS(); break; } } if (thickness > 1) // thick { z = Bits2Number(3, _BIT(pixelIndex,8),_BIT(pixelIndex,7),_BIT(pixelIndex,6)); } } else { ADDR_ASSERT((m_chipFamily >= ADDR_CHIP_FAMILY_CI) && (thickness > 1)); /* 8-Bit Elements and 16-Bit Elements element_index[7:0] = { y[2], x[2], z[1], z[0], y[1], x[1], y[0], x[0] } 32-Bit Elements element_index[7:0] = { y[2], x[2], z[1], y[1], z[0], x[1], y[0], x[0] } 64-Bit Elements and 128-Bit Elements element_index[7:0] = { y[2], x[2], z[1], y[1], x[1], z[0], y[0], x[0] } The equation to compute the element index for the extra thick tile: element_index[8] = z[2] */ switch (bpp) { case 8: case 16: // fall-through x = Bits2Number(3, _BIT(pixelIndex,6),_BIT(pixelIndex,2),_BIT(pixelIndex,0)); y = Bits2Number(3, _BIT(pixelIndex,7),_BIT(pixelIndex,3),_BIT(pixelIndex,1)); z = Bits2Number(2, _BIT(pixelIndex,5),_BIT(pixelIndex,4)); break; case 32: x = Bits2Number(3, _BIT(pixelIndex,6),_BIT(pixelIndex,2),_BIT(pixelIndex,0)); y = Bits2Number(3, _BIT(pixelIndex,7),_BIT(pixelIndex,4),_BIT(pixelIndex,1)); z = Bits2Number(2, _BIT(pixelIndex,5),_BIT(pixelIndex,3)); break; case 64: case 128: // fall-through x = Bits2Number(3, _BIT(pixelIndex,6),_BIT(pixelIndex,3),_BIT(pixelIndex,0)); y = Bits2Number(3, _BIT(pixelIndex,7),_BIT(pixelIndex,4),_BIT(pixelIndex,1)); z = Bits2Number(2, _BIT(pixelIndex,5),_BIT(pixelIndex,2)); break; default: ADDR_ASSERT_ALWAYS(); break; } if (thickness == 8) { z += Bits2Number(3,_BIT(pixelIndex,8),0,0); } } *pX = x; *pY = y; *pSlice += z; } /** **************************************************************************************************** * EgBasedLib::DispatchComputeSurfaceCoordFromAddrDispatch * * @brief * Compute (x,y,slice,sample) coordinates from surface address * @return * N/A **************************************************************************************************** */ VOID EgBasedLib::DispatchComputeSurfaceCoordFromAddr( const ADDR_COMPUTE_SURFACE_COORDFROMADDR_INPUT* pIn, ///< [in] input structure ADDR_COMPUTE_SURFACE_COORDFROMADDR_OUTPUT* pOut ///< [out] output structure ) const { UINT_64 addr = pIn->addr; UINT_32 bitPosition = pIn->bitPosition; UINT_32 bpp = pIn->bpp; UINT_32 pitch = pIn->pitch; UINT_32 height = pIn->height; UINT_32 numSlices = pIn->numSlices; UINT_32 numSamples = ((pIn->numSamples == 0) ? 1 : pIn->numSamples); UINT_32 numFrags = ((pIn->numFrags == 0) ? numSamples : pIn->numFrags); AddrTileMode tileMode = pIn->tileMode; UINT_32 tileBase = pIn->tileBase; UINT_32 compBits = pIn->compBits; AddrTileType microTileType = pIn->tileType; BOOL_32 ignoreSE = pIn->ignoreSE; BOOL_32 isDepthSampleOrder = pIn->isDepth; ADDR_TILEINFO* pTileInfo = pIn->pTileInfo; UINT_32* pX = &pOut->x; UINT_32* pY = &pOut->y; UINT_32* pSlice = &pOut->slice; UINT_32* pSample = &pOut->sample; if (microTileType == ADDR_DEPTH_SAMPLE_ORDER) { isDepthSampleOrder = TRUE; } if (m_chipFamily >= ADDR_CHIP_FAMILY_NI) { if (numFrags != numSamples) { numSamples = numFrags; } /// @note /// 128 bit/thick tiled surface doesn't support display tiling and /// mipmap chain must have the same tileType, so please fill tileType correctly if (IsLinear(pIn->tileMode) == FALSE) { if (bpp >= 128 || Thickness(tileMode) > 1) { ADDR_ASSERT(microTileType != ADDR_DISPLAYABLE); } } } switch (tileMode) { case ADDR_TM_LINEAR_GENERAL://fall through case ADDR_TM_LINEAR_ALIGNED: ComputeSurfaceCoordFromAddrLinear(addr, bitPosition, bpp, pitch, height, numSlices, pX, pY, pSlice, pSample); break; case ADDR_TM_1D_TILED_THIN1://fall through case ADDR_TM_1D_TILED_THICK: ComputeSurfaceCoordFromAddrMicroTiled(addr, bitPosition, bpp, pitch, height, numSamples, tileMode, tileBase, compBits, pX, pY, pSlice, pSample, microTileType, isDepthSampleOrder); break; case ADDR_TM_2D_TILED_THIN1: //fall through case ADDR_TM_2D_TILED_THICK: //fall through case ADDR_TM_3D_TILED_THIN1: //fall through case ADDR_TM_3D_TILED_THICK: //fall through case ADDR_TM_2D_TILED_XTHICK: //fall through case ADDR_TM_3D_TILED_XTHICK: //fall through case ADDR_TM_PRT_TILED_THIN1: //fall through case ADDR_TM_PRT_2D_TILED_THIN1://fall through case ADDR_TM_PRT_3D_TILED_THIN1://fall through case ADDR_TM_PRT_TILED_THICK: //fall through case ADDR_TM_PRT_2D_TILED_THICK://fall through case ADDR_TM_PRT_3D_TILED_THICK: UINT_32 pipeSwizzle; UINT_32 bankSwizzle; if (m_configFlags.useCombinedSwizzle) { ExtractBankPipeSwizzle(pIn->tileSwizzle, pIn->pTileInfo, &bankSwizzle, &pipeSwizzle); } else { pipeSwizzle = pIn->pipeSwizzle; bankSwizzle = pIn->bankSwizzle; } ComputeSurfaceCoordFromAddrMacroTiled(addr, bitPosition, bpp, pitch, height, numSamples, tileMode, tileBase, compBits, microTileType, ignoreSE, isDepthSampleOrder, pipeSwizzle, bankSwizzle, pTileInfo, pX, pY, pSlice, pSample); break; default: ADDR_ASSERT_ALWAYS(); } } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceCoordFromAddrMacroTiled * * @brief * Compute surface coordinates from address for macro tiled surface * @return * N/A **************************************************************************************************** */ VOID EgBasedLib::ComputeSurfaceCoordFromAddrMacroTiled( UINT_64 addr, ///< [in] byte address UINT_32 bitPosition, ///< [in] bit position 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 AddrTileMode tileMode, ///< [in] tile mode UINT_32 tileBase, ///< [in] tile base offset UINT_32 compBits, ///< [in] component bits (for planar surface) AddrTileType microTileType, ///< [in] micro tiling type BOOL_32 ignoreSE, ///< [in] TRUE if shader engines can be ignored BOOL_32 isDepthSampleOrder, ///< [in] TRUE if depth sample order is used UINT_32 pipeSwizzle, ///< [in] pipe swizzle UINT_32 bankSwizzle, ///< [in] bank swizzle ADDR_TILEINFO* pTileInfo, ///< [in] bank structure. /// **All fields to be valid on entry** UINT_32* pX, ///< [out] X coord UINT_32* pY, ///< [out] Y coord UINT_32* pSlice, ///< [out] slice index UINT_32* pSample ///< [out] sample index ) const { UINT_32 mx; UINT_32 my; UINT_64 tileBits; UINT_64 macroTileBits; UINT_32 slices; UINT_32 tileSlices; UINT_64 elementOffset; UINT_64 macroTileIndex; UINT_32 tileIndex; UINT_64 totalOffset; UINT_32 bank; UINT_32 pipe; UINT_32 groupBits = m_pipeInterleaveBytes << 3; UINT_32 pipes = HwlGetPipes(pTileInfo); UINT_32 banks = pTileInfo->banks; UINT_32 bankInterleave = m_bankInterleave; UINT_64 addrBits = BYTES_TO_BITS(addr) + bitPosition; // // remove bits for bank and pipe // totalOffset = (addrBits % groupBits) + (((addrBits / groupBits / pipes) % bankInterleave) * groupBits) + (((addrBits / groupBits / pipes) / bankInterleave) / banks) * groupBits * bankInterleave; UINT_32 microTileThickness = Thickness(tileMode); UINT_32 microTileBits = bpp * microTileThickness * MicroTilePixels * numSamples; UINT_32 microTileBytes = BITS_TO_BYTES(microTileBits); // // Determine if tiles need to be split across slices. // // If the size of the micro tile is larger than the tile split size, then the tile will be // split across multiple slices. // UINT_32 slicesPerTile = 1; //_State->TileSlices if ((microTileBytes > pTileInfo->tileSplitBytes) && (microTileThickness == 1)) { //don't support for thick mode // // Compute the number of slices per tile. // slicesPerTile = microTileBytes / pTileInfo->tileSplitBytes; } tileBits = microTileBits / slicesPerTile; // micro tile bits // in micro tiles because not MicroTileWidth timed. UINT_32 macroWidth = pTileInfo->bankWidth * pipes * pTileInfo->macroAspectRatio; // in micro tiles as well UINT_32 macroHeight = pTileInfo->bankHeight * banks / pTileInfo->macroAspectRatio; UINT_32 pitchInMacroTiles = pitch / MicroTileWidth / macroWidth; macroTileBits = (macroWidth * macroHeight) * tileBits / (banks * pipes); macroTileIndex = totalOffset / macroTileBits; // pitchMacros * height / heightMacros; macroTilesPerSlice == _State->SliceMacros UINT_32 macroTilesPerSlice = (pitch / (macroWidth * MicroTileWidth)) * height / (macroHeight * MicroTileWidth); slices = static_cast(macroTileIndex / macroTilesPerSlice); *pSlice = static_cast(slices / slicesPerTile * microTileThickness); // // calculate element offset and x[2:0], y[2:0], z[1:0] for thick // tileSlices = slices % slicesPerTile; elementOffset = tileSlices * tileBits; elementOffset += totalOffset % tileBits; UINT_32 coordZ = 0; HwlComputePixelCoordFromOffset(static_cast(elementOffset), bpp, numSamples, tileMode, tileBase, compBits, pX, pY, &coordZ, pSample, microTileType, isDepthSampleOrder); macroTileIndex = macroTileIndex % macroTilesPerSlice; *pY += static_cast(macroTileIndex / pitchInMacroTiles * macroHeight * MicroTileHeight); *pX += static_cast(macroTileIndex % pitchInMacroTiles * macroWidth * MicroTileWidth); *pSlice += coordZ; tileIndex = static_cast((totalOffset % macroTileBits) / tileBits); my = (tileIndex / pTileInfo->bankWidth) % pTileInfo->bankHeight * MicroTileHeight; mx = (tileIndex % pTileInfo->bankWidth) * pipes * MicroTileWidth; *pY += my; *pX += mx; bank = ComputeBankFromAddr(addr, banks, pipes); pipe = ComputePipeFromAddr(addr, pipes); HwlComputeSurfaceCoord2DFromBankPipe(tileMode, pX, pY, *pSlice, bank, pipe, bankSwizzle, pipeSwizzle, tileSlices, ignoreSE, pTileInfo); } /** **************************************************************************************************** * EgBasedLib::ComputeSurfaceCoord2DFromBankPipe * * @brief * Compute surface x,y coordinates from bank/pipe info * @return * N/A **************************************************************************************************** */ VOID EgBasedLib::ComputeSurfaceCoord2DFromBankPipe( AddrTileMode tileMode, ///< [in] tile mode UINT_32 x, ///< [in] x coordinate UINT_32 y, ///< [in] y coordinate UINT_32 slice, ///< [in] slice index UINT_32 bank, ///< [in] bank number UINT_32 pipe, ///< [in] pipe number UINT_32 bankSwizzle,///< [in] bank swizzle UINT_32 pipeSwizzle,///< [in] pipe swizzle UINT_32 tileSlices, ///< [in] slices in a micro tile ADDR_TILEINFO* pTileInfo, ///< [in] bank structure. **All fields to be valid on entry** CoordFromBankPipe* pOutput ///< [out] pointer to extracted x/y bits ) const { UINT_32 yBit3 = 0; UINT_32 yBit4 = 0; UINT_32 yBit5 = 0; UINT_32 yBit6 = 0; UINT_32 xBit3 = 0; UINT_32 xBit4 = 0; UINT_32 xBit5 = 0; UINT_32 tileSplitRotation; UINT_32 numPipes = HwlGetPipes(pTileInfo); UINT_32 bankRotation = ComputeBankRotation(tileMode, pTileInfo->banks, numPipes); UINT_32 pipeRotation = ComputePipeRotation(tileMode, numPipes); UINT_32 xBit = x / (MicroTileWidth * pTileInfo->bankWidth * numPipes); UINT_32 yBit = y / (MicroTileHeight * pTileInfo->bankHeight); //calculate the bank and pipe before rotation and swizzle switch (tileMode) { case ADDR_TM_2D_TILED_THIN1: //fall through case ADDR_TM_2D_TILED_THICK: //fall through case ADDR_TM_2D_TILED_XTHICK: //fall through case ADDR_TM_3D_TILED_THIN1: //fall through case ADDR_TM_3D_TILED_THICK: //fall through case ADDR_TM_3D_TILED_XTHICK: tileSplitRotation = ((pTileInfo->banks / 2) + 1); break; default: tileSplitRotation = 0; break; } UINT_32 microTileThickness = Thickness(tileMode); bank ^= tileSplitRotation * tileSlices; if (pipeRotation == 0) { bank ^= bankRotation * (slice / microTileThickness) + bankSwizzle; bank %= pTileInfo->banks; pipe ^= pipeSwizzle; } else { bank ^= bankRotation * (slice / microTileThickness) / numPipes + bankSwizzle; bank %= pTileInfo->banks; pipe ^= pipeRotation * (slice / microTileThickness) + pipeSwizzle; } if (pTileInfo->macroAspectRatio == 1) { switch (pTileInfo->banks) { case 2: yBit3 = _BIT(bank, 0) ^ _BIT(xBit,0); break; case 4: yBit4 = _BIT(bank, 0) ^ _BIT(xBit,0); yBit3 = _BIT(bank, 1) ^ _BIT(xBit,1); break; case 8: yBit3 = _BIT(bank, 2) ^ _BIT(xBit,2); yBit5 = _BIT(bank, 0) ^ _BIT(xBit,0); yBit4 = _BIT(bank, 1) ^ _BIT(xBit,1) ^ yBit5; break; case 16: yBit3 = _BIT(bank, 3) ^ _BIT(xBit, 3); yBit4 = _BIT(bank, 2) ^ _BIT(xBit, 2); yBit6 = _BIT(bank, 0) ^ _BIT(xBit, 0); yBit5 = _BIT(bank, 1) ^ _BIT(xBit, 1) ^ yBit6; break; default: break; } } else if (pTileInfo->macroAspectRatio == 2) { switch (pTileInfo->banks) { case 2: //xBit3 = yBit3^b0 xBit3 = _BIT(bank, 0) ^ _BIT(yBit,0); break; case 4: //xBit3=yBit4^b0; yBit3=xBit4^b1 xBit3 = _BIT(bank, 0) ^ _BIT(yBit,1); yBit3 = _BIT(bank, 1) ^ _BIT(xBit,1); break; case 8: //xBit4, xBit5, yBit5 are known xBit3 = _BIT(bank, 0) ^ _BIT(yBit,2); yBit3 = _BIT(bank, 2) ^ _BIT(xBit,2); yBit4 = _BIT(bank, 1) ^ _BIT(xBit,1) ^ _BIT(yBit, 2); break; case 16://x4,x5,x6,y6 are known xBit3 = _BIT(bank, 0) ^ _BIT(yBit, 3); //x3 = y6 ^ b0 yBit3 = _BIT(bank, 3) ^ _BIT(xBit, 3); //y3 = x6 ^ b3 yBit4 = _BIT(bank, 2) ^ _BIT(xBit, 2); //y4 = x5 ^ b2 yBit5 = _BIT(bank, 1) ^ _BIT(xBit, 1) ^ _BIT(yBit, 3); //y5=x4^y6^b1 break; default: break; } } else if (pTileInfo->macroAspectRatio == 4) { switch (pTileInfo->banks) { case 4: //yBit3, yBit4 xBit3 = _BIT(bank, 0) ^ _BIT(yBit,1); xBit4 = _BIT(bank, 1) ^ _BIT(yBit,0); break; case 8: //xBit5, yBit4, yBit5 xBit3 = _BIT(bank, 0) ^ _BIT(yBit,2); yBit3 = _BIT(bank, 2) ^ _BIT(xBit,2); xBit4 = _BIT(bank, 1) ^ _BIT(yBit,1) ^ _BIT(yBit,2); break; case 16: //xBit5, xBit6, yBit5, yBit6 xBit3 = _BIT(bank, 0) ^ _BIT(yBit, 3);//x3 = b0 ^ y6 xBit4 = _BIT(bank, 1) ^ _BIT(yBit, 2) ^ _BIT(yBit, 3);//x4 = b1 ^ y5 ^ y6; yBit3 = _BIT(bank, 3) ^ _BIT(xBit, 3); //y3 = b3 ^ x6; yBit4 = _BIT(bank, 2) ^ _BIT(xBit, 2); //y4 = b2 ^ x5; break; default: break; } } else if (pTileInfo->macroAspectRatio == 8) { switch (pTileInfo->banks) { case 8: //yBit3, yBit4, yBit5 xBit3 = _BIT(bank, 0) ^ _BIT(yBit,2); //x3 = b0 ^ y5; xBit4 = _BIT(bank, 1) ^ _BIT(yBit,1) ^ _BIT(yBit, 2);//x4 = b1 ^ y4 ^ y5; xBit5 = _BIT(bank, 2) ^ _BIT(yBit,0); break; case 16: //xBit6, yBit4, yBit5, yBit6 xBit3 = _BIT(bank, 0) ^ _BIT(yBit, 3);//x3 = y6 ^ b0 xBit4 = _BIT(bank, 1) ^ _BIT(yBit, 2) ^ _BIT(yBit, 3);//x4 = y5 ^ y6 ^ b1 xBit5 = _BIT(bank, 2) ^ _BIT(yBit, 1);//x5 = y4 ^ b2 yBit3 = _BIT(bank, 3) ^ _BIT(xBit, 3); //y3 = x6 ^ b3 break; default: break; } } pOutput->xBits = xBit; pOutput->yBits = yBit; pOutput->xBit3 = xBit3; pOutput->xBit4 = xBit4; pOutput->xBit5 = xBit5; pOutput->yBit3 = yBit3; pOutput->yBit4 = yBit4; pOutput->yBit5 = yBit5; pOutput->yBit6 = yBit6; } /** **************************************************************************************************** * EgBasedLib::HwlExtractBankPipeSwizzle * @brief * Entry of EgBasedLib ExtractBankPipeSwizzle * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::HwlExtractBankPipeSwizzle( const ADDR_EXTRACT_BANKPIPE_SWIZZLE_INPUT* pIn, ///< [in] input structure ADDR_EXTRACT_BANKPIPE_SWIZZLE_OUTPUT* pOut ///< [out] output structure ) const { ExtractBankPipeSwizzle(pIn->base256b, pIn->pTileInfo, &pOut->bankSwizzle, &pOut->pipeSwizzle); return ADDR_OK; } /** **************************************************************************************************** * EgBasedLib::HwlCombineBankPipeSwizzle * @brief * Combine bank/pipe swizzle * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::HwlCombineBankPipeSwizzle( UINT_32 bankSwizzle, ///< [in] bank swizzle UINT_32 pipeSwizzle, ///< [in] pipe swizzle ADDR_TILEINFO* pTileInfo, ///< [in] tile info UINT_64 baseAddr, ///< [in] base address UINT_32* pTileSwizzle ///< [out] combined swizzle ) const { ADDR_E_RETURNCODE retCode = ADDR_OK; if (pTileSwizzle) { *pTileSwizzle = GetBankPipeSwizzle(bankSwizzle, pipeSwizzle, baseAddr, pTileInfo); } else { retCode = ADDR_INVALIDPARAMS; } return retCode; } /** **************************************************************************************************** * EgBasedLib::HwlComputeBaseSwizzle * @brief * Compute base swizzle * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::HwlComputeBaseSwizzle( const ADDR_COMPUTE_BASE_SWIZZLE_INPUT* pIn, ADDR_COMPUTE_BASE_SWIZZLE_OUTPUT* pOut ) const { UINT_32 bankSwizzle = 0; UINT_32 pipeSwizzle = 0; ADDR_TILEINFO* pTileInfo = pIn->pTileInfo; ADDR_ASSERT(IsMacroTiled(pIn->tileMode)); ADDR_ASSERT(pIn->pTileInfo); /// This is a legacy misreading of h/w doc, use it as it doesn't hurt. static const UINT_8 bankRotationArray[4][16] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ADDR_SURF_2_BANK { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ADDR_SURF_4_BANK { 0, 3, 6, 1, 4, 7, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0 }, // ADDR_SURF_8_BANK { 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 }, // ADDR_SURF_16_BANK }; UINT_32 pipes = HwlGetPipes(pTileInfo); (void)pipes; UINT_32 banks = pTileInfo ? pTileInfo->banks : 2; UINT_32 hwNumBanks; // Uses less bank swizzle bits if (pIn->option.reduceBankBit && banks > 2) { banks >>= 1; } switch (banks) { case 2: hwNumBanks = 0; break; case 4: hwNumBanks = 1; break; case 8: hwNumBanks = 2; break; case 16: hwNumBanks = 3; break; default: ADDR_ASSERT_ALWAYS(); hwNumBanks = 0; break; } if (pIn->option.genOption == ADDR_SWIZZLE_GEN_LINEAR) { bankSwizzle = pIn->surfIndex & (banks - 1); } else // (pIn->option.genOption == ADDR_SWIZZLE_GEN_DEFAULT) { bankSwizzle = bankRotationArray[hwNumBanks][pIn->surfIndex & (banks - 1)]; } if (IsMacro3dTiled(pIn->tileMode)) { pipeSwizzle = pIn->surfIndex & (HwlGetPipes(pTileInfo) - 1); } return HwlCombineBankPipeSwizzle(bankSwizzle, pipeSwizzle, pTileInfo, 0, &pOut->tileSwizzle); } /** **************************************************************************************************** * EgBasedLib::ExtractBankPipeSwizzle * @brief * Extract bank/pipe swizzle from base256b * @return * N/A **************************************************************************************************** */ VOID EgBasedLib::ExtractBankPipeSwizzle( UINT_32 base256b, ///< [in] input base256b register value ADDR_TILEINFO* pTileInfo, ///< [in] 2D tile parameters. Client must provide all data UINT_32* pBankSwizzle, ///< [out] bank swizzle UINT_32* pPipeSwizzle ///< [out] pipe swizzle ) const { UINT_32 bankSwizzle = 0; UINT_32 pipeSwizzle = 0; if (base256b != 0) { UINT_32 numPipes = HwlGetPipes(pTileInfo); UINT_32 bankBits = QLog2(pTileInfo->banks); UINT_32 pipeBits = QLog2(numPipes); UINT_32 groupBytes = m_pipeInterleaveBytes; UINT_32 bankInterleave = m_bankInterleave; pipeSwizzle = (base256b / (groupBytes >> 8)) & ((1<> 8) / numPipes / bankInterleave) & ((1 << bankBits) - 1); } *pPipeSwizzle = pipeSwizzle; *pBankSwizzle = bankSwizzle; } /** **************************************************************************************************** * EgBasedLib::GetBankPipeSwizzle * @brief * Combine bank/pipe swizzle * @return * Base256b bits (only filled bank/pipe bits) **************************************************************************************************** */ UINT_32 EgBasedLib::GetBankPipeSwizzle( UINT_32 bankSwizzle, ///< [in] bank swizzle UINT_32 pipeSwizzle, ///< [in] pipe swizzle UINT_64 baseAddr, ///< [in] base address ADDR_TILEINFO* pTileInfo ///< [in] tile info ) const { UINT_32 pipeBits = QLog2(HwlGetPipes(pTileInfo)); UINT_32 bankInterleaveBits = QLog2(m_bankInterleave); UINT_32 tileSwizzle = pipeSwizzle + ((bankSwizzle << bankInterleaveBits) << pipeBits); baseAddr ^= tileSwizzle * m_pipeInterleaveBytes; baseAddr >>= 8; return static_cast(baseAddr); } /** **************************************************************************************************** * EgBasedLib::ComputeSliceTileSwizzle * @brief * Compute cubemap/3d texture faces/slices tile swizzle * @return * Tile swizzle **************************************************************************************************** */ UINT_32 EgBasedLib::ComputeSliceTileSwizzle( AddrTileMode tileMode, ///< [in] Tile mode UINT_32 baseSwizzle, ///< [in] Base swizzle UINT_32 slice, ///< [in] Slice index, Cubemap face index, 0 means +X UINT_64 baseAddr, ///< [in] Base address ADDR_TILEINFO* pTileInfo ///< [in] Bank structure ) const { UINT_32 tileSwizzle = 0; if (IsMacroTiled(tileMode)) // Swizzle only for macro tile mode { UINT_32 firstSlice = slice / Thickness(tileMode); UINT_32 numPipes = HwlGetPipes(pTileInfo); UINT_32 numBanks = pTileInfo->banks; UINT_32 pipeRotation; UINT_32 bankRotation; UINT_32 bankSwizzle = 0; UINT_32 pipeSwizzle = 0; pipeRotation = ComputePipeRotation(tileMode, numPipes); bankRotation = ComputeBankRotation(tileMode, numBanks, numPipes); if (baseSwizzle != 0) { ExtractBankPipeSwizzle(baseSwizzle, pTileInfo, &bankSwizzle, &pipeSwizzle); } if (pipeRotation == 0) //2D mode { bankSwizzle += firstSlice * bankRotation; bankSwizzle %= numBanks; } else //3D mode { pipeSwizzle += firstSlice * pipeRotation; pipeSwizzle %= numPipes; bankSwizzle += firstSlice * bankRotation / numPipes; bankSwizzle %= numBanks; } tileSwizzle = GetBankPipeSwizzle(bankSwizzle, pipeSwizzle, baseAddr, pTileInfo); } return tileSwizzle; } /** **************************************************************************************************** * EgBasedLib::HwlComputeQbStereoRightSwizzle * * @brief * Compute right eye swizzle * @return * swizzle **************************************************************************************************** */ UINT_32 EgBasedLib::HwlComputeQbStereoRightSwizzle( ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pInfo ///< [in] Surface info, must be valid ) const { UINT_32 bankBits = 0; UINT_32 swizzle = 0; // The assumption is default swizzle for left eye is 0 if (IsMacroTiled(pInfo->tileMode) && pInfo->pStereoInfo && pInfo->pTileInfo) { bankBits = ComputeBankFromCoord(0, pInfo->height, 0, pInfo->tileMode, 0, 0, pInfo->pTileInfo); if (bankBits) { HwlCombineBankPipeSwizzle(bankBits, 0, pInfo->pTileInfo, 0, &swizzle); } } return swizzle; } /** **************************************************************************************************** * EgBasedLib::ComputeBankFromCoord * * @brief * Compute bank number from coordinates * @return * Bank number **************************************************************************************************** */ UINT_32 EgBasedLib::ComputeBankFromCoord( UINT_32 x, ///< [in] x coordinate UINT_32 y, ///< [in] y coordinate UINT_32 slice, ///< [in] slice index AddrTileMode tileMode, ///< [in] tile mode UINT_32 bankSwizzle, ///< [in] bank swizzle UINT_32 tileSplitSlice, ///< [in] If the size of the pixel offset is larger than the /// tile split size, then the pixel will be moved to a separate /// slice. This value equals pixelOffset / tileSplitBytes /// in this case. Otherwise this is 0. ADDR_TILEINFO* pTileInfo ///< [in] tile info ) const { UINT_32 pipes = HwlGetPipes(pTileInfo); UINT_32 bankBit0 = 0; UINT_32 bankBit1 = 0; UINT_32 bankBit2 = 0; UINT_32 bankBit3 = 0; UINT_32 sliceRotation; UINT_32 tileSplitRotation; UINT_32 bank; UINT_32 numBanks = pTileInfo->banks; UINT_32 bankWidth = pTileInfo->bankWidth; UINT_32 bankHeight = pTileInfo->bankHeight; UINT_32 tx = x / MicroTileWidth / (bankWidth * pipes); UINT_32 ty = y / MicroTileHeight / bankHeight; UINT_32 x3 = _BIT(tx,0); UINT_32 x4 = _BIT(tx,1); UINT_32 x5 = _BIT(tx,2); UINT_32 x6 = _BIT(tx,3); UINT_32 y3 = _BIT(ty,0); UINT_32 y4 = _BIT(ty,1); UINT_32 y5 = _BIT(ty,2); UINT_32 y6 = _BIT(ty,3); switch (numBanks) { case 16: bankBit0 = x3 ^ y6; bankBit1 = x4 ^ y5 ^ y6; bankBit2 = x5 ^ y4; bankBit3 = x6 ^ y3; break; case 8: bankBit0 = x3 ^ y5; bankBit1 = x4 ^ y4 ^ y5; bankBit2 = x5 ^ y3; break; case 4: bankBit0 = x3 ^ y4; bankBit1 = x4 ^ y3; break; case 2: bankBit0 = x3 ^ y3; break; default: ADDR_ASSERT_ALWAYS(); break; } bank = bankBit0 | (bankBit1 << 1) | (bankBit2 << 2) | (bankBit3 << 3); //Bits2Number(4, bankBit3, bankBit2, bankBit1, bankBit0); bank = HwlPreAdjustBank((x / MicroTileWidth), bank, pTileInfo); // // Compute bank rotation for the slice. // UINT_32 microTileThickness = Thickness(tileMode); switch (tileMode) { case ADDR_TM_2D_TILED_THIN1: // fall through case ADDR_TM_2D_TILED_THICK: // fall through case ADDR_TM_2D_TILED_XTHICK: sliceRotation = ((numBanks / 2) - 1) * (slice / microTileThickness); break; case ADDR_TM_3D_TILED_THIN1: // fall through case ADDR_TM_3D_TILED_THICK: // fall through case ADDR_TM_3D_TILED_XTHICK: sliceRotation = Max(1u, (pipes / 2) - 1) * (slice / microTileThickness) / pipes; break; default: sliceRotation = 0; break; } // // Compute bank rotation for the tile split slice. // // The sample slice will be non-zero if samples must be split across multiple slices. // This situation arises when the micro tile size multiplied yBit the number of samples exceeds // the split size (set in GB_ADDR_CONFIG). // switch (tileMode) { case ADDR_TM_2D_TILED_THIN1: //fall through case ADDR_TM_3D_TILED_THIN1: //fall through case ADDR_TM_PRT_2D_TILED_THIN1: //fall through case ADDR_TM_PRT_3D_TILED_THIN1: //fall through tileSplitRotation = ((numBanks / 2) + 1) * tileSplitSlice; break; default: tileSplitRotation = 0; break; } // // Apply bank rotation for the slice and tile split slice. // bank ^= bankSwizzle + sliceRotation; bank ^= tileSplitRotation; bank &= (numBanks - 1); return bank; } /** **************************************************************************************************** * EgBasedLib::ComputeBankFromAddr * * @brief * Compute the bank number from an address * @return * Bank number **************************************************************************************************** */ UINT_32 EgBasedLib::ComputeBankFromAddr( UINT_64 addr, ///< [in] address UINT_32 numBanks, ///< [in] number of banks UINT_32 numPipes ///< [in] number of pipes ) const { UINT_32 bank; // // The LSBs of the address are arranged as follows: // bank | bankInterleave | pipe | pipeInterleave // // To get the bank number, shift off the pipe interleave, pipe, and bank interlave bits and // mask the bank bits. // bank = static_cast( (addr >> Log2(m_pipeInterleaveBytes * numPipes * m_bankInterleave)) & (numBanks - 1) ); return bank; } /** **************************************************************************************************** * EgBasedLib::ComputePipeRotation * * @brief * Compute pipe rotation value * @return * Pipe rotation **************************************************************************************************** */ UINT_32 EgBasedLib::ComputePipeRotation( AddrTileMode tileMode, ///< [in] tile mode UINT_32 numPipes ///< [in] number of pipes ) const { UINT_32 rotation; switch (tileMode) { case ADDR_TM_3D_TILED_THIN1: //fall through case ADDR_TM_3D_TILED_THICK: //fall through case ADDR_TM_3D_TILED_XTHICK: //fall through case ADDR_TM_PRT_3D_TILED_THIN1: //fall through case ADDR_TM_PRT_3D_TILED_THICK: rotation = (numPipes < 4) ? 1 : (numPipes / 2 - 1); break; default: rotation = 0; } return rotation; } /** **************************************************************************************************** * EgBasedLib::ComputeBankRotation * * @brief * Compute bank rotation value * @return * Bank rotation **************************************************************************************************** */ UINT_32 EgBasedLib::ComputeBankRotation( AddrTileMode tileMode, ///< [in] tile mode UINT_32 numBanks, ///< [in] number of banks UINT_32 numPipes ///< [in] number of pipes ) const { UINT_32 rotation; switch (tileMode) { case ADDR_TM_2D_TILED_THIN1: // fall through case ADDR_TM_2D_TILED_THICK: // fall through case ADDR_TM_2D_TILED_XTHICK: case ADDR_TM_PRT_2D_TILED_THIN1: case ADDR_TM_PRT_2D_TILED_THICK: // Rotate banks per Z-slice yBit 1 for 4-bank or 3 for 8-bank rotation = numBanks / 2 - 1; break; case ADDR_TM_3D_TILED_THIN1: // fall through case ADDR_TM_3D_TILED_THICK: // fall through case ADDR_TM_3D_TILED_XTHICK: case ADDR_TM_PRT_3D_TILED_THIN1: case ADDR_TM_PRT_3D_TILED_THICK: rotation = (numPipes < 4) ? 1 : (numPipes / 2 - 1); // rotate pipes & banks break; default: rotation = 0; } return rotation; } /** **************************************************************************************************** * EgBasedLib::ComputeHtileBytes * * @brief * Compute htile size in bytes * * @return * Htile size in bytes **************************************************************************************************** */ UINT_64 EgBasedLib::ComputeHtileBytes( UINT_32 pitch, ///< [in] pitch UINT_32 height, ///< [in] height UINT_32 bpp, ///< [in] bits per pixel BOOL_32 isLinear, ///< [in] if it is linear mode UINT_32 numSlices, ///< [in] number of slices UINT_64* sliceBytes, ///< [out] bytes per slice UINT_32 baseAlign ///< [in] base alignments ) const { UINT_64 surfBytes; const UINT_64 HtileCacheLineSize = BITS_TO_BYTES(HtileCacheBits); *sliceBytes = BITS_TO_BYTES(static_cast(pitch) * height * bpp / 64); if (m_configFlags.useHtileSliceAlign) { // Align the sliceSize to htilecachelinesize * pipes at first *sliceBytes = PowTwoAlign(*sliceBytes, HtileCacheLineSize * m_pipes); surfBytes = *sliceBytes * numSlices; } else { // Align the surfSize to htilecachelinesize * pipes at last surfBytes = *sliceBytes * numSlices; surfBytes = PowTwoAlign(surfBytes, HtileCacheLineSize * m_pipes); } return surfBytes; } /** **************************************************************************************************** * EgBasedLib::DispatchComputeFmaskInfo * * @brief * Compute fmask sizes include padded pitch, height, slices, total size in bytes, * meanwhile output suitable tile mode and alignments as well. Results are returned * through output parameters. * * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::DispatchComputeFmaskInfo( 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_COMPUTE_SURFACE_INFO_INPUT surfIn = {0}; ADDR_COMPUTE_SURFACE_INFO_OUTPUT surfOut = {0}; // Setup input structure surfIn.tileMode = pIn->tileMode; surfIn.width = pIn->pitch; surfIn.height = pIn->height; surfIn.numSlices = pIn->numSlices; surfIn.pTileInfo = pIn->pTileInfo; surfIn.tileType = ADDR_NON_DISPLAYABLE; surfIn.flags.fmask = 1; // Setup output structure surfOut.pTileInfo = pOut->pTileInfo; // Setup hwl specific fields HwlFmaskPreThunkSurfInfo(pIn, pOut, &surfIn, &surfOut); surfIn.bpp = HwlComputeFmaskBits(pIn, &surfIn.numSamples); // ComputeSurfaceInfo needs numSamples in surfOut as surface routines need adjusted numSamples surfOut.numSamples = surfIn.numSamples; retCode = HwlComputeSurfaceInfo(&surfIn, &surfOut); // Save bpp field for surface dump support surfOut.bpp = surfIn.bpp; if (retCode == ADDR_OK) { pOut->bpp = surfOut.bpp; pOut->pitch = surfOut.pitch; pOut->height = surfOut.height; pOut->numSlices = surfOut.depth; pOut->fmaskBytes = surfOut.surfSize; pOut->baseAlign = surfOut.baseAlign; pOut->pitchAlign = surfOut.pitchAlign; pOut->heightAlign = surfOut.heightAlign; if (surfOut.depth > 1) { // For fmask, expNumSlices is stored in depth. pOut->sliceSize = surfOut.surfSize / surfOut.depth; } else { pOut->sliceSize = surfOut.surfSize; } // Save numSamples field for surface dump support pOut->numSamples = surfOut.numSamples; HwlFmaskPostThunkSurfInfo(&surfOut, pOut); } return retCode; } /** **************************************************************************************************** * EgBasedLib::HwlFmaskSurfaceInfo * @brief * Entry of EgBasedLib ComputeFmaskInfo * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::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}; // Use internal tile info if pOut does not have a valid pTileInfo if (pOut->pTileInfo == NULL) { pOut->pTileInfo = &tileInfo; } retCode = DispatchComputeFmaskInfo(pIn, 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; } /** **************************************************************************************************** * EgBasedLib::HwlComputeFmaskAddrFromCoord * @brief * Entry of EgBasedLib ComputeFmaskAddrFromCoord * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::HwlComputeFmaskAddrFromCoord( const ADDR_COMPUTE_FMASK_ADDRFROMCOORD_INPUT* pIn, ///< [in] input structure ADDR_COMPUTE_FMASK_ADDRFROMCOORD_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE retCode = ADDR_OK; return retCode; } /** **************************************************************************************************** * EgBasedLib::HwlComputeFmaskCoordFromAddr * @brief * Entry of EgBasedLib ComputeFmaskCoordFromAddr * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::HwlComputeFmaskCoordFromAddr( const ADDR_COMPUTE_FMASK_COORDFROMADDR_INPUT* pIn, ///< [in] input structure ADDR_COMPUTE_FMASK_COORDFROMADDR_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE retCode = ADDR_OK; return retCode; } /** **************************************************************************************************** * EgBasedLib::ComputeFmaskNumPlanesFromNumSamples * * @brief * Compute fmask number of planes from number of samples * * @return * Number of planes **************************************************************************************************** */ UINT_32 EgBasedLib::ComputeFmaskNumPlanesFromNumSamples( UINT_32 numSamples) ///< [in] number of samples { UINT_32 numPlanes; // // FMASK is stored such that each micro tile is composed of elements containing N bits, where // N is the number of samples. There is a micro tile for each bit in the FMASK address, and // micro tiles for each address bit, sometimes referred to as a plane, are stored sequentially. // The FMASK for a 2-sample surface looks like a general surface with 2 bits per element. // The FMASK for a 4-sample surface looks like a general surface with 4 bits per element and // 2 samples. The FMASK for an 8-sample surface looks like a general surface with 8 bits per // element and 4 samples. R6xx and R7xx only stored 3 planes for 8-sample FMASK surfaces. // This was changed for R8xx to simplify the logic in the CB. // switch (numSamples) { case 2: numPlanes = 1; break; case 4: numPlanes = 2; break; case 8: numPlanes = 4; break; default: ADDR_UNHANDLED_CASE(); numPlanes = 0; break; } return numPlanes; } /** **************************************************************************************************** * EgBasedLib::ComputeFmaskResolvedBppFromNumSamples * * @brief * Compute resolved fmask effective bpp based on number of samples * * @return * bpp **************************************************************************************************** */ UINT_32 EgBasedLib::ComputeFmaskResolvedBppFromNumSamples( UINT_32 numSamples) ///< number of samples { UINT_32 bpp; // // Resolved FMASK surfaces are generated yBit the CB and read yBit the texture unit // so that the texture unit can read compressed multi-sample color data. // These surfaces store each index value packed per element. // Each element contains at least num_samples * log2(num_samples) bits. // Resolved FMASK surfaces are addressed as follows: // 2-sample Addressed similarly to a color surface with 8 bits per element and 1 sample. // 4-sample Addressed similarly to a color surface with 8 bits per element and 1 sample. // 8-sample Addressed similarly to a color surface with 32 bits per element and 1 sample. switch (numSamples) { case 2: bpp = 8; break; case 4: bpp = 8; break; case 8: bpp = 32; break; default: ADDR_UNHANDLED_CASE(); bpp = 0; break; } return bpp; } /** **************************************************************************************************** * EgBasedLib::IsTileInfoAllZero * * @brief * Return TRUE if all field are zero * @note * Since NULL input is consider to be all zero **************************************************************************************************** */ BOOL_32 EgBasedLib::IsTileInfoAllZero( const ADDR_TILEINFO* pTileInfo) { BOOL_32 allZero = TRUE; if (pTileInfo) { if ((pTileInfo->banks != 0) || (pTileInfo->bankWidth != 0) || (pTileInfo->bankHeight != 0) || (pTileInfo->macroAspectRatio != 0) || (pTileInfo->tileSplitBytes != 0) || (pTileInfo->pipeConfig != 0) ) { allZero = FALSE; } } return allZero; } /** **************************************************************************************************** * EgBasedLib::HwlTileInfoEqual * * @brief * Return TRUE if all field are equal * @note * Only takes care of current HWL's data **************************************************************************************************** */ BOOL_32 EgBasedLib::HwlTileInfoEqual( const ADDR_TILEINFO* pLeft, ///<[in] Left compare operand const ADDR_TILEINFO* pRight ///<[in] Right compare operand ) const { BOOL_32 equal = FALSE; if (pLeft->banks == pRight->banks && pLeft->bankWidth == pRight->bankWidth && pLeft->bankHeight == pRight->bankHeight && pLeft->macroAspectRatio == pRight->macroAspectRatio && pLeft->tileSplitBytes == pRight->tileSplitBytes) { equal = TRUE; } return equal; } /** **************************************************************************************************** * EgBasedLib::HwlConvertTileInfoToHW * @brief * Entry of EgBasedLib ConvertTileInfoToHW * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::HwlConvertTileInfoToHW( const ADDR_CONVERT_TILEINFOTOHW_INPUT* pIn, ///< [in] input structure ADDR_CONVERT_TILEINFOTOHW_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE retCode = ADDR_OK; ADDR_TILEINFO *pTileInfoIn = pIn->pTileInfo; ADDR_TILEINFO *pTileInfoOut = pOut->pTileInfo; if ((pTileInfoIn != NULL) && (pTileInfoOut != NULL)) { if (pIn->reverse == FALSE) { switch (pTileInfoIn->banks) { case 2: pTileInfoOut->banks = 0; break; case 4: pTileInfoOut->banks = 1; break; case 8: pTileInfoOut->banks = 2; break; case 16: pTileInfoOut->banks = 3; break; default: ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; pTileInfoOut->banks = 0; break; } switch (pTileInfoIn->bankWidth) { case 1: pTileInfoOut->bankWidth = 0; break; case 2: pTileInfoOut->bankWidth = 1; break; case 4: pTileInfoOut->bankWidth = 2; break; case 8: pTileInfoOut->bankWidth = 3; break; default: ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; pTileInfoOut->bankWidth = 0; break; } switch (pTileInfoIn->bankHeight) { case 1: pTileInfoOut->bankHeight = 0; break; case 2: pTileInfoOut->bankHeight = 1; break; case 4: pTileInfoOut->bankHeight = 2; break; case 8: pTileInfoOut->bankHeight = 3; break; default: ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; pTileInfoOut->bankHeight = 0; break; } switch (pTileInfoIn->macroAspectRatio) { case 1: pTileInfoOut->macroAspectRatio = 0; break; case 2: pTileInfoOut->macroAspectRatio = 1; break; case 4: pTileInfoOut->macroAspectRatio = 2; break; case 8: pTileInfoOut->macroAspectRatio = 3; break; default: ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; pTileInfoOut->macroAspectRatio = 0; break; } switch (pTileInfoIn->tileSplitBytes) { case 64: pTileInfoOut->tileSplitBytes = 0; break; case 128: pTileInfoOut->tileSplitBytes = 1; break; case 256: pTileInfoOut->tileSplitBytes = 2; break; case 512: pTileInfoOut->tileSplitBytes = 3; break; case 1024: pTileInfoOut->tileSplitBytes = 4; break; case 2048: pTileInfoOut->tileSplitBytes = 5; break; case 4096: pTileInfoOut->tileSplitBytes = 6; break; default: ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; pTileInfoOut->tileSplitBytes = 0; break; } } else { switch (pTileInfoIn->banks) { case 0: pTileInfoOut->banks = 2; break; case 1: pTileInfoOut->banks = 4; break; case 2: pTileInfoOut->banks = 8; break; case 3: pTileInfoOut->banks = 16; break; default: ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; pTileInfoOut->banks = 2; break; } switch (pTileInfoIn->bankWidth) { case 0: pTileInfoOut->bankWidth = 1; break; case 1: pTileInfoOut->bankWidth = 2; break; case 2: pTileInfoOut->bankWidth = 4; break; case 3: pTileInfoOut->bankWidth = 8; break; default: ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; pTileInfoOut->bankWidth = 1; break; } switch (pTileInfoIn->bankHeight) { case 0: pTileInfoOut->bankHeight = 1; break; case 1: pTileInfoOut->bankHeight = 2; break; case 2: pTileInfoOut->bankHeight = 4; break; case 3: pTileInfoOut->bankHeight = 8; break; default: ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; pTileInfoOut->bankHeight = 1; break; } switch (pTileInfoIn->macroAspectRatio) { case 0: pTileInfoOut->macroAspectRatio = 1; break; case 1: pTileInfoOut->macroAspectRatio = 2; break; case 2: pTileInfoOut->macroAspectRatio = 4; break; case 3: pTileInfoOut->macroAspectRatio = 8; break; default: ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; pTileInfoOut->macroAspectRatio = 1; break; } switch (pTileInfoIn->tileSplitBytes) { case 0: pTileInfoOut->tileSplitBytes = 64; break; case 1: pTileInfoOut->tileSplitBytes = 128; break; case 2: pTileInfoOut->tileSplitBytes = 256; break; case 3: pTileInfoOut->tileSplitBytes = 512; break; case 4: pTileInfoOut->tileSplitBytes = 1024; break; case 5: pTileInfoOut->tileSplitBytes = 2048; break; case 6: pTileInfoOut->tileSplitBytes = 4096; break; default: ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; pTileInfoOut->tileSplitBytes = 64; break; } } if (pTileInfoIn != pTileInfoOut) { pTileInfoOut->pipeConfig = pTileInfoIn->pipeConfig; } } else { ADDR_ASSERT_ALWAYS(); retCode = ADDR_INVALIDPARAMS; } return retCode; } /** **************************************************************************************************** * EgBasedLib::HwlComputeSurfaceInfo * @brief * Entry of EgBasedLib ComputeSurfaceInfo * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::HwlComputeSurfaceInfo( const ADDR_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure ADDR_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE retCode = ADDR_OK; if (pIn->numSamples < pIn->numFrags) { retCode = ADDR_INVALIDPARAMS; } ADDR_TILEINFO tileInfo = {0}; if (retCode == ADDR_OK) { // Uses internal tile info if pOut does not have a valid pTileInfo if (pOut->pTileInfo == NULL) { pOut->pTileInfo = &tileInfo; } if (DispatchComputeSurfaceInfo(pIn, pOut) == FALSE) { retCode = ADDR_INVALIDPARAMS; } // In case client uses tile info as input and would like to calculate a correct size and // alignment together with tile info as output when the tile info is not suppose to have any // matching indices in tile mode tables. if (pIn->flags.skipIndicesOutput == FALSE) { // Returns an index pOut->tileIndex = HwlPostCheckTileIndex(pOut->pTileInfo, pOut->tileMode, pOut->tileType, pOut->tileIndex); if (IsMacroTiled(pOut->tileMode) && (pOut->macroModeIndex == TileIndexInvalid)) { pOut->macroModeIndex = HwlComputeMacroModeIndex(pOut->tileIndex, pIn->flags, pIn->bpp, pIn->numSamples, pOut->pTileInfo); } } // Resets pTileInfo to NULL if the internal tile info is used if (pOut->pTileInfo == &tileInfo) { #if DEBUG // Client does not pass in a valid pTileInfo if (IsMacroTiled(pOut->tileMode)) { // If a valid index is returned, then no pTileInfo is okay ADDR_ASSERT((m_configFlags.useTileIndex == FALSE) || (pOut->tileIndex != TileIndexInvalid)); if (IsTileInfoAllZero(pIn->pTileInfo) == FALSE) { // The initial value of pIn->pTileInfo is copied to tileInfo // We do not expect any of these value to be changed nor any 0 of inputs ADDR_ASSERT(tileInfo.banks == pIn->pTileInfo->banks); ADDR_ASSERT(tileInfo.bankWidth == pIn->pTileInfo->bankWidth); ADDR_ASSERT(tileInfo.bankHeight == pIn->pTileInfo->bankHeight); ADDR_ASSERT(tileInfo.macroAspectRatio == pIn->pTileInfo->macroAspectRatio); ADDR_ASSERT(tileInfo.tileSplitBytes == pIn->pTileInfo->tileSplitBytes); } } #endif pOut->pTileInfo = NULL; } } return retCode; } /** **************************************************************************************************** * EgBasedLib::HwlComputeSurfaceAddrFromCoord * @brief * Entry of EgBasedLib ComputeSurfaceAddrFromCoord * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::HwlComputeSurfaceAddrFromCoord( const ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT* pIn, ///< [in] input structure ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE retCode = ADDR_OK; if ( #if !ALT_TEST // Overflow test needs this out-of-boundary coord (pIn->x > pIn->pitch) || (pIn->y > pIn->height) || #endif (pIn->numSamples > m_maxSamples)) { retCode = ADDR_INVALIDPARAMS; } else { pOut->addr = DispatchComputeSurfaceAddrFromCoord(pIn, pOut); } return retCode; } /** **************************************************************************************************** * EgBasedLib::HwlComputeSurfaceCoordFromAddr * @brief * Entry of EgBasedLib ComputeSurfaceCoordFromAddr * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::HwlComputeSurfaceCoordFromAddr( const ADDR_COMPUTE_SURFACE_COORDFROMADDR_INPUT* pIn, ///< [in] input structure ADDR_COMPUTE_SURFACE_COORDFROMADDR_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE retCode = ADDR_OK; if ((pIn->bitPosition >= 8) || (pIn->numSamples > m_maxSamples)) { retCode = ADDR_INVALIDPARAMS; } else { DispatchComputeSurfaceCoordFromAddr(pIn, pOut); } return retCode; } /** **************************************************************************************************** * EgBasedLib::HwlComputeSliceTileSwizzle * @brief * Entry of EgBasedLib ComputeSurfaceCoordFromAddr * @return * ADDR_E_RETURNCODE **************************************************************************************************** */ ADDR_E_RETURNCODE EgBasedLib::HwlComputeSliceTileSwizzle( const ADDR_COMPUTE_SLICESWIZZLE_INPUT* pIn, ///< [in] input structure ADDR_COMPUTE_SLICESWIZZLE_OUTPUT* pOut ///< [out] output structure ) const { ADDR_E_RETURNCODE retCode = ADDR_OK; if (pIn->pTileInfo && (pIn->pTileInfo->banks > 0)) { pOut->tileSwizzle = ComputeSliceTileSwizzle(pIn->tileMode, pIn->baseSwizzle, pIn->slice, pIn->baseAddr, pIn->pTileInfo); } else { retCode = ADDR_INVALIDPARAMS; } return retCode; } /** **************************************************************************************************** * EgBasedLib::HwlComputeHtileBpp * * @brief * Compute htile bpp * * @return * Htile bpp **************************************************************************************************** */ UINT_32 EgBasedLib::HwlComputeHtileBpp( BOOL_32 isWidth8, ///< [in] TRUE if block width is 8 BOOL_32 isHeight8 ///< [in] TRUE if block height is 8 ) const { // only support 8x8 mode ADDR_ASSERT(isWidth8 && isHeight8); return 32; } /** **************************************************************************************************** * EgBasedLib::HwlComputeHtileBaseAlign * * @brief * Compute htile base alignment * * @return * Htile base alignment **************************************************************************************************** */ UINT_32 EgBasedLib::HwlComputeHtileBaseAlign( BOOL_32 isTcCompatible, ///< [in] if TC compatible BOOL_32 isLinear, ///< [in] if it is linear mode ADDR_TILEINFO* pTileInfo ///< [in] Tile info ) const { UINT_32 baseAlign = m_pipeInterleaveBytes * HwlGetPipes(pTileInfo); if (isTcCompatible) { ADDR_ASSERT(pTileInfo != NULL); if (pTileInfo) { baseAlign *= pTileInfo->banks; } } return baseAlign; } /** **************************************************************************************************** * EgBasedLib::HwlGetPitchAlignmentMicroTiled * * @brief * Compute 1D tiled surface pitch alignment, calculation results are returned through * output parameters. * * @return * pitch alignment **************************************************************************************************** */ UINT_32 EgBasedLib::HwlGetPitchAlignmentMicroTiled( AddrTileMode tileMode, ///< [in] tile mode UINT_32 bpp, ///< [in] bits per pixel ADDR_SURFACE_FLAGS flags, ///< [in] surface flags UINT_32 numSamples ///< [in] number of samples ) const { UINT_32 pitchAlign; UINT_32 microTileThickness = Thickness(tileMode); UINT_32 pixelsPerMicroTile; UINT_32 pixelsPerPipeInterleave; UINT_32 microTilesPerPipeInterleave; // // Special workaround for depth/stencil buffer, use 8 bpp to meet larger requirement for // stencil buffer since pitch alignment is related to bpp. // For a depth only buffer do not set this. // // Note: this actually does not work for mipmap but mipmap depth texture is not really // sampled with mipmap. // if (flags.depth && (flags.noStencil == FALSE)) { bpp = 8; } pixelsPerMicroTile = MicroTilePixels * microTileThickness; pixelsPerPipeInterleave = BYTES_TO_BITS(m_pipeInterleaveBytes) / (bpp * numSamples); microTilesPerPipeInterleave = pixelsPerPipeInterleave / pixelsPerMicroTile; pitchAlign = Max(MicroTileWidth, microTilesPerPipeInterleave * MicroTileWidth); return pitchAlign; } /** **************************************************************************************************** * EgBasedLib::HwlGetSizeAdjustmentMicroTiled * * @brief * Adjust 1D tiled surface pitch and slice size * * @return * Logical slice size in bytes **************************************************************************************************** */ UINT_64 EgBasedLib::HwlGetSizeAdjustmentMicroTiled( UINT_32 thickness, ///< [in] thickness UINT_32 bpp, ///< [in] bits per pixel ADDR_SURFACE_FLAGS flags, ///< [in] surface flags UINT_32 numSamples, ///< [in] number of samples UINT_32 baseAlign, ///< [in] base alignment UINT_32 pitchAlign, ///< [in] pitch alignment UINT_32* pPitch, ///< [in,out] pointer to pitch UINT_32* pHeight ///< [in,out] pointer to height ) const { UINT_64 logicalSliceSize; UINT_64 physicalSliceSize; UINT_32 pitch = *pPitch; UINT_32 height = *pHeight; // Logical slice: pitch * height * bpp * numSamples (no 1D MSAA so actually numSamples == 1) logicalSliceSize = BITS_TO_BYTES(static_cast(pitch) * height * bpp * numSamples); // Physical slice: multiplied by thickness physicalSliceSize = logicalSliceSize * thickness; // // R800 will always pad physical slice size to baseAlign which is pipe_interleave_bytes // ADDR_ASSERT((physicalSliceSize % baseAlign) == 0); return logicalSliceSize; } /** **************************************************************************************************** * EgBasedLib::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 * **************************************************************************************************** */ UINT_32 EgBasedLib::HwlStereoCheckRightOffsetPadding( ADDR_TILEINFO* pTileInfo ///< Tiling info ) const { UINT_32 stereoHeightAlign = 0; if (pTileInfo->macroAspectRatio > 2) { // Since 3D rendering treats right eye surface starting from y == "eye height" while // display engine treats it to be 0, so the bank bits may be different. // Additional padding in height is required to make sure it's possible // to achieve synonym by adjusting bank swizzle of right eye surface. static const UINT_32 StereoAspectRatio = 2; stereoHeightAlign = pTileInfo->banks * pTileInfo->bankHeight * MicroTileHeight / StereoAspectRatio; } return stereoHeightAlign; } } // V1 } // Addr