blob: f3d97d275a86fa623da06da3216246d6b2ae647e [file] [log] [blame]
/*==============================================================================
Copyright(c) 2017 Intel Corporation
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, sublicense,
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 above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
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 NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS 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.
============================================================================*/
#include "Internal/Common/GmmLibInc.h"
/////////////////////////////////////////////////////////////////////////////////////
/// GMM Interface to return lock or render aligned offset to a mip map
///
/// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO
/// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO to store offset info
///
/// @return ::GMM_STATUS
/////////////////////////////////////////////////////////////////////////////////////
GMM_STATUS GmmTexGetMipMapOffset(GMM_TEXTURE_INFO * pTexInfo,
GMM_REQ_OFFSET_INFO *pReqInfo)
{
GMM_STATUS Status = GMM_SUCCESS;
bool RestoreRenderReq = false;
GMM_TEXTURE_CALC *pTextureCalc;
GMM_DPF_ENTER;
__GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
__GMM_ASSERTPTR(pReqInfo, GMM_ERROR);
__GMM_ASSERT(pReqInfo->CubeFace <= __GMM_NO_CUBE_MAP);
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo);
if((pReqInfo->Plane >= GMM_MAX_PLANE) ||
(pReqInfo->Plane < GMM_NO_PLANE) ||
(pReqInfo->MipLevel >= GMM_MAX_MIPMAP))
{
GMM_ASSERTDPF(0, "Invalid parameter!");
return GMM_ERROR;
}
if((pTexInfo->TileMode >= GMM_TILE_MODES) ||
(pTexInfo->TileMode < TILE_NONE))
{
GMM_ASSERTDPF(0, "Invalid parameter!");
return GMM_ERROR;
}
// Retrieve offset info at pReqInfo->MipLevel
if(pReqInfo->ReqLock)
{
if(pReqInfo->ReqRender)
{
pReqInfo->ReqRender = 0;
RestoreRenderReq = true;
}
if(pTextureCalc->GetTexLockOffset(pTexInfo, pReqInfo) != GMM_SUCCESS)
{
GMM_ASSERTDPF(0, "ReqLock failed!");
Status = GMM_ERROR;
}
}
if(RestoreRenderReq == true)
pReqInfo->ReqRender = 1;
if(pReqInfo->ReqRender)
{
if(pTextureCalc->GetTexRenderOffset(pTexInfo, pReqInfo) != GMM_SUCCESS)
{
GMM_ASSERTDPF(0, "ReqRender failed!");
Status = GMM_ERROR;
}
}
if(pReqInfo->ReqStdLayout)
{
if(pTextureCalc->GetTexStdLayoutOffset(pTexInfo, pReqInfo) != GMM_SUCCESS)
{
GMM_ASSERTDPF(0, "ReqStdLayout failed!");
Status = GMM_ERROR;
}
}
GMM_DPF_EXIT;
return Status;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Calculates StdLayout offsets and related pitches of
/// subresource..
///
/// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO
/// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO to store offset info
///
/// @return ::GMM_STATUS
/////////////////////////////////////////////////////////////////////////////////////
GMM_STATUS GmmLib::GmmTextureCalc::GetTexStdLayoutOffset(GMM_TEXTURE_INFO * pTexInfo,
GMM_REQ_OFFSET_INFO *pReqInfo)
{
uint32_t ReqArrayIndex;
bool NeedSurfaceSize = false;
__GMM_ASSERT(pTexInfo);
__GMM_ASSERT(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf);
__GMM_ASSERT(
(pTexInfo->Type == RESOURCE_2D) ||
(pTexInfo->Type == RESOURCE_3D) ||
(pTexInfo->Type == RESOURCE_CUBE));
__GMM_ASSERT(GmmIsPlanar(pTexInfo->Format) == false); // Planar not support
if(pReqInfo->StdLayout.Offset == -1) // Special Req for Surface Size
{
NeedSurfaceSize = true;
ReqArrayIndex = // TODO(Medium): Add planar support.
(pTexInfo->ArraySize * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1));
}
else
{
ReqArrayIndex =
(pReqInfo->ArrayIndex * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1));
}
{
uint32_t TileSize = 0;
if(pTexInfo->Flags.Info.TiledYs)
{
TileSize = GMM_KBYTE(64);
}
else if(pTexInfo->Flags.Info.TiledYf)
{
TileSize = GMM_KBYTE(4);
}
const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo);
uint32_t BytesPerElement = pTexInfo->BitsPerPixel / CHAR_BIT;
GMM_TILE_MODE TileMode = pTexInfo->TileMode;
struct
{
uint32_t Width, Height, Depth;
} Element, Tile;
__GMM_ASSERT(TileMode < GMM_TILE_MODES);
GetCompressionBlockDimensions(
pTexInfo->Format,
&Element.Width,
&Element.Height,
&Element.Depth);
Tile.Width =
(pPlatform->TileInfo[TileMode].LogicalTileWidth / BytesPerElement) *
Element.Width;
Tile.Height =
pPlatform->TileInfo[TileMode].LogicalTileHeight *
Element.Height;
Tile.Depth =
pPlatform->TileInfo[TileMode].LogicalTileDepth *
Element.Depth;
{
GMM_GFX_ADDRESS TargetLodOffset = 0;
GMM_GFX_SIZE_T PrevMipSize = 0;
GMM_GFX_SIZE_T SliceOffset = 0;
GMM_GFX_SIZE_T SlicePitch = 0;
uint32_t Lod;
uint32_t EffectiveMaxLod =
(ReqArrayIndex == 0) ?
pReqInfo->MipLevel :
GFX_MIN(pTexInfo->MaxLod, pTexInfo->Alignment.MipTailStartLod);
pReqInfo->StdLayout.Offset = 0;
for(Lod = 0; Lod <= EffectiveMaxLod; Lod++)
{
GMM_GFX_SIZE_T MipWidth = GmmTexGetMipWidth(pTexInfo, Lod);
uint32_t MipHeight = GmmTexGetMipHeight(pTexInfo, Lod);
uint32_t MipDepth = GmmTexGetMipDepth(pTexInfo, Lod);
uint32_t MipCols = GFX_ULONG_CAST(
GFX_CEIL_DIV(
MipWidth,
Tile.Width));
uint32_t MipRows =
GFX_CEIL_DIV(
MipHeight,
Tile.Height);
uint32_t MipDepthTiles =
GFX_CEIL_DIV(
MipDepth,
Tile.Depth);
uint32_t RowPitch = MipCols * TileSize; // Bytes from one tile row to the next.
uint32_t DepthPitch = RowPitch * MipRows; // Bytes from one depth slice of tiles to the next.
if(Lod <= pTexInfo->Alignment.MipTailStartLod)
{
pReqInfo->StdLayout.Offset += PrevMipSize;
}
if(Lod == pReqInfo->MipLevel)
{
TargetLodOffset = pReqInfo->StdLayout.Offset;
pReqInfo->StdLayout.TileRowPitch = RowPitch;
pReqInfo->StdLayout.TileDepthPitch = DepthPitch;
}
PrevMipSize = DepthPitch * MipDepthTiles;
SlicePitch += DepthPitch;
}
if(pReqInfo->Slice > 0)
{
SliceOffset = SlicePitch * pReqInfo->Slice;
}
if(!NeedSurfaceSize && pReqInfo->MipLevel >= pTexInfo->Alignment.MipTailStartLod)
{
pReqInfo->StdLayout.Offset += (ReqArrayIndex * (pReqInfo->StdLayout.Offset + PrevMipSize)) +
GetMipTailByteOffset(pTexInfo, pReqInfo->MipLevel);
}
else
{
pReqInfo->StdLayout.Offset = ReqArrayIndex * (pReqInfo->StdLayout.Offset + PrevMipSize) +
TargetLodOffset;
}
pReqInfo->StdLayout.Offset += SliceOffset;
}
}
return GMM_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Calculates offset address of a sub resource(i.e. Mip Map, Cube face, volume texture)
///
/// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO
/// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO to store offset info
///
/// @return ::GMM_STATUS
/////////////////////////////////////////////////////////////////////////////////////
GMM_STATUS GmmLib::GmmTextureCalc::GetTexLockOffset(GMM_TEXTURE_INFO * pTexInfo,
GMM_REQ_OFFSET_INFO *pReqInfo)
{
GMM_STATUS Result = GMM_SUCCESS;
GMM_GFX_SIZE_T AddressOffset;
uint32_t Pitch, Slice;
uint32_t MipHeight, MipWidth, MipLevel;
uint32_t NumberOfMipsInSingleRow, SliceRow;
__GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
__GMM_ASSERTPTR(pReqInfo, GMM_ERROR);
const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo);
// set default value
AddressOffset = 0;
Pitch = GFX_ULONG_CAST(pTexInfo->Pitch);
MipLevel = pReqInfo->MipLevel;
Slice = pReqInfo->Slice;
if(GmmIsPlanar(pTexInfo->Format))
{
AddressOffset = GetMipMapByteAddress(pTexInfo, pReqInfo);
pReqInfo->Lock.Offset64 = AddressOffset;
pReqInfo->Lock.Pitch = Pitch;
// Adjust returned pitch for non-uniform-pitch U/V queries...
if((pReqInfo->Plane == GMM_PLANE_U) ||
(pReqInfo->Plane == GMM_PLANE_V))
{
switch(pTexInfo->Format)
{
case GMM_FORMAT_I420:
case GMM_FORMAT_IYUV:
case GMM_FORMAT_YV12:
case GMM_FORMAT_NV11:
pReqInfo->Lock.Pitch /= 2;
break;
case GMM_FORMAT_YVU9:
pReqInfo->Lock.Pitch /= 4;
break;
default:
//Cool--Constant pitch across all planes.
break;
}
}
return Result;
}
switch(pTexInfo->Type)
{
case RESOURCE_3D:
{
if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE)
{
AddressOffset = GFX_ULONG_CAST(GetMipMapByteAddress(pTexInfo, pReqInfo));
// Bytes from one slice to the next...
pReqInfo->Lock.Gen9PlusSlicePitch = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock);
}
else
{
MipHeight = pTexInfo->BaseHeight >> MipLevel;
MipWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth) >> MipLevel;
AlignTexHeightWidth(pTexInfo, &MipHeight, &MipWidth);
// See how many mip can fit in one row
NumberOfMipsInSingleRow = GFX_2_TO_POWER_OF(MipLevel);
SliceRow = Slice / NumberOfMipsInSingleRow;
// get the base address + Slice pitch
AddressOffset = pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[MipLevel];
pReqInfo->Lock.Mip0SlicePitch = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Texture3DOffsetInfo.Mip0SlicePitch);
// Actual address is offset based on requested slice
AddressOffset += SliceRow * MipHeight * Pitch;
// Get to particular slice
if(Slice % NumberOfMipsInSingleRow)
{
AddressOffset += (((Slice % NumberOfMipsInSingleRow) *
MipWidth * pTexInfo->BitsPerPixel) >>
3);
}
}
break;
}
case RESOURCE_CUBE:
case RESOURCE_2D:
case RESOURCE_1D:
{
AddressOffset = GetMipMapByteAddress(pTexInfo, pReqInfo);
break;
}
default:
{ // These resources dont' have multiple levels of detail
AddressOffset = 0;
break;
}
}
pReqInfo->Lock.Offset64 = AddressOffset;
pReqInfo->Lock.Pitch = Pitch;
return Result;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Function used to align width and height of texture so that it satisfy our HW
/// restriction
///
/// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO
/// @param[in] pHeight: ptr to height of mip
/// @param[in] pWidth: ptr to width of mip
///
/////////////////////////////////////////////////////////////////////////////////////
void GmmLib::GmmTextureCalc::AlignTexHeightWidth(GMM_TEXTURE_INFO *pTexInfo,
uint32_t * pHeight,
uint32_t * pWidth)
{
uint32_t MipWidth = 0;
uint32_t MipHeight = 0;
uint32_t UnitAlignHeight = 0;
uint32_t UnitAlignWidth = 0;
uint8_t Compress = 0;
__GMM_ASSERTPTR(pTexInfo, VOIDRETURN);
__GMM_ASSERTPTR(pWidth, VOIDRETURN);
__GMM_ASSERTPTR(pHeight, VOIDRETURN);
__GMM_ASSERTPTR(pGmmGlobalContext, VOIDRETURN);
MipWidth = *pWidth;
MipHeight = *pHeight;
UnitAlignWidth = pTexInfo->Alignment.HAlign;
UnitAlignHeight = pTexInfo->Alignment.VAlign;
Compress = GmmIsCompressed(pTexInfo->Format);
MipWidth = GFX_MAX(MipWidth, UnitAlignWidth);
MipHeight = GFX_MAX(MipHeight, UnitAlignHeight);
MipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth);
MipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight);
if(Compress)
{
uint32_t CompressHeight, CompressWidth, CompressDepth;
GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
MipWidth /= CompressWidth;
MipHeight /= CompressHeight;
}
else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
{
MipWidth *= 2;
MipHeight /= 2;
}
*pHeight = MipHeight;
*pWidth = MipWidth;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Function used to calculate the render aligned offset of a given surface
///
/// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO
/// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO
///
/// @return ::GMM_STATUS
/////////////////////////////////////////////////////////////////////////////////////
GMM_STATUS GmmLib::GmmTextureCalc::GetTexRenderOffset(GMM_TEXTURE_INFO * pTexInfo,
GMM_REQ_OFFSET_INFO *pReqInfo)
{
const GMM_TILE_INFO * pTileInfo = NULL;
GMM_GFX_SIZE_T AddressOffset = 0;
GMM_GFX_SIZE_T RenderAlignOffset = 0;
uint32_t OffsetX = 0;
uint32_t OffsetY = 0;
uint32_t OffsetZ = 0;
const GMM_PLATFORM_INFO *pPlatform = NULL;
__GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
__GMM_ASSERTPTR(pReqInfo, GMM_ERROR);
pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo);
pTileInfo = &pPlatform->TileInfo[pTexInfo->TileMode];
AddressOffset = GetMipMapByteAddress(pTexInfo, pReqInfo);
if(GMM_IS_TILED(*pTileInfo))
{
uint32_t TileAlignedOffsetX = 0;
uint32_t TileAlignedOffsetY = 0;
GMM_GFX_SIZE_T MipTailByteOffset = 0;
//--- Compute Tile-Aligned Offset, and Corresponding X/Y Offsets -------
// Render/Tiled-Aligned offsets and corresponding X/Y offsets are used
// to program the Surface Base Address and X/Y Offset fields of a
// SURFACE_STATE. For a given subresource, the tiled-aligned offset
// addresses the tile containing the base of the subresource; the X/Y
// offsets then give the additional offsets into the tile of the
// subresource base. (Though in SURFACE_STATE, X Offset is specified in
// pixels, this function will return the X Offset in bytes. Y Offset is
// in pixel rows.)
if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
(pReqInfo->MipLevel >= pTexInfo->Alignment.MipTailStartLod))
{
MipTailByteOffset = GetMipTailByteOffset(pTexInfo, pReqInfo->MipLevel);
// For MipTail, Offset is really with respect to start of MipTail,
// so taking out individual Mipoffset within miptail region to get correct Tile aligned offset.
AddressOffset -= MipTailByteOffset;
}
if(!pTexInfo->Flags.Info.RedecribedPlanes)
{
GMM_GFX_SIZE_T Pitch = pTexInfo->Pitch;
if(!pTexInfo->Pitch)
{
// If no pitch exists, but the surface is still marked as tiled, then it is a 1D TileYf/Ys surface.
// Technically no pitch exists for 1D surfaces, but we will fake it to make calculations work below.
// Since 1D surfaces only have an X-dimension, this Pitch calculation is only used for OffsetX calculation.
Pitch = pTexInfo->Size;
}
if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
{
OffsetX = GFX_ULONG_CAST(AddressOffset % Pitch);
TileAlignedOffsetX = GFX_ALIGN_FLOOR(OffsetX, pTileInfo->LogicalTileWidth / 2);
OffsetX -= TileAlignedOffsetX;
}
else
{
OffsetX = GFX_ULONG_CAST(AddressOffset % Pitch);
TileAlignedOffsetX = GFX_ALIGN_FLOOR(OffsetX, pTileInfo->LogicalTileWidth);
OffsetX -= TileAlignedOffsetX;
}
if(pTexInfo->Pitch)
{
if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW)
{
//Expt: YOffset ignore row-interleave -- verify both 2d/3d mips
OffsetY = GFX_ULONG_CAST(AddressOffset / pTexInfo->Pitch);
OffsetY *= 2;
TileAlignedOffsetY = GFX_ALIGN_FLOOR(OffsetY, pTileInfo->LogicalTileHeight * 2 * pTileInfo->LogicalTileDepth);
OffsetY -= TileAlignedOffsetY;
TileAlignedOffsetY /= 2;
}
else
{
OffsetY = GFX_ULONG_CAST(AddressOffset / pTexInfo->Pitch);
TileAlignedOffsetY = GFX_ALIGN_FLOOR(OffsetY, pTileInfo->LogicalTileHeight * pTileInfo->LogicalTileDepth);
OffsetY -= TileAlignedOffsetY;
}
}
RenderAlignOffset =
TileAlignedOffsetY * pTexInfo->Pitch +
(TileAlignedOffsetX / pTileInfo->LogicalTileWidth) * pTileInfo->LogicalSize;
// For Gen9+, Miptail Lods should be reported in a way that
// - Base Address equals tile-aligned "Miptail start address"
// - OffsetX equals to offset (in bytes) from "Miptail start Lod" to "current Lod" in geometric X direction
// - OffsetY and OffsetZ are their pixel distance from "Miptail start Lod" to "current Lod" in geometric Y, Z directions
// Note: only Tile Yf and TileYs have Miptails and their Mips are always "tile aligned"
if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) &&
(pReqInfo->MipLevel >= pTexInfo->Alignment.MipTailStartLod) &&
// Planar surfaces do not support MIPs
!GmmIsPlanar(pTexInfo->Format))
{
GetMipTailGeometryOffset(pTexInfo, pReqInfo->MipLevel, &OffsetX, &OffsetY, &OffsetZ);
}
}
else
{
// Std swizzled and UV packed planes begin at tile-aligned
// offsets and do not support MIPs, so no adjustment is needed
RenderAlignOffset = AddressOffset;
OffsetX = OffsetY = OffsetZ = 0;
}
}
else
{
// Linear case make sure Render address is DWORD aligned.
RenderAlignOffset = GFX_ALIGN_FLOOR(AddressOffset, GMM_BYTES(4));
if(pTexInfo->Pitch)
{
OffsetX = GFX_ULONG_CAST((AddressOffset - RenderAlignOffset) % pTexInfo->Pitch);
OffsetY = GFX_ULONG_CAST((AddressOffset - RenderAlignOffset) / pTexInfo->Pitch);
}
else
{
// One-dimensional textures (no height)
OffsetX = GFX_ULONG_CAST(AddressOffset - RenderAlignOffset);
OffsetY = 0;
}
}
pReqInfo->Render.Offset64 = RenderAlignOffset;
pReqInfo->Render.XOffset = GFX_ULONG_CAST(OffsetX);
pReqInfo->Render.YOffset = GFX_ULONG_CAST(OffsetY);
pReqInfo->Render.ZOffset = GFX_ULONG_CAST(OffsetZ);
return GMM_SUCCESS;
} // __GmmGetRenderAlignAddress
/////////////////////////////////////////////////////////////////////////////////////
/// Function used to calculate byte address of a specified mip map
///
/// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO
/// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO
///
/// @return ::GMM_GFX_SIZE_T byte offset
/////////////////////////////////////////////////////////////////////////////////////
GMM_GFX_SIZE_T GmmLib::GmmTextureCalc::GetMipMapByteAddress(GMM_TEXTURE_INFO * pTexInfo,
GMM_REQ_OFFSET_INFO *pReqInfo)
{
GMM_GFX_SIZE_T ArrayQPitch, MipMapByteAddress, Pitch;
uint32_t MipLevel;
__GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
__GMM_ASSERTPTR(pReqInfo, GMM_ERROR);
__GMM_ASSERT(!(pTexInfo->Flags.Gpu.CCS && !pTexInfo->Flags.Gpu.UnifiedAuxSurface));
__GMM_ASSERT(pReqInfo->Plane < GMM_MAX_PLANE);
MipLevel = pReqInfo->MipLevel;
Pitch = pTexInfo->Pitch;
ArrayQPitch = pReqInfo->ReqRender ?
pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender :
pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock;
const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo);
if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear)
{
ArrayQPitch *= pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth;
}
if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE) &&
((pTexInfo->MSAA.NumSamples > 1) &&
!(pTexInfo->Flags.Gpu.Depth ||
pTexInfo->Flags.Gpu.SeparateStencil ||
GMM_IS_64KB_TILE(pTexInfo->Flags) ||
pTexInfo->Flags.Info.TiledYf)))
{
ArrayQPitch *= pTexInfo->MSAA.NumSamples;
}
if(GmmIsPlanar(pTexInfo->Format))
{
uint32_t Plane = pReqInfo->Plane;
uint32_t OffsetX = 0;
uint32_t OffsetY = 0;
if(Plane < GMM_MAX_PLANE)
{
OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.X[Plane]);
OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.Y[Plane]);
}
MipMapByteAddress = (OffsetY * Pitch) + OffsetX;
__GMM_ASSERT(!pReqInfo->ArrayIndex || (pReqInfo->ArrayIndex < pTexInfo->ArraySize));
MipMapByteAddress += (pTexInfo->OffsetInfo.Plane.ArrayQPitch * pReqInfo->ArrayIndex);
}
else
{
switch(pTexInfo->Type)
{
case RESOURCE_CUBE:
{
uint32_t CubeFace = pReqInfo->CubeFace;
GMM_ASSERTDPF( // Validate Cube Map Params...
(!pReqInfo->ArrayIndex || (pReqInfo->ArrayIndex < pTexInfo->ArraySize)) &&
(pReqInfo->CubeFace < __GMM_MAX_CUBE_FACE) &&
(pReqInfo->CubeFace != __GMM_NO_CUBE_MAP) &&
(pReqInfo->Plane == GMM_NO_PLANE) &&
(pReqInfo->Slice == 0),
"Invalid parameter!");
// Support for CubeMap Arrays using 2D Arrays
MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel];
MipMapByteAddress += (ArrayQPitch * ((6 * pReqInfo->ArrayIndex) + CubeFace));
break;
}
case RESOURCE_2D:
case RESOURCE_1D:
{
MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel];
if(pReqInfo->ArrayIndex)
{
MipMapByteAddress += (ArrayQPitch * pReqInfo->ArrayIndex);
}
break;
}
case RESOURCE_3D:
{
if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE)
{
MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel];
if(pReqInfo->Slice)
{
MipMapByteAddress += (ArrayQPitch * pReqInfo->Slice);
}
}
else
{
MipMapByteAddress = Get3DMipByteAddress(pTexInfo, pReqInfo);
}
break;
}
default:
{ // These resources don't have multiple levels of detail
MipMapByteAddress = 0;
break;
}
}
}
MipMapByteAddress += pTexInfo->Flags.Gpu.S3d ?
GetDisplayFrameOffset(pTexInfo, pReqInfo) :
0;
return MipMapByteAddress;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Utility function used to calculate byte address to a mip slice
///
/// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO
/// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO
///
/// @return byte offset
/////////////////////////////////////////////////////////////////////////////////////
GMM_GFX_SIZE_T GmmLib::GmmTextureCalc::Get3DMipByteAddress(GMM_TEXTURE_INFO * pTexInfo,
GMM_REQ_OFFSET_INFO *pReqInfo)
{
uint32_t MipsInThisRow, PlaneRows;
uint32_t MipHeight, MipWidth;
uint32_t UnitAlignHeight, UnitAlignWidth;
GMM_GFX_SIZE_T MipMapByteAddress, ExtraBytes;
uint32_t Slice, MipLevel, Pitch;
uint8_t Compress;
GMM_RESOURCE_FORMAT GenericFormat;
uint32_t CompressHeight, CompressWidth, CompressDepth;
__GMM_ASSERTPTR(pGmmGlobalContext, 0);
GenericFormat = pTexInfo->Format;
Slice = pReqInfo->Slice;
MipLevel = pReqInfo->MipLevel;
Pitch = GFX_ULONG_CAST(pTexInfo->Pitch);
// For slice 0 for any mip address is simple and stored in table
if(Slice == 0)
{
MipMapByteAddress = pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[MipLevel];
}
// For any slice
else
{
MipMapByteAddress = pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[MipLevel];
// See how many mip can fit in one row
MipsInThisRow = GFX_2_TO_POWER_OF(MipLevel);
PlaneRows = Slice / MipsInThisRow;
// make sure we get the height and mip of base level
MipWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth);
MipHeight = pTexInfo->BaseHeight;
MipWidth >>= MipLevel;
MipHeight >>= MipLevel;
UnitAlignWidth = pTexInfo->Alignment.HAlign;
UnitAlignHeight = pTexInfo->Alignment.VAlign;
Compress = GmmIsCompressed(pTexInfo->Format);
GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth);
// clamp such that mip height is at least min height
MipHeight = GFX_MAX(MipHeight, UnitAlignHeight);
MipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight);
// clamp such that mip width is at least min width
MipWidth = GFX_MAX(MipWidth, UnitAlignWidth);
MipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth);
if(Compress)
{
MipWidth /= CompressWidth;
MipHeight /= CompressHeight;
}
else if(pTexInfo->Flags.Gpu.SeparateStencil)
{
MipWidth *= 2;
MipHeight /= 2;
}
ExtraBytes = PlaneRows * MipHeight * Pitch;
ExtraBytes += ((Slice % MipsInThisRow) *
MipWidth * pTexInfo->BitsPerPixel) >>
3;
// get address offset
MipMapByteAddress += ExtraBytes;
}
return MipMapByteAddress;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Utility function calculates a byte offset from the base of the allocation
// to L frame, R frame, or blank region.
///
/// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO
/// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO
///
/// @return byte offset
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GmmLib::GmmTextureCalc::GetDisplayFrameOffset(GMM_TEXTURE_INFO * pTexInfo,
GMM_REQ_OFFSET_INFO *pReqInfo)
{
uint32_t Offset;
__GMM_ASSERTPTR(pTexInfo, GMM_ERROR);
__GMM_ASSERTPTR(pReqInfo, GMM_ERROR);
switch(pReqInfo->Frame)
{
case GMM_DISPLAY_L:
Offset = 0;
break;
case GMM_DISPLAY_R:
Offset = pTexInfo->S3d.RFrameOffset;
break;
case GMM_DISPLAY_BLANK_AREA:
Offset = pTexInfo->S3d.BlankAreaOffset;
break;
default:
Offset = 0;
GMM_ASSERTDPF(0, "Unknown Frame Type!");
break;
}
return Offset;
}