Files
rocm-systems/runtime/hsa-runtime/image/addrlib/src/gfx12/gfx12addrlib.cpp
T
David Yat Sin f1a13b6d87 Move addrlib into rocr namespace
This avoids conflicts in case application is loading another copy of
addrlib.

Change-Id: Ifb4a10270c867366d5eed0a8c015257b415189a5
Signed-off-by: Chris Freehill <cfreehil@amd.com>
2024-06-25 12:41:53 -05:00

1314 lines
49 KiB
C++

/*
************************************************************************************************************************
*
* Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
*
***********************************************************************************************************************/
/**
************************************************************************************************************************
* @file gfx12addrlib.cpp
* @brief Contain the implementation for the Gfx12Lib class.
************************************************************************************************************************
*/
#include "gfx12addrlib.h"
#include "gfx12_gb_reg.h"
#include "amdgpu_asic_addr.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace rocr {
namespace Addr
{
/**
************************************************************************************************************************
* Gfx12HwlInit
*
* @brief
* Creates an Gfx12Lib object.
*
* @return
* Returns an Gfx12Lib object pointer.
************************************************************************************************************************
*/
Addr::Lib* Gfx12HwlInit(
const Client* pClient)
{
return V3::Gfx12Lib::CreateObj(pClient);
}
namespace V3
{
////////////////////////////////////////////////////////////////////////////////////////////////////
// Static Const Member
////////////////////////////////////////////////////////////////////////////////////////////////////
const SwizzleModeFlags Gfx12Lib::SwizzleModeTable[ADDR3_MAX_TYPE] =
{//Linear 2d 3d 256B 4KB 64KB 256KB Reserved
{{1, 0, 0, 0, 0, 0, 0, 0}}, // ADDR3_LINEAR
{{0, 1, 0, 1, 0, 0, 0, 0}}, // ADDR3_256B_2D
{{0, 1, 0, 0, 1, 0, 0, 0}}, // ADDR3_4KB_2D
{{0, 1, 0, 0, 0, 1, 0, 0}}, // ADDR3_64KB_2D
{{0, 1, 0, 0, 0, 0, 1, 0}}, // ADDR3_256KB_2D
{{0, 0, 1, 0, 1, 0, 0, 0}}, // ADDR3_4KB_3D
{{0, 0, 1, 0, 0, 1, 0, 0}}, // ADDR3_64KB_3D
{{0, 0, 1, 0, 0, 0, 1, 0}}, // ADDR3_256KB_3D
};
const ADDR_EXTENT3D Gfx12Lib::Block4K_Log2_3d[] = {{4, 4, 4}, {3, 4, 4}, {3, 4, 3}, {3, 3, 3}, {2, 3, 3}};
const ADDR_EXTENT3D Gfx12Lib::Block64K_Log2_3d[] = {{6, 5, 5}, {5, 5, 5}, {5, 5, 4}, {5, 4, 4}, {4, 4, 4}};
const ADDR_EXTENT3D Gfx12Lib::Block256K_Log2_3d[] = {{6, 6, 6}, {5, 6, 6}, {5, 6, 5}, {5, 5, 5}, {4, 5, 5}};
/**
************************************************************************************************************************
* Gfx12Lib::Gfx12Lib
*
* @brief
* Constructor
*
************************************************************************************************************************
*/
Gfx12Lib::Gfx12Lib(
const Client* pClient)
:
Lib(pClient),
m_numSwizzleBits(0)
{
memset(&m_settings, 0, sizeof(m_settings));
memcpy(m_swizzleModeTable, SwizzleModeTable, sizeof(SwizzleModeTable));
}
/**
************************************************************************************************************************
* Gfx12Lib::~Gfx12Lib
*
* @brief
* Destructor
************************************************************************************************************************
*/
Gfx12Lib::~Gfx12Lib()
{
}
/**
************************************************************************************************************************
* Gfx12Lib::ConvertSwizzlePatternToEquation
*
* @brief
* Convert swizzle pattern to equation.
*
* @return
* N/A
************************************************************************************************************************
*/
VOID Gfx12Lib::ConvertSwizzlePatternToEquation(
UINT_32 elemLog2, ///< [in] element bytes log2
Addr3SwizzleMode swMode, ///< [in] swizzle mode
const ADDR_SW_PATINFO* pPatInfo, ///< [in] swizzle pattern info
ADDR_EQUATION* pEquation) ///< [out] equation converted from swizzle pattern
const
{
ADDR_BIT_SETTING fullSwizzlePattern[Log2Size256K];
GetSwizzlePatternFromPatternInfo(pPatInfo, fullSwizzlePattern);
const ADDR_BIT_SETTING* pSwizzle = fullSwizzlePattern;
const UINT_32 blockSizeLog2 = GetBlockSizeLog2(swMode, TRUE);
pEquation->numBits = blockSizeLog2;
pEquation->stackedDepthSlices = FALSE;
for (UINT_32 i = 0; i < elemLog2; i++)
{
pEquation->addr[i].channel = 0;
pEquation->addr[i].valid = 1;
pEquation->addr[i].index = i;
}
for (UINT_32 i = elemLog2; i < blockSizeLog2; i++)
{
ADDR_ASSERT(IsPow2(pSwizzle[i].value));
if (pSwizzle[i].x != 0)
{
ADDR_ASSERT(IsPow2(static_cast<UINT_32>(pSwizzle[i].x)));
pEquation->addr[i].channel = 0;
pEquation->addr[i].valid = 1;
pEquation->addr[i].index = Log2(pSwizzle[i].x) + elemLog2;
}
else if (pSwizzle[i].y != 0)
{
ADDR_ASSERT(IsPow2(static_cast<UINT_32>(pSwizzle[i].y)));
pEquation->addr[i].channel = 1;
pEquation->addr[i].valid = 1;
pEquation->addr[i].index = Log2(pSwizzle[i].y);
}
else if (pSwizzle[i].z != 0)
{
ADDR_ASSERT(IsPow2(static_cast<UINT_32>(pSwizzle[i].z)));
pEquation->addr[i].channel = 2;
pEquation->addr[i].valid = 1;
pEquation->addr[i].index = Log2(pSwizzle[i].z);
}
else if (pSwizzle[i].s != 0)
{
ADDR_ASSERT(IsPow2(static_cast<UINT_32>(pSwizzle[i].s)));
pEquation->addr[i].channel = 3;
pEquation->addr[i].valid = 1;
pEquation->addr[i].index = Log2(pSwizzle[i].s);
}
else
{
ADDR_ASSERT_ALWAYS();
}
}
}
/**
************************************************************************************************************************
* Gfx12Lib::InitEquationTable
*
* @brief
* Initialize Equation table.
*
* @return
* N/A
************************************************************************************************************************
*/
VOID Gfx12Lib::InitEquationTable()
{
memset(m_equationTable, 0, sizeof(m_equationTable));
for (UINT_32 swModeIdx = 0; swModeIdx < ADDR3_MAX_TYPE; swModeIdx++)
{
const Addr3SwizzleMode swMode = static_cast<Addr3SwizzleMode>(swModeIdx);
if (IsLinear(swMode))
{
// Skip linear equation (data table is not useful for 2D/3D images-- only contains x-coordinate bits)
continue;
}
const UINT_32 maxMsaa = Is2dSwizzle(swMode) ? MaxMsaaRateLog2 : 1;
for (UINT_32 msaaIdx = 0; msaaIdx < maxMsaa; msaaIdx++)
{
for (UINT_32 elemLog2 = 0; elemLog2 < MaxElementBytesLog2; elemLog2++)
{
UINT_32 equationIndex = ADDR_INVALID_EQUATION_INDEX;
const ADDR_SW_PATINFO* pPatInfo = GetSwizzlePatternInfo(swMode, elemLog2, 1 << msaaIdx);
if (pPatInfo != NULL)
{
ADDR_ASSERT(IsValidSwMode(swMode));
ADDR_EQUATION equation = {};
ConvertSwizzlePatternToEquation(elemLog2, swMode, pPatInfo, &equation);
equationIndex = m_numEquations;
ADDR_ASSERT(equationIndex < NumSwizzlePatterns);
m_equationTable[equationIndex] = equation;
m_numEquations++;
}
SetEquationTableEntry(swMode, msaaIdx, elemLog2, equationIndex);
}
}
}
}
/**
************************************************************************************************************************
* Gfx12Lib::GetBlockPixelDimensions
*
* @brief
* Returns the pixel dimensions of one block.
*
************************************************************************************************************************
*/
ADDR_EXTENT3D Gfx12Lib::GetBlockPixelDimensions(
Addr3SwizzleMode swizzleMode,
UINT_32 log2BytesPerPixel
) const
{
ADDR_EXTENT3D log2Dim = {};
switch (swizzleMode)
{
case ADDR3_4KB_3D:
log2Dim = Block4K_Log2_3d[log2BytesPerPixel];
break;
case ADDR3_64KB_3D:
log2Dim = Block64K_Log2_3d[log2BytesPerPixel];
break;
case ADDR3_256KB_3D:
log2Dim = Block256K_Log2_3d[log2BytesPerPixel];
break;
default:
ADDR_ASSERT_ALWAYS();
break;
}
return { 1u << log2Dim.width, 1u << log2Dim.height, 1u << log2Dim.depth };
}
/**
************************************************************************************************************************
* Gfx12Lib::GetMipOrigin
*
* @brief
* Internal function to calculate origins of the mip levels
*
* @return
* ADDR_E_RETURNCODE
************************************************************************************************************************
*/
VOID Gfx12Lib::GetMipOrigin(
const ADDR3_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure
const ADDR_EXTENT3D& mipExtentFirstInTail,
ADDR3_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure
) const
{
const BOOL_32 is3d = Is3dSwizzle(pIn->swizzleMode);
const UINT_32 bytesPerPixel = pIn->bpp >> 3;
const UINT_32 log2Bpp = Log2(bytesPerPixel);
const ADDR_EXTENT3D pixelBlockDims = GetBlockPixelDimensions(ADDR3_4KB_3D, log2Bpp);
const ADDR_EXTENT3D tailMaxDim = GetMipTailDim(pIn->swizzleMode,
pOut->blockExtent);
const UINT_32 blockSizeLog2 = GetBlockSizeLog2(pIn->swizzleMode);
const UINT_32 maxMipsInTail = GetMaxNumMipsInTail(pIn->swizzleMode, blockSizeLog2);
UINT_32 pitch = tailMaxDim.width;
UINT_32 height = tailMaxDim.height;
UINT_32 depth = (is3d ? PowTwoAlign(mipExtentFirstInTail.depth, pixelBlockDims.depth) : 1);
const UINT_32 tailMaxDepth = (is3d ? (depth / pixelBlockDims.depth) : 1);
for (UINT_32 i = pOut->firstMipIdInTail; i < pIn->numMipLevels; i++)
{
INT_32 mipInTail = static_cast<INT_32>(i) - static_cast<INT_32>(pOut->firstMipIdInTail);
if ((mipInTail < 0) || (pIn->numMipLevels == 1))
{
mipInTail = MaxMipLevels;
}
// "m" can be negative
const INT_32 signedM = static_cast<INT_32>(maxMipsInTail) - static_cast<INT_32>(1) - mipInTail;
const UINT_32 m = Max(0, signedM);
const UINT_32 mipOffset = (m > 6) ? (16 << m) : (m << 8);
pOut->pMipInfo[i].offset = mipOffset * tailMaxDepth;
pOut->pMipInfo[i].mipTailOffset = mipOffset;
pOut->pMipInfo[i].macroBlockOffset = 0;
pOut->pMipInfo[i].pitch = pitch;
pOut->pMipInfo[i].height = height;
pOut->pMipInfo[i].depth = depth;
if (IsLinear(pIn->swizzleMode))
{
pOut->pMipInfo[i].mipTailCoordX = mipOffset >> 8;
pOut->pMipInfo[i].mipTailCoordY = 0;
pOut->pMipInfo[i].mipTailCoordZ = 0;
pitch = Max(pitch >> 1, 1u);
}
else
{
UINT_32 mipX = ((mipOffset >> 9) & 1) |
((mipOffset >> 10) & 2) |
((mipOffset >> 11) & 4) |
((mipOffset >> 12) & 8) |
((mipOffset >> 13) & 16) |
((mipOffset >> 14) & 32);
UINT_32 mipY = ((mipOffset >> 8) & 1) |
((mipOffset >> 9) & 2) |
((mipOffset >> 10) & 4) |
((mipOffset >> 11) & 8) |
((mipOffset >> 12) & 16) |
((mipOffset >> 13) & 32);
if (is3d == FALSE)
{
pOut->pMipInfo[i].mipTailCoordX = mipX * Block256_2d[log2Bpp].w;
pOut->pMipInfo[i].mipTailCoordY = mipY * Block256_2d[log2Bpp].h;
pOut->pMipInfo[i].mipTailCoordZ = 0;
pitch = Max(pitch >> 1, Block256_2d[log2Bpp].w);
height = Max(height >> 1, Block256_2d[log2Bpp].h);
depth = 1;
}
else
{
pOut->pMipInfo[i].mipTailCoordX = mipX * pixelBlockDims.width;
pOut->pMipInfo[i].mipTailCoordY = mipY * pixelBlockDims.height;
pOut->pMipInfo[i].mipTailCoordZ = 0;
pitch = Max(pitch >> 1, pixelBlockDims.width);
height = Max(height >> 1, pixelBlockDims.height);
depth = PowTwoAlign(Max(depth >> 1, 1u), pixelBlockDims.depth);
}
}
}
}
/**
************************************************************************************************************************
* Gfx12Lib::GetMipOffset
*
* @brief
* Internal function to calculate alignment for a surface
*
* @return
* ADDR_E_RETURNCODE
************************************************************************************************************************
*/
VOID Gfx12Lib::GetMipOffset(
const ADDR3_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure
ADDR3_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure
) const
{
const UINT_32 bytesPerPixel = pIn->bpp >> 3;
const UINT_32 log2Bpp = Log2(bytesPerPixel);
const UINT_32 blockSizeLog2 = GetBlockSizeLog2(pIn->swizzleMode);
const UINT_32 blockSize = 1 << blockSizeLog2;
const ADDR_EXTENT3D tailMaxDim = GetMipTailDim(pIn->swizzleMode,
pOut->blockExtent);
const ADDR_EXTENT3D mip0Dims = GetBaseMipExtents(pIn);
const UINT_32 maxMipsInTail = GetMaxNumMipsInTail(pIn->swizzleMode, blockSizeLog2);
UINT_32 firstMipInTail = pIn->numMipLevels;
UINT_64 mipChainSliceSize = 0;
UINT_64 mipSize[MaxMipLevels];
UINT_64 mipSliceSize[MaxMipLevels];
const ADDR_EXTENT3D fixedTailMaxDim = tailMaxDim;
for (UINT_32 mipIdx = 0; mipIdx < pIn->numMipLevels; mipIdx++)
{
const ADDR_EXTENT3D mipExtents = GetMipExtent(mip0Dims, mipIdx);
if (SupportsMipTail(pIn->swizzleMode) &&
IsInMipTail(fixedTailMaxDim, mipExtents, maxMipsInTail, pIn->numMipLevels - mipIdx))
{
firstMipInTail = mipIdx;
mipChainSliceSize += blockSize / pOut->blockExtent.depth;
break;
}
else
{
const UINT_32 pitch = UseCustomPitch(pIn)
? pOut->pitch
: ((mipIdx == 0) && CanTrimLinearPadding(pIn))
? PowTwoAlign(mipExtents.width, 128u / bytesPerPixel)
: PowTwoAlign(mipExtents.width, pOut->blockExtent.width);
const UINT_32 height = UseCustomHeight(pIn)
? pOut->height
: PowTwoAlign(mipExtents.height, pOut->blockExtent.height);
const UINT_32 depth = PowTwoAlign(mipExtents.depth, pOut->blockExtent.depth);
// The original "blockExtent" calculation does subtraction of logs (i.e., division) to get the
// sizes. We aligned our pitch and height to those sizes, which means we need to multiply the various
// factors back together to get back to the slice size.
const UINT_64 sliceSize = static_cast<UINT_64>(pitch) * height * pIn->numSamples * (pIn->bpp >> 3);
mipSize[mipIdx] = sliceSize * depth;
mipSliceSize[mipIdx] = sliceSize * pOut->blockExtent.depth;
mipChainSliceSize += sliceSize;
if (pOut->pMipInfo != NULL)
{
pOut->pMipInfo[mipIdx].pitch = pitch;
pOut->pMipInfo[mipIdx].height = height;
pOut->pMipInfo[mipIdx].depth = depth;
// The slice size of a linear image was calculated above as if the "pitch" is 256 byte aligned.
// However, the rendering pitch is aligned to 128 bytes, and that is what needs to be reported
// to our clients.
if (IsLinear(pIn->swizzleMode))
{
pOut->pMipInfo[mipIdx].pitch = PowTwoAlign(mipExtents.width, 128u / bytesPerPixel);
}
}
}
}
pOut->sliceSize = mipChainSliceSize;
pOut->surfSize = mipChainSliceSize * pOut->numSlices;
pOut->mipChainInTail = (firstMipInTail == 0) ? TRUE : FALSE;
pOut->firstMipIdInTail = firstMipInTail;
if (pOut->pMipInfo != NULL)
{
if (IsLinear(pIn->swizzleMode))
{
// 1. Linear swizzle mode doesn't have miptails.
// 2. The organization of linear 3D mipmap resource is same as GFX11, we should use mip slice size to
// caculate mip offset.
ADDR_ASSERT(firstMipInTail == pIn->numMipLevels);
UINT_64 sliceSize = 0;
for (INT_32 i = static_cast<INT_32>(pIn->numMipLevels) - 1; i >= 0; i--)
{
pOut->pMipInfo[i].offset = sliceSize;
pOut->pMipInfo[i].macroBlockOffset = sliceSize;
pOut->pMipInfo[i].mipTailOffset = 0;
sliceSize += mipSliceSize[i];
}
}
else
{
UINT_64 offset = 0;
UINT_64 macroBlkOffset = 0;
UINT_32 tailMaxDepth = 0;
ADDR_EXTENT3D mipExtentFirstInTail = {};
if (firstMipInTail != pIn->numMipLevels)
{
mipExtentFirstInTail = GetMipExtent(mip0Dims, firstMipInTail);
offset = blockSize *
PowTwoAlign(mipExtentFirstInTail.depth,
pOut->blockExtent.depth) / pOut->blockExtent.depth;
macroBlkOffset = blockSize;
}
for (INT_32 i = firstMipInTail - 1; i >= 0; i--)
{
pOut->pMipInfo[i].offset = offset;
pOut->pMipInfo[i].macroBlockOffset = macroBlkOffset;
pOut->pMipInfo[i].mipTailOffset = 0;
offset += mipSize[i];
macroBlkOffset += mipSliceSize[i];
}
GetMipOrigin(pIn, mipExtentFirstInTail, pOut);
}
}
}
/**
************************************************************************************************************************
* Gfx12Lib::HwlComputeSurfaceInfo
*
* @brief
* Internal function to calculate alignment for a surface
*
* @return
* VOID
************************************************************************************************************************
*/
ADDR_E_RETURNCODE Gfx12Lib::HwlComputeSurfaceInfo(
const ADDR3_COMPUTE_SURFACE_INFO_INPUT* pIn, ///< [in] input structure
ADDR3_COMPUTE_SURFACE_INFO_OUTPUT* pOut ///< [out] output structure
) const
{
ComputeBlockDimensionForSurf(&pOut->blockExtent,
pIn->bpp,
pIn->numSamples,
pIn->swizzleMode);
ADDR_E_RETURNCODE returnCode = ApplyCustomizedPitchHeight(pIn, pOut);
if (returnCode == ADDR_OK)
{
pOut->numSlices = PowTwoAlign(pIn->numSlices, pOut->blockExtent.depth);
pOut->baseAlign = 1 << GetBlockSizeLog2(pIn->swizzleMode);
GetMipOffset(pIn, pOut);
SanityCheckSurfSize(pIn, pOut);
// Slices must be exact multiples of the block sizes. However:
// - with 3D images, one block will contain multiple slices, so that needs to be taken into account.
// - with linear images that have only once slice, we may trim and use the pitch alignment for size.
ADDR_ASSERT(((pOut->sliceSize * pOut->blockExtent.depth) %
GetBlockSize(pIn->swizzleMode, CanTrimLinearPadding(pIn))) == 0);
}
return returnCode;
}
/**
************************************************************************************************************************
* Gfx12Lib::GetBaseMipExtents
*
* @brief
* Return the size of the base mip level in a nice cozy little structure.
*
************************************************************************************************************************
*/
ADDR_EXTENT3D Gfx12Lib::GetBaseMipExtents(
const ADDR3_COMPUTE_SURFACE_INFO_INPUT* pIn
) const
{
return { pIn->width,
pIn->height,
(IsTex3d(pIn->resourceType) ? pIn->numSlices : 1) }; // slices is depth for 3d
}
/**
************************************************************************************************************************
* Gfx12Lib::GetMaxNumMipsInTail
*
* @brief
* Return max number of mips in tails
*
* @return
* Max number of mips in tails
************************************************************************************************************************
*/
UINT_32 Gfx12Lib::GetMaxNumMipsInTail(
Addr3SwizzleMode swizzleMode,
UINT_32 blockSizeLog2 ///< block size log2
) const
{
UINT_32 effectiveLog2 = blockSizeLog2;
UINT_32 mipsInTail = 1;
if (Is3dSwizzle(swizzleMode))
{
effectiveLog2 -= (blockSizeLog2 - 8) / 3;
}
if (effectiveLog2 > 8)
{
mipsInTail = (effectiveLog2 <= 11) ? (1 + (1 << (effectiveLog2 - 9))) : (effectiveLog2 - 4);
}
return mipsInTail;
}
/**
************************************************************************************************************************
* Gfx12Lib::HwlComputeSurfaceAddrFromCoordTiled
*
* @brief
* Internal function to calculate address from coord for tiled swizzle surface
*
* @return
* ADDR_E_RETURNCODE
************************************************************************************************************************
*/
ADDR_E_RETURNCODE Gfx12Lib::HwlComputeSurfaceAddrFromCoordTiled(
const ADDR3_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT* pIn, ///< [in] input structure
ADDR3_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT* pOut ///< [out] output structure
) const
{
// 256B block cannot support 3D image.
ADDR_ASSERT((IsTex3d(pIn->resourceType) && IsBlock256b(pIn->swizzleMode)) == FALSE);
ADDR3_COMPUTE_SURFACE_INFO_INPUT localIn = {};
ADDR3_COMPUTE_SURFACE_INFO_OUTPUT localOut = {};
ADDR3_MIP_INFO mipInfo[MaxMipLevels];
localIn.size = sizeof(localIn);
localIn.flags = pIn->flags;
localIn.swizzleMode = pIn->swizzleMode;
localIn.resourceType = pIn->resourceType;
localIn.format = ADDR_FMT_INVALID;
localIn.bpp = pIn->bpp;
localIn.width = Max(pIn->unAlignedDims.width, 1u);
localIn.height = Max(pIn->unAlignedDims.height, 1u);
localIn.numSlices = Max(pIn->unAlignedDims.depth, 1u);
localIn.numMipLevels = Max(pIn->numMipLevels, 1u);
localIn.numSamples = Max(pIn->numSamples, 1u);
localOut.size = sizeof(localOut);
localOut.pMipInfo = mipInfo;
ADDR_E_RETURNCODE ret = ComputeSurfaceInfo(&localIn, &localOut);
if (ret == ADDR_OK)
{
const UINT_32 elemLog2 = Log2(pIn->bpp >> 3);
const UINT_32 blkSizeLog2 = GetBlockSizeLog2(pIn->swizzleMode);
const UINT_32 eqIndex = GetEquationTableEntry(pIn->swizzleMode, Log2(localIn.numSamples), elemLog2);
if (eqIndex != ADDR_INVALID_EQUATION_INDEX)
{
const BOOL_32 inTail = ((mipInfo[pIn->mipId].mipTailOffset != 0) && (blkSizeLog2 != Log2Size256));
const BOOL_32 is3dNoMsaa = ((IsTex3d(pIn->resourceType) == TRUE) && (localIn.numSamples == 1));
const UINT_64 sliceSize = is3dNoMsaa ? (localOut.sliceSize * localOut.blockExtent.depth)
: localOut.sliceSize;
const UINT_32 sliceId = is3dNoMsaa ? (pIn->slice / localOut.blockExtent.depth) : pIn->slice;
const UINT_32 x = inTail ? (pIn->x + mipInfo[pIn->mipId].mipTailCoordX) : pIn->x;
const UINT_32 y = inTail ? (pIn->y + mipInfo[pIn->mipId].mipTailCoordY) : pIn->y;
const UINT_32 z = inTail ? (pIn->slice + mipInfo[pIn->mipId].mipTailCoordZ) : pIn->slice;
const UINT_32 pb = mipInfo[pIn->mipId].pitch / localOut.blockExtent.width;
const UINT_32 yb = pIn->y / localOut.blockExtent.height;
const UINT_32 xb = pIn->x / localOut.blockExtent.width;
const UINT_64 blkIdx = yb * pb + xb;
const UINT_32 blkOffset = ComputeOffsetFromEquation(&m_equationTable[eqIndex],
x << elemLog2,
y,
z,
pIn->sample);
pOut->addr = sliceSize * sliceId +
mipInfo[pIn->mipId].macroBlockOffset +
(blkIdx << blkSizeLog2) +
blkOffset;
}
else
{
ret = ADDR_INVALIDPARAMS;
}
}
return ret;
}
/**
************************************************************************************************************************
* Gfx12Lib::HwlComputePipeBankXor
*
* @brief
* Generate a PipeBankXor value to be ORed into bits above numSwizzleBits of address
*
* @return
* PipeBankXor value
************************************************************************************************************************
*/
ADDR_E_RETURNCODE Gfx12Lib::HwlComputePipeBankXor(
const ADDR3_COMPUTE_PIPEBANKXOR_INPUT* pIn, ///< [in] input structure
ADDR3_COMPUTE_PIPEBANKXOR_OUTPUT* pOut ///< [out] output structure
) const
{
if ((m_numSwizzleBits != 0) && // does this configuration support swizzling
// base address XOR in GFX12 will be applied to all blk_size = 4KB, 64KB, or 256KB swizzle modes,
// Note that Linear and 256B are excluded.
(IsLinear(pIn->swizzleMode) == FALSE) &&
(IsBlock256b(pIn->swizzleMode) == FALSE))
{
pOut->pipeBankXor = pIn->surfIndex % (1 << m_numSwizzleBits);
}
else
{
pOut->pipeBankXor = 0;
}
return ADDR_OK;
}
/**
************************************************************************************************************************
* Gfx12Lib::ComputeOffsetFromEquation
*
* @brief
* Compute offset from equation
*
* @return
* Offset
************************************************************************************************************************
*/
UINT_32 Gfx12Lib::ComputeOffsetFromEquation(
const ADDR_EQUATION* pEq, ///< Equation
UINT_32 x, ///< x coord in bytes
UINT_32 y, ///< y coord in pixel
UINT_32 z, ///< z coord in slice
UINT_32 s ///< MSAA sample index
) const
{
UINT_32 offset = 0;
for (UINT_32 i = 0; i < pEq->numBits; i++)
{
UINT_32 v = 0;
if (pEq->addr[i].valid)
{
if (pEq->addr[i].channel == 0)
{
v ^= (x >> pEq->addr[i].index) & 1;
}
else if (pEq->addr[i].channel == 1)
{
v ^= (y >> pEq->addr[i].index) & 1;
}
else if (pEq->addr[i].channel == 2)
{
v ^= (z >> pEq->addr[i].index) & 1;
}
else if (pEq->addr[i].channel == 3)
{
v ^= (s >> pEq->addr[i].index) & 1;
}
else
{
ADDR_ASSERT_ALWAYS();
}
}
offset |= (v << i);
}
return offset;
}
/**
************************************************************************************************************************
* Gfx12Lib::GetSwizzlePatternInfo
*
* @brief
* Get swizzle pattern
*
* @return
* Swizzle pattern information
************************************************************************************************************************
*/
const ADDR_SW_PATINFO* Gfx12Lib::GetSwizzlePatternInfo(
Addr3SwizzleMode swizzleMode, ///< Swizzle mode
UINT_32 elemLog2, ///< Element size in bytes log2
UINT_32 numFrag ///< Number of fragment
) const
{
const ADDR_SW_PATINFO* patInfo = NULL;
if (Is2dSwizzle(swizzleMode) == FALSE)
{
ADDR_ASSERT(numFrag == 1);
}
switch (swizzleMode)
{
case ADDR3_256KB_2D:
switch (numFrag)
{
case 1:
patInfo = GFX12_SW_256KB_2D_1xAA_PATINFO;
break;
case 2:
patInfo = GFX12_SW_256KB_2D_2xAA_PATINFO;
break;
case 4:
patInfo = GFX12_SW_256KB_2D_4xAA_PATINFO;
break;
case 8:
patInfo = GFX12_SW_256KB_2D_8xAA_PATINFO;
break;
default:
ADDR_ASSERT_ALWAYS();
}
break;
case ADDR3_256KB_3D:
patInfo = GFX12_SW_256KB_3D_PATINFO;
break;
case ADDR3_64KB_2D:
switch (numFrag)
{
case 1:
patInfo = GFX12_SW_64KB_2D_1xAA_PATINFO;
break;
case 2:
patInfo = GFX12_SW_64KB_2D_2xAA_PATINFO;
break;
case 4:
patInfo = GFX12_SW_64KB_2D_4xAA_PATINFO;
break;
case 8:
patInfo = GFX12_SW_64KB_2D_8xAA_PATINFO;
break;
default:
ADDR_ASSERT_ALWAYS();
}
break;
case ADDR3_64KB_3D:
patInfo = GFX12_SW_64KB_3D_PATINFO;
break;
case ADDR3_4KB_2D:
switch (numFrag)
{
case 1:
patInfo = GFX12_SW_4KB_2D_1xAA_PATINFO;
break;
case 2:
patInfo = GFX12_SW_4KB_2D_2xAA_PATINFO;
break;
case 4:
patInfo = GFX12_SW_4KB_2D_4xAA_PATINFO;
break;
case 8:
patInfo = GFX12_SW_4KB_2D_8xAA_PATINFO;
break;
default:
ADDR_ASSERT_ALWAYS();
}
break;
case ADDR3_4KB_3D:
patInfo = GFX12_SW_4KB_3D_PATINFO;
break;
case ADDR3_256B_2D:
switch (numFrag)
{
case 1:
patInfo = GFX12_SW_256B_2D_1xAA_PATINFO;
break;
case 2:
patInfo = GFX12_SW_256B_2D_2xAA_PATINFO;
break;
case 4:
patInfo = GFX12_SW_256B_2D_4xAA_PATINFO;
break;
case 8:
patInfo = GFX12_SW_256B_2D_8xAA_PATINFO;
break;
default:
break;
}
break;
default:
ADDR_ASSERT_ALWAYS();
break;
}
return (patInfo != NULL) ? &patInfo[elemLog2] : NULL;
}
/**
************************************************************************************************************************
* Gfx12Lib::HwlInitGlobalParams
*
* @brief
* Initializes global parameters
*
* @return
* TRUE if all settings are valid
*
************************************************************************************************************************
*/
BOOL_32 Gfx12Lib::HwlInitGlobalParams(
const ADDR_CREATE_INPUT* pCreateIn) ///< [in] create input
{
BOOL_32 valid = TRUE;
GB_ADDR_CONFIG_GFX12 gbAddrConfig;
gbAddrConfig.u32All = pCreateIn->regValue.gbAddrConfig;
switch (gbAddrConfig.bits.NUM_PIPES)
{
case ADDR_CONFIG_1_PIPE:
m_pipesLog2 = 0;
break;
case ADDR_CONFIG_2_PIPE:
m_pipesLog2 = 1;
break;
case ADDR_CONFIG_4_PIPE:
m_pipesLog2 = 2;
break;
case ADDR_CONFIG_8_PIPE:
m_pipesLog2 = 3;
break;
case ADDR_CONFIG_16_PIPE:
m_pipesLog2 = 4;
break;
case ADDR_CONFIG_32_PIPE:
m_pipesLog2 = 5;
break;
case ADDR_CONFIG_64_PIPE:
m_pipesLog2 = 6;
break;
default:
ADDR_ASSERT_ALWAYS();
valid = FALSE;
break;
}
switch (gbAddrConfig.bits.PIPE_INTERLEAVE_SIZE)
{
case ADDR_CONFIG_PIPE_INTERLEAVE_256B:
m_pipeInterleaveLog2 = 8;
break;
case ADDR_CONFIG_PIPE_INTERLEAVE_512B:
m_pipeInterleaveLog2 = 9;
break;
case ADDR_CONFIG_PIPE_INTERLEAVE_1KB:
m_pipeInterleaveLog2 = 10;
break;
case ADDR_CONFIG_PIPE_INTERLEAVE_2KB:
m_pipeInterleaveLog2 = 11;
break;
default:
ADDR_ASSERT_ALWAYS();
valid = FALSE;
break;
}
m_numSwizzleBits = ((m_pipesLog2 >= 3) ? m_pipesLog2 - 2 : 0);
if (valid)
{
InitEquationTable();
}
return valid;
}
/**
************************************************************************************************************************
* Gfx12Lib::HwlComputeNonBlockCompressedView
*
* @brief
* Compute non-block-compressed view for a given mipmap level/slice.
*
* @return
* ADDR_E_RETURNCODE
************************************************************************************************************************
*/
ADDR_E_RETURNCODE Gfx12Lib::HwlComputeNonBlockCompressedView(
const ADDR3_COMPUTE_NONBLOCKCOMPRESSEDVIEW_INPUT* pIn, ///< [in] input structure
ADDR3_COMPUTE_NONBLOCKCOMPRESSEDVIEW_OUTPUT* pOut ///< [out] output structure
) const
{
ADDR_E_RETURNCODE returnCode = ADDR_OK;
if (((pIn->format < ADDR_FMT_ASTC_4x4) || (pIn->format > ADDR_FMT_ETC2_128BPP)) &&
((pIn->format < ADDR_FMT_BC1) || (pIn->format > ADDR_FMT_BC7)))
{
// Only support BC1~BC7, ASTC, or ETC2 for now...
returnCode = ADDR_NOTSUPPORTED;
}
else
{
UINT_32 bcWidth, bcHeight;
const UINT_32 bpp = GetElemLib()->GetBitsPerPixel(pIn->format, NULL, &bcWidth, &bcHeight);
ADDR3_COMPUTE_SURFACE_INFO_INPUT infoIn = {};
infoIn.size = sizeof(infoIn);
infoIn.flags = pIn->flags;
infoIn.swizzleMode = pIn->swizzleMode;
infoIn.resourceType = pIn->resourceType;
infoIn.format = pIn->format;
infoIn.bpp = bpp;
infoIn.width = RoundUpQuotient(pIn->unAlignedDims.width, bcWidth);
infoIn.height = RoundUpQuotient(pIn->unAlignedDims.height, bcHeight);
infoIn.numSlices = pIn->unAlignedDims.depth;
infoIn.numMipLevels = pIn->numMipLevels;
infoIn.numSamples = 1;
ADDR3_MIP_INFO mipInfo[MaxMipLevels] = {};
ADDR3_COMPUTE_SURFACE_INFO_OUTPUT infoOut = {};
infoOut.size = sizeof(infoOut);
infoOut.pMipInfo = mipInfo;
returnCode = HwlComputeSurfaceInfo(&infoIn, &infoOut);
if (returnCode == ADDR_OK)
{
ADDR3_COMPUTE_SUBRESOURCE_OFFSET_FORSWIZZLEPATTERN_INPUT subOffIn = {};
subOffIn.size = sizeof(subOffIn);
subOffIn.swizzleMode = infoIn.swizzleMode;
subOffIn.resourceType = infoIn.resourceType;
subOffIn.pipeBankXor = pIn->pipeBankXor;
subOffIn.slice = pIn->slice;
subOffIn.sliceSize = infoOut.sliceSize;
subOffIn.macroBlockOffset = mipInfo[pIn->mipId].macroBlockOffset;
subOffIn.mipTailOffset = mipInfo[pIn->mipId].mipTailOffset;
ADDR3_COMPUTE_SUBRESOURCE_OFFSET_FORSWIZZLEPATTERN_OUTPUT subOffOut = {};
subOffOut.size = sizeof(subOffOut);
// For any mipmap level, move nonBc view base address by offset
HwlComputeSubResourceOffsetForSwizzlePattern(&subOffIn, &subOffOut);
pOut->offset = subOffOut.offset;
ADDR3_COMPUTE_SLICE_PIPEBANKXOR_INPUT slicePbXorIn = {};
slicePbXorIn.size = sizeof(slicePbXorIn);
slicePbXorIn.swizzleMode = infoIn.swizzleMode;
slicePbXorIn.resourceType = infoIn.resourceType;
slicePbXorIn.bpe = infoIn.bpp;
slicePbXorIn.basePipeBankXor = pIn->pipeBankXor;
slicePbXorIn.slice = pIn->slice;
slicePbXorIn.numSamples = 1;
ADDR3_COMPUTE_SLICE_PIPEBANKXOR_OUTPUT slicePbXorOut = {};
slicePbXorOut.size = sizeof(slicePbXorOut);
// For any mipmap level, nonBc view should use computed pbXor
HwlComputeSlicePipeBankXor(&slicePbXorIn, &slicePbXorOut);
pOut->pipeBankXor = slicePbXorOut.pipeBankXor;
const BOOL_32 tiled = (pIn->swizzleMode != ADDR3_LINEAR);
const BOOL_32 inTail = tiled && (pIn->mipId >= infoOut.firstMipIdInTail);
const UINT_32 requestMipWidth =
RoundUpQuotient(Max(pIn->unAlignedDims.width >> pIn->mipId, 1u), bcWidth);
const UINT_32 requestMipHeight =
RoundUpQuotient(Max(pIn->unAlignedDims.height >> pIn->mipId, 1u), bcHeight);
if (inTail)
{
// For mipmap level that is in mip tail block, hack a lot of things...
// Basically all mipmap levels in tail block will be viewed as a small mipmap chain that all levels
// are fit in tail block:
// - mipId = relative mip id (which is counted from first mip ID in tail in original mip chain)
pOut->mipId = pIn->mipId - infoOut.firstMipIdInTail;
// - at least 2 mipmap levels (since only 1 mipmap level will not be viewed as mipmap!)
pOut->numMipLevels = Max(infoIn.numMipLevels - infoOut.firstMipIdInTail, 2u);
// - (mip0) width = requestMipWidth << mipId, the value can't exceed mip tail dimension threshold
pOut->unAlignedDims.width = Min(requestMipWidth << pOut->mipId, infoOut.blockExtent.width / 2);
// - (mip0) height = requestMipHeight << mipId, the value can't exceed mip tail dimension threshold
pOut->unAlignedDims.height = Min(requestMipHeight << pOut->mipId, infoOut.blockExtent.height);
}
// This check should cover at least mipId == 0
else if ((requestMipWidth << pIn->mipId) == infoIn.width)
{
// For mipmap level [N] that is not in mip tail block and downgraded without losing element:
// - only one mipmap level and mipId = 0
pOut->mipId = 0;
pOut->numMipLevels = 1;
// (mip0) width = requestMipWidth
pOut->unAlignedDims.width = requestMipWidth;
// (mip0) height = requestMipHeight
pOut->unAlignedDims.height = requestMipHeight;
}
else
{
// For mipmap level [N] that is not in mip tail block and downgraded with element losing,
// We have to make it a multiple mipmap view (2 levels view here), add one extra element if needed,
// because single mip view may have different pitch value than original (multiple) mip view...
// A simple case would be:
// - 64KB block swizzle mode, 8 Bytes-Per-Element. Block dim = [0x80, 0x40]
// - 2 mipmap levels with API mip0 width = 0x401/mip1 width = 0x200 and non-BC view
// mip0 width = 0x101/mip1 width = 0x80
// By multiple mip view, the pitch for mip level 1 would be 0x100 bytes, due to rounding up logic in
// GetMipSize(), and by single mip level view the pitch will only be 0x80 bytes.
// - 2 levels and mipId = 1
pOut->mipId = 1;
pOut->numMipLevels = 2;
const UINT_32 upperMipWidth =
RoundUpQuotient(Max(pIn->unAlignedDims.width >> (pIn->mipId - 1), 1u), bcWidth);
const UINT_32 upperMipHeight =
RoundUpQuotient(Max(pIn->unAlignedDims.height >> (pIn->mipId - 1), 1u), bcHeight);
const BOOL_32 needToAvoidInTail = tiled &&
(requestMipWidth <= infoOut.blockExtent.width / 2) &&
(requestMipHeight <= infoOut.blockExtent.height);
const UINT_32 hwMipWidth =
PowTwoAlign(ShiftCeil(infoIn.width, pIn->mipId), infoOut.blockExtent.width);
const UINT_32 hwMipHeight =
PowTwoAlign(ShiftCeil(infoIn.height, pIn->mipId), infoOut.blockExtent.height);
const BOOL_32 needExtraWidth =
((upperMipWidth < requestMipWidth * 2) ||
((upperMipWidth == requestMipWidth * 2) &&
((needToAvoidInTail == TRUE) ||
(hwMipWidth > PowTwoAlign(requestMipWidth, infoOut.blockExtent.width)))));
const BOOL_32 needExtraHeight =
((upperMipHeight < requestMipHeight * 2) ||
((upperMipHeight == requestMipHeight * 2) &&
((needToAvoidInTail == TRUE) ||
(hwMipHeight > PowTwoAlign(requestMipHeight, infoOut.blockExtent.height)))));
// (mip0) width = requestLastMipLevelWidth
pOut->unAlignedDims.width = upperMipWidth + (needExtraWidth ? 1: 0);
// (mip0) height = requestLastMipLevelHeight
pOut->unAlignedDims.height = upperMipHeight + (needExtraHeight ? 1: 0);
}
// Assert the downgrading from this mip[0] width would still generate correct mip[N] width
ADDR_ASSERT(ShiftRight(pOut->unAlignedDims.width, pOut->mipId) == requestMipWidth);
// Assert the downgrading from this mip[0] height would still generate correct mip[N] height
ADDR_ASSERT(ShiftRight(pOut->unAlignedDims.height, pOut->mipId) == requestMipHeight);
}
}
return returnCode;
}
/**
************************************************************************************************************************
* Gfx12Lib::HwlComputeSubResourceOffsetForSwizzlePattern
*
* @brief
* Compute sub resource offset to support swizzle pattern
*
* @return
* VOID
************************************************************************************************************************
*/
VOID Gfx12Lib::HwlComputeSubResourceOffsetForSwizzlePattern(
const ADDR3_COMPUTE_SUBRESOURCE_OFFSET_FORSWIZZLEPATTERN_INPUT* pIn, ///< [in] input structure
ADDR3_COMPUTE_SUBRESOURCE_OFFSET_FORSWIZZLEPATTERN_OUTPUT* pOut ///< [out] output structure
) const
{
pOut->offset = pIn->slice * pIn->sliceSize + pIn->macroBlockOffset;
}
/**
************************************************************************************************************************
* Gfx12Lib::HwlComputeSlicePipeBankXor
*
* @brief
* Generate slice PipeBankXor value based on base PipeBankXor value and slice id
*
* @return
* PipeBankXor value
************************************************************************************************************************
*/
ADDR_E_RETURNCODE Gfx12Lib::HwlComputeSlicePipeBankXor(
const ADDR3_COMPUTE_SLICE_PIPEBANKXOR_INPUT* pIn, ///< [in] input structure
ADDR3_COMPUTE_SLICE_PIPEBANKXOR_OUTPUT* pOut ///< [out] output structure
) const
{
ADDR_E_RETURNCODE returnCode = ADDR_OK;
// PipeBankXor is only applied to 4KB, 64KB and 256KB on GFX12.
if ((IsLinear(pIn->swizzleMode) == FALSE) && (IsBlock256b(pIn->swizzleMode) == FALSE))
{
if (pIn->bpe == 0)
{
// Require a valid bytes-per-element value passed from client...
returnCode = ADDR_INVALIDPARAMS;
}
else
{
const ADDR_SW_PATINFO* pPatInfo = GetSwizzlePatternInfo(pIn->swizzleMode,
Log2(pIn->bpe >> 3),
1);
if (pPatInfo != NULL)
{
const UINT_32 elemLog2 = Log2(pIn->bpe >> 3);
const UINT_32 eqIndex = GetEquationTableEntry(pIn->swizzleMode, Log2(pIn->numSamples), elemLog2);
const UINT_32 pipeBankXorOffset = ComputeOffsetFromEquation(&m_equationTable[eqIndex],
0,
0,
pIn->slice,
0);
const UINT_32 pipeBankXor = pipeBankXorOffset >> m_pipeInterleaveLog2;
// Should have no bit set under pipe interleave
ADDR_ASSERT((pipeBankXor << m_pipeInterleaveLog2) == pipeBankXorOffset);
pOut->pipeBankXor = pIn->basePipeBankXor ^ pipeBankXor;
}
else
{
// Should never come here...
ADDR_NOT_IMPLEMENTED();
returnCode = ADDR_NOTSUPPORTED;
}
}
}
else
{
pOut->pipeBankXor = 0;
}
return returnCode;
}
/**
************************************************************************************************************************
* Gfx12Lib::SanityCheckSurfSize
*
* @brief
* Calculate the surface size via the exact hardware algorithm to see if it matches.
*
* @return
************************************************************************************************************************
*/
void Gfx12Lib::SanityCheckSurfSize(
const ADDR3_COMPUTE_SURFACE_INFO_INPUT* pIn,
const ADDR3_COMPUTE_SURFACE_INFO_OUTPUT* pOut
) const
{
#if DEBUG
// Verify that the requested image size is valid for the below algorithm. The below code includes
// implicit assumptions about the surface dimensions being less than "MaxImageDim"; otherwise, it can't
// calculate "firstMipInTail" accurately and the below assertion will trip incorrectly.
//
// Surfaces destined for use only on the SDMA engine can exceed the gfx-engine-imposed limitations of
// the "maximum" image dimensions.
if ((pIn->width <= MaxImageDim) &&
(pIn->height <= MaxImageDim) &&
(pIn->numMipLevels <= MaxMipLevels) &&
(UseCustomPitch(pIn) == FALSE) &&
(UseCustomHeight(pIn) == FALSE) &&
// HiZS surfaces have a reduced image size (i.e,. each pixel represents an 8x8 region of the parent
// image, at least for single samples) but they still have the same number of mip levels as the
// parent image. This disconnect produces false assertions below as the image size doesn't apparently
// support the specified number of mip levels.
((pIn->flags.hiZHiS == 0) || (pIn->numMipLevels == 1)))
{
UINT_32 lastMipSize = 1;
UINT_32 dataChainSize = 0;
const ADDR_EXTENT3D mip0Dims = GetBaseMipExtents(pIn);
const UINT_32 blockSizeLog2 = GetBlockSizeLog2(pIn->swizzleMode);
const ADDR_EXTENT3D tailMaxDim = GetMipTailDim(pIn->swizzleMode, pOut->blockExtent);
const UINT_32 maxMipsInTail = GetMaxNumMipsInTail(pIn->swizzleMode, blockSizeLog2);
UINT_32 firstMipInTail = 0;
for (INT_32 mipIdx = MaxMipLevels - 1; mipIdx >= 0; mipIdx--)
{
const ADDR_EXTENT3D mipExtents = GetMipExtent(mip0Dims, mipIdx);
if ((mipExtents.width <= tailMaxDim.width) &&
(mipExtents.height <= tailMaxDim.height) &&
((static_cast<INT_32>(pIn->numMipLevels) - mipIdx) < static_cast<INT_32>(maxMipsInTail)))
{
firstMipInTail = mipIdx;
}
}
for (INT_32 mipIdx = firstMipInTail - 1; mipIdx >= -1; mipIdx--)
{
const ADDR_EXTENT3D mipExtents = GetMipExtent(mip0Dims, mipIdx);
const UINT_32 mipBlockWidth = ShiftCeil(mipExtents.width, Log2(pOut->blockExtent.width));
const UINT_32 mipBlockHeight = ShiftCeil(mipExtents.height, Log2(pOut->blockExtent.height));
if (mipIdx < (static_cast<INT_32>(pIn->numMipLevels) - 1))
{
dataChainSize += lastMipSize;
}
if (mipIdx >= 0)
{
lastMipSize = 4 * lastMipSize
- ((mipBlockWidth & 1) ? mipBlockHeight : 0)
- ((mipBlockHeight & 1) ? mipBlockWidth : 0)
- ((mipBlockWidth & mipBlockHeight & 1) ? 1 : 0);
}
}
if (CanTrimLinearPadding(pIn))
{
ADDR_ASSERT((pOut->sliceSize * pOut->blockExtent.depth) <= (dataChainSize << blockSizeLog2));
}
else
{
ADDR_ASSERT((pOut->sliceSize * pOut->blockExtent.depth) == (dataChainSize << blockSizeLog2));
}
}
#endif
}
} // V3
} // Addr
} // namespace rocr