blob: aba782a8ecaa56b17270297d025ed9146646f363 [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"
/////////////////////////////////////////////////////////////////////////////////////
/// Returns indication of whether resource is eligible for 64KB pages or not.
/// On Windows, UMD must call this api after GmmResCreate()
/// @return 1/0
/////////////////////////////////////////////////////////////////////////////////////
uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::Is64KBPageSuitable()
{
bool Ignore64KBPadding = false;
//!!!! DO NOT USE GetSizeSurface() as it returns the padded size and not natural size.
GMM_GFX_SIZE_T Size = Surf.Size + AuxSurf.Size + AuxSecSurf.Size;
__GMM_ASSERT(Size);
// All ESM resources and VirtuaPadding are exempt from 64KB paging
if(Surf.Flags.Info.ExistingSysMem ||
Surf.Flags.Info.XAdapter ||
Surf.Flags.Gpu.CameraCapture ||
Surf.Flags.Info.KernelModeMapped ||
(Surf.Flags.Gpu.S3d && !Surf.Flags.Gpu.S3dDx &&
!pGmmGlobalContext->GetSkuTable().FtrDisplayEngineS3d)
#if(LHDM)
|| (Surf.Flags.Info.AllowVirtualPadding &&
ExistingSysMem.hParentAllocation)
#endif
)
{
Ignore64KBPadding = true;
}
if(pGmmGlobalContext->GetSkuTable().FtrLocalMemory)
{
Ignore64KBPadding |= (Surf.Flags.Info.NonLocalOnly || (Surf.Flags.Info.Shared && !Surf.Flags.Info.NotLockable));
Ignore64KBPadding |= (pGmmGlobalContext->GetSkuTable().FtrLocalMemoryAllows4KB && Surf.Flags.Info.NoOptimizationPadding);
}
else
{
// The final padded size cannot be larger then a set percentage of the original size
if((Surf.Flags.Info.NoOptimizationPadding && !GFX_IS_ALIGNED(Size, GMM_KBYTE(64))) /*Surface is not 64kb aligned*/ ||
(!Surf.Flags.Info.NoOptimizationPadding && (((Size * (100 + pGmmGlobalContext->GetAllowedPaddingFor64KbPagesPercentage())) / 100) < GFX_ALIGN(Size, GMM_KBYTE(64)))) /*10% padding TBC */)
{
Ignore64KBPadding |= true;
}
}
// If 64KB paging is enabled pad out the resource to 64KB alignment
if(pGmmGlobalContext->GetSkuTable().FtrWddm2_1_64kbPages &&
// Ignore the padding for the above VirtualPadding or ESM cases
(!Ignore64KBPadding) &&
// Resource must be 64KB aligned
(GFX_IS_ALIGNED(Surf.Alignment.BaseAlignment, GMM_KBYTE(64)) ||
// Or must be aligned to a factor of 64KB
(Surf.Alignment.BaseAlignment == GMM_KBYTE(32)) ||
(Surf.Alignment.BaseAlignment == GMM_KBYTE(16)) ||
(Surf.Alignment.BaseAlignment == GMM_KBYTE(8)) ||
(Surf.Alignment.BaseAlignment == GMM_KBYTE(4))))
{
return 1;
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Allows clients to "create" any type of resource. This function does not
/// allocate any memory for the resource. It just calculates the various parameters
/// which are useful for the client and can be queried using other functions.
///
/// @param[in] GmmLib Context: Reference to ::GmmLibContext
/// @param[in] CreateParams: Flags which specify what sort of resource to create
///
/// @return ::GMM_STATUS
/////////////////////////////////////////////////////////////////////////////////////
GMM_STATUS GMM_STDCALL GmmLib::GmmResourceInfoCommon::Create(GMM_RESCREATE_PARAMS &CreateParams)
{
GMM_STATUS Status = GMM_ERROR;
#if defined(__GMM_KMD__)
ClientType = GMM_KMD_VISTA;
#else
GET_GMM_CLIENT_TYPE(pClientContext, ClientType);
#endif
Status = Create(*pGmmGlobalContext, CreateParams);
return Status;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Allows clients to "create" Custom memory layout received from the App as user pointer or DMABUF
// This function does not allocate any memory for the resource. It just calculates/ populates the various parameters
/// which are useful for the client and can be queried using other functions.
///
/// @param[in] GmmLib Context: Reference to ::GmmLibContext
/// @param[in] CreateParams: Flags which specify what sort of resource to create
///
/// @return ::GMM_STATUS
/////////////////////////////////////////////////////////////////////////////////////
GMM_STATUS GMM_STDCALL GmmLib::GmmResourceInfoCommon::CreateCustomRes(Context &GmmLibContext, GMM_RESCREATE_CUSTOM_PARAMS &CreateParams)
{
const GMM_PLATFORM_INFO *pPlatform;
GMM_STATUS Status = GMM_ERROR;
GMM_TEXTURE_CALC * pTextureCalc = NULL;
uint32_t BitsPerPixel, i;
GMM_DPF_ENTER;
__GMM_ASSERTPTR(pGmmGlobalContext, GMM_ERROR);
pGmmLibContext = reinterpret_cast<uint64_t>(&GmmLibContext);
if((CreateParams.Format > GMM_FORMAT_INVALID) &&
(CreateParams.Format < GMM_RESOURCE_FORMATS))
{
BitsPerPixel = pGmmGlobalContext->GetPlatformInfo().FormatTable[CreateParams.Format].Element.BitsPer;
}
else
{
GMM_ASSERTDPF(0, "Format Error");
Status = GMM_INVALIDPARAM;
goto ERROR_CASE;
}
pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf);
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
Surf.Type = CreateParams.Type;
Surf.Format = CreateParams.Format;
Surf.BaseWidth = CreateParams.BaseWidth64;
Surf.BaseHeight = CreateParams.BaseHeight;
Surf.Flags = CreateParams.Flags;
Surf.CachePolicy.Usage = CreateParams.Usage;
Surf.Pitch = CreateParams.Pitch;
Surf.Size = CreateParams.Size;
Surf.Alignment.BaseAlignment = CreateParams.BaseAlignment;
Surf.MaxLod = 1;
Surf.ArraySize = 1;
#if(_DEBUG || _RELEASE_INTERNAL)
Surf.Platform = pGmmGlobalContext->GetPlatformInfo().Platform;
#endif
Surf.BitsPerPixel = BitsPerPixel;
Surf.Alignment.QPitch = (GMM_GLOBAL_GFX_SIZE_T)(Surf.Pitch * Surf.BaseHeight);
pTextureCalc->SetTileMode(&Surf);
if(GmmIsPlanar(Surf.Format))
{
if(GMM_IS_TILED(pPlatform->TileInfo[Surf.TileMode]))
{
Surf.OffsetInfo.Plane.IsTileAlignedPlanes = true;
}
for(i = 1; i <= CreateParams.NoOfPlanes; i++)
{
Surf.OffsetInfo.Plane.X[i] = CreateParams.PlaneOffset.X[i];
Surf.OffsetInfo.Plane.Y[i] = CreateParams.PlaneOffset.Y[i];
}
Surf.OffsetInfo.Plane.NoOfPlanes = CreateParams.NoOfPlanes;
if (Surf.ArraySize > 1)
{
//Surf.OffsetInfo.Plane.ArrayQPitch = Surf.Size; //Not required as this new interface doesn't support arrayed surfaces.
}
UpdateUnAlignedParams();
}
switch(Surf.Type)
{
case RESOURCE_1D:
case RESOURCE_2D:
case RESOURCE_PRIMARY:
case RESOURCE_SHADOW:
case RESOURCE_STAGING:
case RESOURCE_GDI:
case RESOURCE_NNDI:
case RESOURCE_HARDWARE_MBM:
case RESOURCE_OVERLAY_INTERMEDIATE_SURFACE:
case RESOURCE_IFFS_MAPTOGTT:
#if _WIN32
case RESOURCE_WGBOX_ENCODE_DISPLAY:
case RESOURCE_WGBOX_ENCODE_REFERENCE:
#endif
{
if (Surf.ArraySize > 1)
{
// Surf.OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender =
// Surf.OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = Surf.Pitch * Surf.BaseHeight; //Not required as this new interface doesn't support arrayed surfaces.
}
for(i = 0; i <= Surf.MaxLod; i++)
{
Surf.OffsetInfo.Texture2DOffsetInfo.Offset[i] = 0;
}
break;
}
default:
{
GMM_ASSERTDPF(0, "GmmTexAlloc: Unknown surface type!");
Status = GMM_INVALIDPARAM;
goto ERROR_CASE;
;
}
};
GMM_DPF_EXIT;
return GMM_SUCCESS;
ERROR_CASE:
//Zero out all the members
new(this) GmmResourceInfoCommon();
GMM_DPF_EXIT;
return Status;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Allows clients to "create" any type of resource. This function does not
/// allocate any memory for the resource. It just calculates the various parameters
/// which are useful for the client and can be queried using other functions.
///
/// @param[in] GmmLib Context: Reference to ::GmmLibContext
/// @param[in] CreateParams: Flags which specify what sort of resource to create
///
/// @return ::GMM_STATUS
/////////////////////////////////////////////////////////////////////////////////////
GMM_STATUS GMM_STDCALL GmmLib::GmmResourceInfoCommon::Create(Context &GmmLibContext, GMM_RESCREATE_PARAMS &CreateParams)
{
const GMM_PLATFORM_INFO *pPlatform;
GMM_STATUS Status = GMM_ERROR;
GMM_TEXTURE_CALC * pTextureCalc = NULL;
GMM_DPF_ENTER;
__GMM_ASSERTPTR(pGmmGlobalContext, GMM_ERROR);
if(CreateParams.Flags.Info.ExistingSysMem &&
(CreateParams.Flags.Info.TiledW ||
CreateParams.Flags.Info.TiledX ||
GMM_IS_4KB_TILE(CreateParams.Flags) ||
GMM_IS_64KB_TILE(CreateParams.Flags)))
{
GMM_ASSERTDPF(0, "Tiled System Accelerated Memory not supported.");
Status = GMM_INVALIDPARAM;
goto ERROR_CASE;
}
pGmmLibContext = reinterpret_cast<uint64_t>(&GmmLibContext);
#if(!defined(__GMM_KMD__) && !defined(GMM_UNIFIED_LIB))
// Client ULT does new on ResInfo without calling GmmInitGlobalContext. If they call create later, on the previously created
// ResInfo object set the clientContext for them, since clientContext wouldnt have been set
if(!pClientContext)
{
pClientContext = pGmmGlobalContext->pGmmGlobalClientContext;
GET_GMM_CLIENT_TYPE(pClientContext, ClientType);
}
#endif
#if defined(__GMM_KMD__)
ClientType = GMM_KMD_VISTA;
#endif
if(!CopyClientParams(CreateParams))
{
Status = GMM_INVALIDPARAM;
goto ERROR_CASE;
}
pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf);
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
#if defined(__GMM_KMD__) || !defined(_WIN32)
if(!CreateParams.Flags.Info.ExistingSysMem)
#else
// TiledResource uses a private gfx alloc, which doesn't receive a WDDM CreateAllocation
if(!CreateParams.Flags.Info.ExistingSysMem &&
(CreateParams.NoGfxMemory || CreateParams.Flags.Gpu.TiledResource))
#endif
{
if(!ValidateParams())
{
GMM_ASSERTDPF(0, "Invalid parameter!");
Status = GMM_INVALIDPARAM;
goto ERROR_CASE;
}
if(GMM_SUCCESS != pTextureCalc->AllocateTexture(&Surf))
{
GMM_ASSERTDPF(0, "GmmTexAlloc failed!");
goto ERROR_CASE;
}
// Fill out the texture info for each plane if they require rediscription
if(Surf.Flags.Info.RedecribedPlanes)
{
if(false == RedescribePlanes())
{
GMM_ASSERTDPF(0, "Redescribe planes failed!");
goto ERROR_CASE;
}
}
if(Surf.Flags.Gpu.UnifiedAuxSurface)
{
GMM_GFX_SIZE_T TotalSize;
uint32_t Alignment;
if(GMM_SUCCESS != pTextureCalc->FillTexCCS(&Surf, (AuxSecSurf.Type != RESOURCE_INVALID ? &AuxSecSurf : &AuxSurf)))
{
GMM_ASSERTDPF(0, "GmmTexAlloc failed!");
goto ERROR_CASE;
}
if(AuxSurf.Size == 0 && AuxSurf.Type != RESOURCE_INVALID && GMM_SUCCESS != pTextureCalc->AllocateTexture(&AuxSurf))
{
GMM_ASSERTDPF(0, "GmmTexAlloc failed!");
goto ERROR_CASE;
}
AuxSurf.UnpaddedSize = AuxSurf.Size;
if(Surf.Flags.Gpu.IndirectClearColor ||
Surf.Flags.Gpu.ColorDiscard)
{
if(pGmmGlobalContext->GetSkuTable().FtrFlatPhysCCS && AuxSurf.Type == RESOURCE_INVALID)
{
//ie only AuxType is CCS, doesn't exist with FlatCCS, enable it for CC
AuxSurf.Type = Surf.Type;
}
if(!Surf.Flags.Gpu.TiledResource)
{
AuxSurf.CCSize = PAGE_SIZE; // 128bit Float Value + 32bit RT Native Value + Padding.
AuxSurf.Size += PAGE_SIZE;
}
else
{
AuxSurf.CCSize = GMM_KBYTE(64); // 128bit Float Value + 32bit RT Native Value + Padding.
AuxSurf.Size += GMM_KBYTE(64);
}
}
TotalSize = Surf.Size + AuxSurf.Size; //Not including AuxSecSurf size, multi-Aux surface isn't supported for displayables
Alignment = GFX_ULONG_CAST(Surf.Pitch * pPlatform->TileInfo[Surf.TileMode].LogicalTileHeight);
// We need to pad the aux size to the size of the paired surface's tile row (i.e. Pitch * TileHeight) to
// ensure the entire surface can be described with a constant pitch (for GGTT aliasing, clean FENCE'ing and
// AcquireSwizzlingRange, even though the aux isn't intentionally part of such fencing).
if(Surf.Flags.Gpu.FlipChain &&
!__GMM_IS_ALIGN(TotalSize, Alignment))
{
AuxSurf.Size += (GFX_ALIGN_NP2(TotalSize, Alignment) - TotalSize);
}
if((Surf.Size + AuxSurf.Size + AuxSecSurf.Size) > (GMM_GFX_SIZE_T)(pPlatform->SurfaceMaxSize))
{
GMM_ASSERTDPF(0, "Surface too large!");
goto ERROR_CASE;
}
}
}
if(Surf.Flags.Info.ExistingSysMem)
{
Surf.ExistingSysMem.IsGmmAllocated =
(CreateParams.pExistingSysMem &&
CreateParams.ExistingSysMemSize) ?
false :
true;
if(!Surf.ExistingSysMem.IsGmmAllocated)
{
Surf.ExistingSysMem.IsPageAligned =
(((CreateParams.pExistingSysMem & (PAGE_SIZE - 1)) == 0) &&
(((CreateParams.pExistingSysMem + CreateParams.ExistingSysMemSize) & (PAGE_SIZE - 1)) == 0)) ?
true :
false;
}
if(!ValidateParams())
{
GMM_ASSERTDPF(0, "Invalid parameter!");
goto ERROR_CASE;
}
// Get surface Gfx memory size required.
if(GMM_SUCCESS != pTextureCalc->AllocateTexture(&Surf))
{
GMM_ASSERTDPF(0, "GmmTexAlloc failed!");
goto ERROR_CASE;
}
if(CreateParams.pExistingSysMem &&
CreateParams.ExistingSysMemSize)
{
// Client provided own memory and is not assumed to be Gfx aligned
ExistingSysMem.IsGmmAllocated = 0;
ExistingSysMem.pExistingSysMem = CreateParams.pExistingSysMem;
ExistingSysMem.Size = CreateParams.ExistingSysMemSize;
// An upper dword of 0xffffffff is invalid and may mean the address
// was sign extended or came from a rogue UMD. In either case
// we can truncate the address down to 32 bits prevent attempts
// to access an invalid address range.
if((ExistingSysMem.pExistingSysMem & (0xffffffff00000000ull)) == (0xffffffff00000000ull))
{
ExistingSysMem.pExistingSysMem &= 0xffffffff;
}
//Align the base address to new ESM requirements.
if(!Surf.ExistingSysMem.IsPageAligned)
{
if(GMM_SUCCESS != ApplyExistingSysMemRestrictions())
{
GMM_ASSERTDPF(0, "Malloc'ed Sys Mem too small for gfx surface!");
goto ERROR_CASE;
}
}
else
{
ExistingSysMem.pVirtAddress =
ExistingSysMem.pGfxAlignedVirtAddress = CreateParams.pExistingSysMem;
}
if((ExistingSysMem.pVirtAddress + Surf.Size) >
(CreateParams.pExistingSysMem + ExistingSysMem.Size))
{
GMM_ASSERTDPF(0, "Malloc'ed Sys Mem too small for gfx surface");
goto ERROR_CASE;
}
}
else
{
__GMM_BUFFER_TYPE Restrictions = {0};
ExistingSysMem.IsGmmAllocated = 1;
Surf.ExistingSysMem.IsPageAligned = 1;
// Adjust memory size to compensate for Gfx alignment.
pTextureCalc->GetResRestrictions(&Surf, Restrictions);
ExistingSysMem.Size = Restrictions.Alignment + Surf.Size;
ExistingSysMem.pVirtAddress = (uint64_t)GMM_MALLOC(GFX_ULONG_CAST(ExistingSysMem.Size));
if(!ExistingSysMem.pVirtAddress)
{
GMM_ASSERTDPF(0, "Failed to allocate System Accelerated Memory.");
goto ERROR_CASE;
}
else
{
ExistingSysMem.pGfxAlignedVirtAddress = (uint64_t)GFX_ALIGN(ExistingSysMem.pVirtAddress, Restrictions.Alignment);
}
}
}
if(Is64KBPageSuitable() && pGmmGlobalContext->GetSkuTable().FtrLocalMemory)
{
// BaseAlignment can be greater than 64KB and needs to be aligned to 64KB
Surf.Alignment.BaseAlignment = GFX_MAX(GFX_ALIGN(Surf.Alignment.BaseAlignment, GMM_KBYTE(64)), GMM_KBYTE(64));
}
GMM_DPF_EXIT;
return GMM_SUCCESS;
ERROR_CASE:
//Zero out all the members
new(this) GmmResourceInfoCommon();
if(CreateParams.pPreallocatedResInfo)
{
this->GetResFlags().Info.__PreallocatedResInfo = 1; // Set flag if PreAllocated ResInfo has been set by the Client.
}
GMM_DPF_EXIT;
return Status;
}
void GmmLib::GmmResourceInfoCommon::UpdateUnAlignedParams()
{
uint32_t YHeight = 0, VHeight = 0;
uint32_t Height = 0, UmdUHeight = 0, UmdVHeight = 0;
uint32_t WidthBytesPhysical = GFX_ULONG_CAST(Surf.BaseWidth) * Surf.BitsPerPixel >> 3;
__GMM_ASSERTPTR(((Surf.TileMode < GMM_TILE_MODES) && (Surf.TileMode >= TILE_NONE)), VOIDRETURN);
GMM_DPF_ENTER;
Height = Surf.BaseHeight;
switch(Surf.Format)
{
case GMM_FORMAT_IMC1: // IMC1 = IMC3 with Swapped U/V
case GMM_FORMAT_IMC3:
case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3.
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// UUUU
// UUUU
// VVVV
// VVVV
case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width.
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// UUUUUUUU
// UUUUUUUU
// VVVVVVVV
// VVVVVVVV
{
YHeight = GFX_ALIGN(Surf.BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
VHeight = GFX_ALIGN(GFX_CEIL_DIV(Surf.BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT);
break;
}
case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width.
//YYYYYYYY
//YYYYYYYY
//YYYYYYYY
//YYYYYYYY
//UUUUUUUU
//VVVVVVVV
{
YHeight = GFX_ALIGN(Surf.BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
VHeight = GFX_ALIGN(GFX_CEIL_DIV(Surf.BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT);
break;
}
case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height.
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// UU
// UU
// UU
// UU
// VV
// VV
// VV
// VV
case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height.
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// UUUU
// UUUU
// UUUU
// UUUU
// VVVV
// VVVV
// VVVV
// VVVV
case GMM_FORMAT_BGRP:
case GMM_FORMAT_RGBP:
case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size.
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// UUUUUUUU
// UUUUUUUU
// UUUUUUUU
// UUUUUUUU
// VVVVVVVV
// VVVVVVVV
// VVVVVVVV
// VVVVVVVV
{
YHeight = GFX_ALIGN(Surf.BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
VHeight = GFX_ALIGN(Surf.BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
break;
}
case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V
case GMM_FORMAT_IMC4:
{
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// UUUUVVVV
// UUUUVVVV
__GMM_ASSERT((Surf.Pitch & 1) == 0);
YHeight = GFX_ALIGN(Surf.BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT);
VHeight = GFX_CEIL_DIV(YHeight, 2);
break;
}
case GMM_FORMAT_I420: // I420 = IYUV
case GMM_FORMAT_IYUV: // I420/IYUV = YV12 with Swapped U/V
case GMM_FORMAT_YV12:
case GMM_FORMAT_YVU9:
{
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// VVVVVV.. <-- V and U planes follow the Y plane, as linear
// ..UUUUUU arrays--without respect to pitch.
uint32_t YSize, YVSizeRShift, VSize, UOffset;
uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment;
YSize = GFX_ULONG_CAST(Surf.Pitch) * Surf.BaseHeight;
// YVU9 has one U/V pixel for each 4x4 Y block.
// The others have one U/V pixel for each 2x2 Y block.
// YVU9 has a Y:V size ratio of 16 (4x4 --> 1).
// The others have a ratio of 4 (2x2 --> 1).
YVSizeRShift = (Surf.Format != GMM_FORMAT_YVU9) ? 2 : 4;
// If a Y plane isn't fully-aligned to its Y-->U/V block size, the
// extra/unaligned Y pixels still need corresponding U/V pixels--So
// for the purpose of computing the UVSize, we must consider a
// dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would
// require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.)
YSizeForUVPurposesDimensionalAlignment = (Surf.Format != GMM_FORMAT_YVU9) ? 2 : 4;
YSizeForUVPurposes =
GFX_ALIGN(GFX_ULONG_CAST(Surf.Pitch), YSizeForUVPurposesDimensionalAlignment) *
GFX_ALIGN(Surf.BaseHeight, YSizeForUVPurposesDimensionalAlignment);
VSize = (YSizeForUVPurposes >> YVSizeRShift);
YHeight = GFX_CEIL_DIV(YSize + 2 * VSize, WidthBytesPhysical);
break;
}
case GMM_FORMAT_NV12:
case GMM_FORMAT_NV21:
case GMM_FORMAT_NV11:
case GMM_FORMAT_P010:
case GMM_FORMAT_P012:
case GMM_FORMAT_P016:
case GMM_FORMAT_P208:
{
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// YYYYYYYY
// [UV-Packing]
YHeight = GFX_ALIGN(Height, __GMM_EVEN_ROW);
if((Surf.Format == GMM_FORMAT_NV12) ||
(Surf.Format == GMM_FORMAT_NV21) ||
(Surf.Format == GMM_FORMAT_P010) ||
(Surf.Format == GMM_FORMAT_P012) ||
(Surf.Format == GMM_FORMAT_P016))
{
VHeight = GFX_CEIL_DIV(Height, 2);
}
else
{
VHeight = YHeight; // U/V plane is same as Y
}
break;
}
default:
{
GMM_ASSERTDPF(0, "Unknown Video Format U\n");
break;
}
}
Surf.OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] = YHeight;
if(Surf.OffsetInfo.Plane.NoOfPlanes == 2)
{
Surf.OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] = VHeight;
UmdUHeight = (GMM_GLOBAL_GFX_SIZE_T)((Surf.Size / Surf.Pitch) - Surf.OffsetInfo.Plane.Y[GMM_PLANE_U]);
}
else if(Surf.OffsetInfo.Plane.NoOfPlanes == 3)
{
Surf.OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] =
Surf.OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_V] = VHeight;
UmdUHeight = (GMM_GLOBAL_GFX_SIZE_T)(Surf.OffsetInfo.Plane.Y[GMM_PLANE_V] - Surf.OffsetInfo.Plane.Y[GMM_PLANE_U]);
UmdVHeight = (GMM_GLOBAL_GFX_SIZE_T)(((Surf.Size / Surf.Pitch) - Surf.OffsetInfo.Plane.Y[GMM_PLANE_U]) / 2);
__GMM_ASSERTPTR((UmdUHeight == UmdVHeight), VOIDRETURN);
}
__GMM_ASSERTPTR(((Surf.OffsetInfo.Plane.Y[GMM_PLANE_U] == YHeight) && (UmdUHeight == VHeight)), VOIDRETURN);
}
/////////////////////////////////////////////////////////////////////////////////////
/// This function calculates number of planes required for the given input format
/// and allocates texture info for the respective planes.
///
/// @return ::bool
/////////////////////////////////////////////////////////////////////////////////////
bool GmmLib::GmmResourceInfoCommon::RedescribePlanes()
{
const GMM_PLATFORM_INFO *pPlatform;
GMM_TEXTURE_CALC * pTextureCalc = NULL;
GMM_STATUS Status = GMM_SUCCESS;
int MaxPlanes = 1;
pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf);
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
__GMM_ASSERT(Surf.Flags.Info.RedecribedPlanes);
GMM_TEXTURE_INFO *pYPlane = &PlaneSurf[GMM_PLANE_Y];
GMM_TEXTURE_INFO *pUPlane = &PlaneSurf[GMM_PLANE_U];
GMM_TEXTURE_INFO *pVPlane = &PlaneSurf[GMM_PLANE_V];
pYPlane->Type = Surf.Type;
pYPlane->BaseWidth = Surf.BaseWidth;
pYPlane->BaseHeight = Surf.BaseHeight;
pYPlane->Depth = Surf.Depth;
pYPlane->ArraySize = Surf.ArraySize;
pYPlane->MSAA = Surf.MSAA;
pYPlane->Flags = Surf.Flags;
pYPlane->BitsPerPixel = Surf.BitsPerPixel;
#if(_DEBUG || _RELEASE_INTERNAL)
pYPlane->Platform = Surf.Platform;
#endif
pYPlane->Flags.Info.RedecribedPlanes = false;
*pUPlane = *pVPlane = *pYPlane;
if(GmmIsUVPacked(Surf.Format))
{
// UV packed resources must have two seperate
// tiling modes per plane, due to the packed
// UV plane having twice the bits per pixel
// as the Y plane.
if(Surf.BitsPerPixel == 8)
{
pYPlane->BitsPerPixel = 8;
pYPlane->Format = GMM_FORMAT_R8_UINT;
pUPlane->BitsPerPixel = 16;
pUPlane->Format = GMM_FORMAT_R16_UINT;
}
else if(Surf.BitsPerPixel == 16)
{
pYPlane->BitsPerPixel = 16;
pYPlane->Format = GMM_FORMAT_R16_UINT;
pUPlane->BitsPerPixel = 32;
pUPlane->Format = GMM_FORMAT_R32_UINT;
}
else
{
GMM_ASSERTDPF(0, "Unsupported format/pixel size combo!");
Status = GMM_INVALIDPARAM;
goto ERROR_CASE;
}
pUPlane->BaseHeight = GFX_CEIL_DIV(pYPlane->BaseHeight, 2);
pUPlane->BaseWidth = GFX_CEIL_DIV(pYPlane->BaseWidth, 2);
MaxPlanes = 2;
}
else
{
// Non-UV packed surfaces only require the plane descriptors
// have proper height and width for each plane
switch(Surf.Format)
{
case GMM_FORMAT_IMC1:
case GMM_FORMAT_IMC2:
case GMM_FORMAT_IMC3:
case GMM_FORMAT_IMC4:
case GMM_FORMAT_MFX_JPEG_YUV420:
{
pUPlane->BaseWidth = pVPlane->BaseWidth = GFX_CEIL_DIV(pYPlane->BaseWidth, 2);
}
case GMM_FORMAT_MFX_JPEG_YUV422V:
{
pUPlane->BaseHeight = pVPlane->BaseHeight = GFX_CEIL_DIV(pYPlane->BaseHeight, 2);
break;
}
case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE:
{
pUPlane->BaseHeight = pVPlane->BaseHeight = GFX_CEIL_DIV(pYPlane->BaseHeight, 4);
break;
}
case GMM_FORMAT_MFX_JPEG_YUV411:
{
pUPlane->BaseWidth = pVPlane->BaseWidth = GFX_CEIL_DIV(pYPlane->BaseWidth, 4);
break;
}
case GMM_FORMAT_MFX_JPEG_YUV422H:
{
pUPlane->BaseWidth = pVPlane->BaseWidth = GFX_CEIL_DIV(pYPlane->BaseWidth, 2);
break;
}
default:
{
break;
}
}
pYPlane->Format = pUPlane->Format = pVPlane->Format =
(pYPlane->BitsPerPixel == 8) ? GMM_FORMAT_R8_UINT : GMM_FORMAT_R16_UINT;
MaxPlanes = 3;
}
for(int i = GMM_PLANE_Y; i <= MaxPlanes; i++) // all 2 or 3 planes
{
if((GMM_SUCCESS != pTextureCalc->AllocateTexture(&PlaneSurf[i])))
{
GMM_ASSERTDPF(false, "GmmTexAlloc failed!");
Status = GMM_ERROR;
goto ERROR_CASE;
}
}
Status = static_cast<GMM_STATUS>(false == ReAdjustPlaneProperties(false));
ERROR_CASE:
return (Status == GMM_SUCCESS) ? true : false;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns downscaled width for fast clear of given subresource
/// @param[in] uint32_t : MipLevel
/// @return Width
/////////////////////////////////////////////////////////////////////////////////////
uint64_t GmmLib::GmmResourceInfoCommon::GetFastClearWidth(uint32_t MipLevel)
{
uint64_t width = 0;
uint64_t mipWidth = GetMipWidth(MipLevel);
uint32_t numSamples = GetNumSamples();
GMM_TEXTURE_CALC *pTextureCalc;
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
if(numSamples == 1)
{
width = pTextureCalc->ScaleFCRectWidth(&Surf, mipWidth);
}
else if(numSamples == 2 || numSamples == 4)
{
width = GFX_ALIGN(mipWidth, 8) / 8;
}
else if(numSamples == 8)
{
width = GFX_ALIGN(mipWidth, 2) / 2;
}
else // numSamples == 16
{
width = mipWidth;
}
return width;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns downscaled height for fast clear of given subresource
/// @param[in] uint32_t : MipLevel
/// @return height
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GmmLib::GmmResourceInfoCommon::GetFastClearHeight(uint32_t MipLevel)
{
uint32_t height = 0;
uint32_t mipHeight = GetMipHeight(MipLevel);
uint32_t numSamples = GetNumSamples();
GMM_TEXTURE_CALC *pTextureCalc;
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
if(numSamples == 1)
{
height = pTextureCalc->ScaleFCRectHeight(&Surf, mipHeight);
}
else
{
height = GFX_ALIGN(mipHeight, 2) / 2;
}
return height;
}
/////////////////////////////////////////////////////////////////////////////////////
/// This function readjustes Plane properties. Valid for MainSurf not for AuxSurf
///
/// @param[in] bool: Whether Surf is Aux
///
/// @return ::bool
/////////////////////////////////////////////////////////////////////////////////////
bool GmmLib::GmmResourceInfoCommon::ReAdjustPlaneProperties(bool IsAuxSurf)
{
const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf);
GMM_TEXTURE_INFO * pTexInfo = &Surf;
GMM_TEXTURE_INFO * pPlaneTexInfo = PlaneSurf;
if(IsAuxSurf)
{
//AuxSurf isn't redescribed
return false;
}
if(GmmIsUVPacked(pTexInfo->Format))
{
pPlaneTexInfo[GMM_PLANE_V] = pPlaneTexInfo[GMM_PLANE_U];
// Need to adjust the returned surfaces and then copy
// the relivent data into the parent descriptor.
// UV plane is wider while Y plane is taller,
// so adjust pitch and sizes to fit accordingly
pTexInfo->Alignment = pPlaneTexInfo[GMM_PLANE_U].Alignment;
pTexInfo->Alignment.VAlign = pPlaneTexInfo[GMM_PLANE_Y].Alignment.VAlign;
if(pPlaneTexInfo[GMM_PLANE_Y].Pitch != pPlaneTexInfo[GMM_PLANE_U].Pitch)
{
pPlaneTexInfo[GMM_PLANE_Y].Size = (pPlaneTexInfo[GMM_PLANE_Y].Size / pPlaneTexInfo[GMM_PLANE_Y].Pitch) * pPlaneTexInfo[GMM_PLANE_U].Pitch;
__GMM_ASSERT(GFX_IS_ALIGNED(pPlaneTexInfo[GMM_PLANE_Y].Size, pPlatform->TileInfo[pPlaneTexInfo[GMM_PLANE_Y].TileMode].LogicalSize));
if(pPlaneTexInfo[GMM_PLANE_Y].ArraySize > 1)
{
pPlaneTexInfo[GMM_PLANE_Y].OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender =
pPlaneTexInfo[GMM_PLANE_Y].OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock =
pPlaneTexInfo[GMM_PLANE_Y].Size / pPlaneTexInfo[GMM_PLANE_Y].ArraySize;
}
pTexInfo->Pitch = pPlaneTexInfo[GMM_PLANE_Y].Pitch = pPlaneTexInfo[GMM_PLANE_U].Pitch;
}
pTexInfo->OffsetInfo.Plane.ArrayQPitch =
pPlaneTexInfo[GMM_PLANE_Y].OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender +
pPlaneTexInfo[GMM_PLANE_U].OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender;
pTexInfo->Size = pPlaneTexInfo[GMM_PLANE_Y].Size + pPlaneTexInfo[GMM_PLANE_U].Size;
if(pTexInfo->Size > (GMM_GFX_SIZE_T)(pPlatform->SurfaceMaxSize))
{
GMM_ASSERTDPF(0, "Surface too large!");
return false;
}
}
else
{
// The parent resource should be the same size as all of the child planes
__GMM_ASSERT(pTexInfo->Size == (pPlaneTexInfo[GMM_PLANE_Y].Size +
pPlaneTexInfo[GMM_PLANE_U].Size + pPlaneTexInfo[GMM_PLANE_U].Size));
}
return true;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns the Platform info. If Platform has been overriden by the clients, then
/// it returns the overriden Platform Info struct.
/// @return Reference to the relevent ::GMM_PLATFORM_INFO
/////////////////////////////////////////////////////////////////////////////////////
const GMM_PLATFORM_INFO &GmmLib::GmmResourceInfoCommon::GetPlatformInfo()
{
#if(defined(__GMM_KMD__) && (_DEBUG || _RELEASE_INTERNAL))
if(GFX_GET_CURRENT_RENDERCORE(Surf.Platform) != GFX_GET_CURRENT_RENDERCORE(((Context *)pGmmLibContext)->GetPlatformInfo().Platform))
{
return ((Context *)pGmmLibContext)->GetOverridePlatformInfo();
}
else
{
return ((Context *)pGmmLibContext)->GetPlatformInfo();
}
#else
return ((Context *)pGmmLibContext)->GetPlatformInfo();
#endif
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns width padded to HAlign. Only called for special flags. See asserts in
/// function for which surfaces are supported.
///
/// @param[in] MipLevel Mip level for which the width is requested
/// @return Padded Width
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetPaddedWidth(uint32_t MipLevel)
{
GMM_TEXTURE_CALC *pTextureCalc;
uint32_t AlignedWidth;
GMM_GFX_SIZE_T MipWidth;
uint32_t HAlign;
__GMM_ASSERT(MipLevel <= Surf.MaxLod);
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
// This shall be called for Depth and Separate Stencil main surface resource
// This shall be called for the Aux surfaces (MCS, CCS and Hiz) too.
// MCS will have Surf.Flags.Gpu.CCS set
// Hiz will have Surf.Flags.Gpu.HiZ set
__GMM_ASSERT(Surf.Flags.Gpu.Depth || Surf.Flags.Gpu.SeparateStencil ||
Surf.Flags.Gpu.CCS || Surf.Flags.Gpu.HiZ ||
AuxSurf.Flags.Gpu.__MsaaTileMcs ||
AuxSurf.Flags.Gpu.CCS || AuxSurf.Flags.Gpu.__NonMsaaTileYCcs);
MipWidth = pTextureCalc->GmmTexGetMipWidth(&Surf, MipLevel);
HAlign = Surf.Alignment.HAlign;
if(AuxSurf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaTileYCcs)
{
HAlign = AuxSurf.Alignment.HAlign;
}
AlignedWidth = __GMM_EXPAND_WIDTH(pTextureCalc,
GFX_ULONG_CAST(MipWidth),
HAlign,
&Surf);
if(Surf.Flags.Gpu.SeparateStencil)
{
if(Surf.Flags.Info.TiledW)
{
AlignedWidth *= 2;
}
// Reverse MSAA Expansion ////////////////////////////////////////////////
// It might seem strange that we ExpandWidth (with consideration for MSAA)
// only to "reverse" the MSAA portion of the expansion...It's an order-of-
// operations thing--The intention of the reversal isn't to have
// disregarded the original MSAA expansion but to produce a width, that
// when MSAA'ed will match the true physical width (which requires MSAA
// consideration to compute).
switch(Surf.MSAA.NumSamples)
{
case 1:
break;
case 2: // Same as 4x...
case 4:
AlignedWidth /= 2;
break;
case 8: // Same as 16x...
case 16:
AlignedWidth /= 4;
break;
default:
__GMM_ASSERT(0);
}
}
// CCS Aux surface, Aligned width needs to be scaled based on main surface bpp
if(AuxSurf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaTileYCcs)
{
AlignedWidth = pTextureCalc->ScaleTextureWidth(&AuxSurf, AlignedWidth);
}
return AlignedWidth;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns height padded to VAlign. Only called for special flags. See asserts in
/// function for which surfaces are supported.
///
/// @param[in] MipLevel Mip level for which the height is requested
/// @return Padded height
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetPaddedHeight(uint32_t MipLevel)
{
GMM_TEXTURE_CALC *pTextureCalc;
uint32_t AlignedHeight, MipHeight;
uint32_t VAlign;
__GMM_ASSERT(MipLevel <= Surf.MaxLod);
// See note in GmmResGetPaddedWidth.
__GMM_ASSERT(Surf.Flags.Gpu.Depth || Surf.Flags.Gpu.SeparateStencil ||
Surf.Flags.Gpu.CCS || Surf.Flags.Gpu.HiZ ||
AuxSurf.Flags.Gpu.__MsaaTileMcs ||
AuxSurf.Flags.Gpu.CCS || AuxSurf.Flags.Gpu.__NonMsaaTileYCcs);
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
MipHeight = pTextureCalc->GmmTexGetMipHeight(&Surf, MipLevel);
VAlign = Surf.Alignment.VAlign;
if(AuxSurf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaTileYCcs)
{
VAlign = AuxSurf.Alignment.VAlign;
}
AlignedHeight = __GMM_EXPAND_HEIGHT(pTextureCalc,
MipHeight,
VAlign,
&Surf);
if(Surf.Flags.Gpu.SeparateStencil)
{
if(Surf.Flags.Info.TiledW)
{
AlignedHeight /= 2;
}
// Reverse MSAA Expansion ////////////////////////////////////////////////
// See note in GmmResGetPaddedWidth.
switch(Surf.MSAA.NumSamples)
{
case 1:
break;
case 2:
break; // No height adjustment for 2x...
case 4: // Same as 8x...
case 8:
AlignedHeight /= 2;
break;
case 16:
AlignedHeight /= 4;
break;
default:
__GMM_ASSERT(0);
}
}
// CCS Aux surface, AlignedHeight needs to be scaled by 16
if(AuxSurf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaTileYCcs)
{
AlignedHeight = pTextureCalc->ScaleTextureHeight(&AuxSurf, AlignedHeight);
}
return AlignedHeight;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns pitch padded to VAlign. Only called for special flags. See asserts in
/// function for which surfaces are supported.
///
/// @param[in] MipLevel Mip level for which the pitch is requested
/// @return Padded pitch
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetPaddedPitch(uint32_t MipLevel)
{
uint32_t AlignedWidth;
uint32_t AlignedPitch;
uint32_t BitsPerPixel;
__GMM_ASSERT(MipLevel <= Surf.MaxLod);
// See note in GetPaddedWidth.
AlignedWidth = GetPaddedWidth(MipLevel);
BitsPerPixel = Surf.BitsPerPixel;
if(AuxSurf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaTileYCcs)
{
BitsPerPixel = 8; //Aux surface are 8bpp
}
AlignedPitch = AlignedWidth * BitsPerPixel >> 3;
return AlignedPitch;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns resource's QPitch.
///
/// @return QPitch
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetQPitch()
{
const GMM_PLATFORM_INFO *pPlatform;
uint32_t QPitch;
pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf);
__GMM_ASSERT(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE);
__GMM_ASSERT((Surf.Type != RESOURCE_3D) ||
(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE));
// 2D/CUBE ==> distance in rows between array slices
// 3D ==> distance in rows between R-slices
// Compressed ==> one row contains a complete compression block vertically
// HiZ ==> HZ_PxPerByte * HZ_QPitch
// Stencil ==> logical, i.e. not halved
if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) &&
GmmIsCompressed(Surf.Format))
{
QPitch = Surf.Alignment.QPitch / GetCompressionBlockHeight();
if((Surf.Type == RESOURCE_3D) && !Surf.Flags.Info.Linear)
{
const GMM_TILE_MODE TileMode = Surf.TileMode;
__GMM_ASSERT(TileMode < GMM_TILE_MODES);
QPitch = GFX_ALIGN(QPitch, pPlatform->TileInfo[TileMode].LogicalTileHeight);
}
}
else if(Surf.Flags.Gpu.HiZ)
{
QPitch = Surf.Alignment.QPitch * pPlatform->HiZPixelsPerByte;
}
else
{
QPitch = Surf.Alignment.QPitch;
}
return QPitch;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns offset information to a particular mip map or plane.
///
/// @param[in][out] Has info about which offset client is requesting. Offset is also
/// passed back to the client in this parameter.
/// @return ::GMM_STATUS
/////////////////////////////////////////////////////////////////////////////////////
GMM_STATUS GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetOffset(GMM_REQ_OFFSET_INFO &ReqInfo)
{
GMM_TEXTURE_CALC *pTextureCalc;
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
__GMM_ASSERT((pTextureCalc != NULL))
if(Surf.Flags.Info.RedecribedPlanes)
{
uint8_t RestoreReqStdLayout = ReqInfo.ReqStdLayout ? 1 : 0;
// Lock and Render offsets do not require additional handling
if(ReqInfo.ReqLock || ReqInfo.ReqRender)
{
ReqInfo.ReqStdLayout = 0;
GmmTexGetMipMapOffset(&Surf, &ReqInfo);
ReqInfo.ReqStdLayout = RestoreReqStdLayout;
}
if(ReqInfo.ReqStdLayout)
{
GMM_REQ_OFFSET_INFO TempReqInfo[GMM_MAX_PLANE] = {0};
GMM_TEXTURE_INFO TexInfo[GMM_MAX_PLANE];
uint32_t Plane, TotalPlanes = GmmLib::Utility::GmmGetNumPlanes(Surf.Format);
// Caller must specify which plane they need the offset into if not
// getting the whole surface size
if(ReqInfo.Plane >= GMM_MAX_PLANE ||
(ReqInfo.StdLayout.Offset != -1 && !ReqInfo.Plane))
{
__GMM_ASSERT(0);
return GMM_ERROR;
}
TempReqInfo[GMM_PLANE_Y] = *&ReqInfo;
TempReqInfo[GMM_PLANE_Y].Plane = GMM_NO_PLANE;
TempReqInfo[GMM_PLANE_Y].ReqLock = TempReqInfo[GMM_PLANE_Y].ReqRender = 0;
TempReqInfo[GMM_PLANE_V] = TempReqInfo[GMM_PLANE_U] = TempReqInfo[GMM_PLANE_Y];
pTextureCalc->GetRedescribedPlaneParams(&Surf, GMM_PLANE_Y, &TexInfo[GMM_PLANE_Y]);
pTextureCalc->GetRedescribedPlaneParams(&Surf, GMM_PLANE_U, &TexInfo[GMM_PLANE_U]);
pTextureCalc->GetRedescribedPlaneParams(&Surf, GMM_PLANE_V, &TexInfo[GMM_PLANE_V]);
if(GMM_SUCCESS != GmmTexGetMipMapOffset(&TexInfo[GMM_PLANE_Y], &TempReqInfo[GMM_PLANE_Y]) ||
GMM_SUCCESS != GmmTexGetMipMapOffset(&TexInfo[GMM_PLANE_U], &TempReqInfo[GMM_PLANE_U]) ||
GMM_SUCCESS != GmmTexGetMipMapOffset(&TexInfo[GMM_PLANE_V], &TempReqInfo[GMM_PLANE_V]))
{
__GMM_ASSERT(0);
return GMM_ERROR;
}
ReqInfo.StdLayout.TileDepthPitch = TempReqInfo[ReqInfo.Plane].StdLayout.TileDepthPitch;
ReqInfo.StdLayout.TileRowPitch = TempReqInfo[ReqInfo.Plane].StdLayout.TileRowPitch;
if(ReqInfo.StdLayout.Offset == -1)
{
// Special request to get the StdLayout size
ReqInfo.StdLayout.Offset = TempReqInfo[ReqInfo.Plane].StdLayout.Offset;
if(!ReqInfo.Plane)
{
for(Plane = GMM_PLANE_Y; Plane <= TotalPlanes; Plane++)
{
ReqInfo.StdLayout.Offset += TempReqInfo[Plane].StdLayout.Offset;
}
}
}
else
{
ReqInfo.StdLayout.Offset = TempReqInfo[ReqInfo.Plane].StdLayout.Offset;
for(Plane = GMM_PLANE_Y; Plane < (uint32_t)ReqInfo.Plane; Plane++)
{
// Find the size of the previous planes and add it to the offset
TempReqInfo[Plane].StdLayout.Offset = -1;
if(GMM_SUCCESS != GmmTexGetMipMapOffset(&TexInfo[Plane], &TempReqInfo[Plane]))
{
__GMM_ASSERT(0);
return GMM_ERROR;
}
ReqInfo.StdLayout.Offset += TempReqInfo[Plane].StdLayout.Offset;
}
}
}
return GMM_SUCCESS;
}
else
{
return GmmTexGetMipMapOffset(&Surf, &ReqInfo);
}
}
/////////////////////////////////////////////////////////////////////////////////////
/// Performs a CPU BLT between a specified GPU resource and a system memory surface,
/// as defined by the GMM_RES_COPY_BLT descriptor.
///
/// @param[in] pBlt: Describes the blit operation. See ::GMM_RES_COPY_BLT for more info.
/// @return 1 if succeeded, 0 otherwise
/////////////////////////////////////////////////////////////////////////////////////
uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::CpuBlt(GMM_RES_COPY_BLT *pBlt)
{
#define REQUIRE(e) \
if(!(e)) \
{ \
__GMM_ASSERT(0); \
Success = 0; \
goto EXIT; \
}
const GMM_PLATFORM_INFO *pPlatform;
uint8_t Success = 1;
GMM_TEXTURE_INFO * pTexInfo;
GMM_TEXTURE_CALC * pTextureCalc;
GMM_TEXTURE_INFO RedescribedPlaneInfo;
__GMM_ASSERTPTR(pBlt, 0);
pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf);
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
__GMM_ASSERT(
Surf.Type == RESOURCE_1D ||
Surf.Type == RESOURCE_2D ||
Surf.Type == RESOURCE_PRIMARY ||
Surf.Type == RESOURCE_CUBE ||
Surf.Type == RESOURCE_3D);
__GMM_ASSERT(pBlt->Gpu.MipLevel <= Surf.MaxLod);
__GMM_ASSERT(Surf.MSAA.NumSamples <= 1); // Supported by CpuSwizzleBlt--but not yet this function.
__GMM_ASSERT(!Surf.Flags.Gpu.Depth || Surf.MSAA.NumSamples <= 1); // MSAA depth currently ends up with a few exchange swizzles--CpuSwizzleBlt could support with expanded XOR'ing, but probably no use case.
__GMM_ASSERT(!(
pBlt->Blt.Upload &&
Surf.Flags.Gpu.Depth &&
(Surf.BitsPerPixel == 32) &&
(pBlt->Sys.PixelPitch == 4) &&
(pBlt->Blt.BytesPerPixel == 3))); // When uploading D24 data from D24S8 to D24X8, no harm in copying S8 to X8 and upload will then be faster.
pTexInfo = &(Surf);
// YUV Planar surface
if(pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes && GmmIsPlanar(Surf.Format))
{
uint32_t PlaneId = GMM_NO_PLANE;
uint32_t TotalHeight = 0;
if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 2)
{
TotalHeight = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] +
pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U]);
}
else if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 3)
{
TotalHeight = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] +
pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] +
pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_V]);
}
else
{
TotalHeight = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y]); //YV12 exception
}
// Determine if BLT rectange is for monolithic surface or contained in specific Y/UV plane
if(((pBlt->Gpu.OffsetY + pBlt->Blt.Height <= Surf.OffsetInfo.Plane.Y[GMM_PLANE_U]) || pTexInfo->OffsetInfo.Plane.NoOfPlanes == 1) &&
(pBlt->Gpu.OffsetX + pBlt->Blt.Width <= Surf.BaseWidth))
{
PlaneId = GMM_PLANE_Y;
}
else if(pBlt->Gpu.OffsetY >= Surf.OffsetInfo.Plane.Y[GMM_PLANE_U] &&
(pBlt->Gpu.OffsetY + pBlt->Blt.Height <= (Surf.OffsetInfo.Plane.Y[GMM_PLANE_U] + pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U])) &&
(pBlt->Gpu.OffsetX + pBlt->Blt.Width <= Surf.BaseWidth))
{
PlaneId = GMM_PLANE_U;
}
else if(pBlt->Gpu.OffsetY >= Surf.OffsetInfo.Plane.Y[GMM_PLANE_V] &&
(pBlt->Gpu.OffsetY + pBlt->Blt.Height <= (Surf.OffsetInfo.Plane.Y[GMM_PLANE_V] + pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U])) &&
(pBlt->Gpu.OffsetX + pBlt->Blt.Width <= Surf.BaseWidth))
{
PlaneId = GMM_PLANE_V;
}
// For smaller surface, BLT rect may fall in Y Plane due to tile alignment but user may have requested monolithic BLT
if(pBlt->Gpu.OffsetX == 0 &&
pBlt->Gpu.OffsetY == 0 &&
pBlt->Blt.Height >= TotalHeight)
{
PlaneId = GMM_MAX_PLANE;
}
if(PlaneId == GMM_MAX_PLANE)
{
// TODO BLT rect should not overlap between planes.
{
// __GMM_ASSERT(0); // decide later, for now blt it
//return 0;
}
// BLT monolithic surface per plane and remove padding due to tiling.
for(PlaneId = GMM_PLANE_Y; PlaneId <= pTexInfo->OffsetInfo.Plane.NoOfPlanes; PlaneId++)
{
if(PlaneId == GMM_PLANE_Y)
{
pBlt->Gpu.OffsetX = GFX_ULONG_CAST(Surf.OffsetInfo.Plane.X[GMM_PLANE_Y]);
pBlt->Gpu.OffsetY = GFX_ULONG_CAST(Surf.OffsetInfo.Plane.Y[GMM_PLANE_Y]);
pBlt->Blt.Height = GFX_ULONG_CAST(Surf.OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y]);
}
else if(PlaneId == GMM_PLANE_U)
{
pBlt->Gpu.OffsetX = GFX_ULONG_CAST(Surf.OffsetInfo.Plane.X[GMM_PLANE_U]);
pBlt->Gpu.OffsetY = GFX_ULONG_CAST(Surf.OffsetInfo.Plane.Y[GMM_PLANE_U]);
pBlt->Sys.pData = (char *)pBlt->Sys.pData + uint32_t(pBlt->Blt.Height * pBlt->Sys.RowPitch);
pBlt->Blt.Height = GFX_ULONG_CAST(Surf.OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U]);
if(Surf.Flags.Info.RedecribedPlanes)
{
__GMM_ASSERT(0);
}
}
else
{
pBlt->Gpu.OffsetX = GFX_ULONG_CAST(Surf.OffsetInfo.Plane.X[GMM_PLANE_V]);
pBlt->Gpu.OffsetY = GFX_ULONG_CAST(Surf.OffsetInfo.Plane.Y[GMM_PLANE_V]);
pBlt->Blt.Height = GFX_ULONG_CAST(Surf.OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U]);
pBlt->Sys.pData = (char *)pBlt->Sys.pData + uint32_t(pBlt->Blt.Height * pBlt->Sys.RowPitch);
}
CpuBlt(pBlt);
}
}
// else continue below
}
// UV packed planar surfaces will have different tiling geometries for the
// Y and UV planes. Blts cannot span across the tiling boundaries and we
// must select the proper mode for each plane. Non-UV packed formats will
// have a constant tiling mode, and so do not have the same limits
if(Surf.Flags.Info.RedecribedPlanes &&
GmmIsUVPacked(Surf.Format))
{
if(!((pBlt->Gpu.OffsetY >= pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]) ||
((pBlt->Gpu.OffsetY + pBlt->Blt.Height) <= pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U])))
{
__GMM_ASSERT(0);
return false;
}
if(pBlt->Gpu.OffsetY < pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U])
{
pTextureCalc->GetRedescribedPlaneParams(pTexInfo, GMM_PLANE_Y, &RedescribedPlaneInfo);
// Y Plane
pTexInfo = &RedescribedPlaneInfo;
}
else
{
// UV Plane
pTextureCalc->GetRedescribedPlaneParams(pTexInfo, GMM_PLANE_U, &RedescribedPlaneInfo);
pTexInfo = &RedescribedPlaneInfo;
}
}
if(pBlt->Blt.Slices > 1)
{
GMM_RES_COPY_BLT SliceBlt = *pBlt;
uint32_t Slice;
SliceBlt.Blt.Slices = 1;
for(Slice = pBlt->Gpu.Slice;
Slice < (pBlt->Gpu.Slice + pBlt->Blt.Slices);
Slice++)
{
SliceBlt.Gpu.Slice = Slice;
SliceBlt.Sys.pData = (void *)((char *)pBlt->Sys.pData + (Slice - pBlt->Gpu.Slice) * pBlt->Sys.SlicePitch);
SliceBlt.Sys.BufferSize = pBlt->Sys.BufferSize - GFX_ULONG_CAST((char *)SliceBlt.Sys.pData - (char *)pBlt->Sys.pData);
CpuBlt(&SliceBlt);
}
}
else // Single Subresource...
{
uint32_t ResPixelPitch = pTexInfo->BitsPerPixel / CHAR_BIT;
uint32_t BlockWidth, BlockHeight, BlockDepth;
uint32_t __CopyWidthBytes, __CopyHeight, __OffsetXBytes, __OffsetY;
GMM_REQ_OFFSET_INFO GetOffset = {0};
pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &BlockWidth, &BlockHeight, &BlockDepth);
#if(LHDM)
if(pTexInfo->MsFormat == D3DDDIFMT_G8R8_G8B8 ||
pTexInfo->MsFormat == D3DDDIFMT_R8G8_B8G8)
{
BlockWidth = 2;
ResPixelPitch = 4;
}
#endif
{ // __CopyWidthBytes...
uint32_t Width;
if(!pBlt->Blt.Width) // i.e. "Full Width"
{
__GMM_ASSERT(!GmmIsPlanar(pTexInfo->Format)); // Caller must set Blt.Width--GMM "auto-size on zero" not supported with planars since multiple interpretations would confuse more than help.
Width = GFX_ULONG_CAST(pTextureCalc->GmmTexGetMipWidth(pTexInfo, pBlt->Gpu.MipLevel));
__GMM_ASSERT(Width >= pBlt->Gpu.OffsetX);
Width -= pBlt->Gpu.OffsetX;
__GMM_ASSERT(Width);
}
else
{
Width = pBlt->Blt.Width;
}
if(((pBlt->Sys.PixelPitch == 0) ||
(pBlt->Sys.PixelPitch == ResPixelPitch)) &&
((pBlt->Blt.BytesPerPixel == 0) ||
(pBlt->Blt.BytesPerPixel == ResPixelPitch)))
{
// Full-Pixel BLT...
__CopyWidthBytes =
GFX_CEIL_DIV(Width, BlockWidth) * ResPixelPitch;
}
else // Partial-Pixel BLT...
{
__GMM_ASSERT(BlockWidth == 1); // No partial-pixel support for block-compressed formats.
// When copying between surfaces with different pixel pitches,
// specify CopyWidthBytes in terms of unswizzled surface
// (convenient convention used by CpuSwizzleBlt).
__CopyWidthBytes =
Width *
(pBlt->Sys.PixelPitch ?
pBlt->Sys.PixelPitch :
ResPixelPitch);
}
}
{ // __CopyHeight...
if(!pBlt->Blt.Height) // i.e. "Full Height"
{
__GMM_ASSERT(!GmmIsPlanar(pTexInfo->Format)); // Caller must set Blt.Height--GMM "auto-size on zero" not supported with planars since multiple interpretations would confuse more than help.
__CopyHeight = pTextureCalc->GmmTexGetMipHeight(pTexInfo, pBlt->Gpu.MipLevel);
__GMM_ASSERT(__CopyHeight >= pBlt->Gpu.OffsetY);
__CopyHeight -= pBlt->Gpu.OffsetY;
__GMM_ASSERT(__CopyHeight);
}
else
{
__CopyHeight = pBlt->Blt.Height;
}
__CopyHeight = GFX_CEIL_DIV(__CopyHeight, BlockHeight);
}
__GMM_ASSERT((pBlt->Gpu.OffsetX % BlockWidth) == 0);
__OffsetXBytes = (pBlt->Gpu.OffsetX / BlockWidth) * ResPixelPitch + pBlt->Gpu.OffsetSubpixel;
__GMM_ASSERT((pBlt->Gpu.OffsetY % BlockHeight) == 0);
__OffsetY = (pBlt->Gpu.OffsetY / BlockHeight);
{ // Get pResData Offsets to this subresource...
GetOffset.ReqLock = pTexInfo->Flags.Info.Linear;
GetOffset.ReqStdLayout = !GetOffset.ReqLock && pTexInfo->Flags.Info.StdSwizzle;
GetOffset.ReqRender = !GetOffset.ReqLock && !GetOffset.ReqStdLayout;
GetOffset.MipLevel = pBlt->Gpu.MipLevel;
switch(pTexInfo->Type)
{
case RESOURCE_1D:
case RESOURCE_2D:
case RESOURCE_PRIMARY:
{
GetOffset.ArrayIndex = pBlt->Gpu.Slice;
break;
}
case RESOURCE_CUBE:
{
GetOffset.ArrayIndex = pBlt->Gpu.Slice / 6;
GetOffset.CubeFace = (GMM_CUBE_FACE_ENUM)(pBlt->Gpu.Slice % 6);
break;
}
case RESOURCE_3D:
{
GetOffset.Slice = (GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf) ?
(pBlt->Gpu.Slice / pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth) :
pBlt->Gpu.Slice;
break;
}
default:
__GMM_ASSERT(0);
}
REQUIRE(this->GetOffset(GetOffset) == GMM_SUCCESS);
}
if(pTexInfo->Flags.Info.Linear)
{
char * pDest, *pSrc;
uint32_t DestPitch, SrcPitch;
uint32_t y;
__GMM_ASSERT( // Linear-to-linear subpixel BLT unexpected--Not implemented.
(!pBlt->Sys.PixelPitch || (pBlt->Sys.PixelPitch == ResPixelPitch)) &&
(!pBlt->Blt.BytesPerPixel || (pBlt->Blt.BytesPerPixel == ResPixelPitch)));
if(pBlt->Blt.Upload)
{
pDest = (char *)pBlt->Gpu.pData;
DestPitch = GFX_ULONG_CAST(pTexInfo->Pitch);
pSrc = (char *)pBlt->Sys.pData;
SrcPitch = pBlt->Sys.RowPitch;
}
else
{
pDest = (char *)pBlt->Sys.pData;
DestPitch = pBlt->Sys.RowPitch;
pSrc = (char *)pBlt->Gpu.pData;
SrcPitch = GFX_ULONG_CAST(pTexInfo->Pitch);
}
__GMM_ASSERT(GetOffset.Lock.Offset < pTexInfo->Size);
pDest += GetOffset.Lock.Offset + (__OffsetY * DestPitch + __OffsetXBytes);
for(y = 0; y < __CopyHeight; y++)
{
// Memcpy per row isn't optimal, but doubt this linear-to-linear path matters.
#if _WIN32
#ifdef __GMM_KMD__
GFX_MEMCPY_S
#else
memcpy_s
#endif
(pDest, __CopyWidthBytes, pSrc, __CopyWidthBytes);
#else
memcpy(pDest, pSrc, __CopyWidthBytes);
#endif
pDest += DestPitch;
pSrc += SrcPitch;
}
}
else // Swizzled BLT...
{
CPU_SWIZZLE_BLT_SURFACE LinearSurface = {0}, SwizzledSurface;
uint32_t ZOffset = 0;
__GMM_ASSERT(GetOffset.Render.Offset64 < pTexInfo->Size);
ZOffset = (pTexInfo->Type == RESOURCE_3D &&
(GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf)) ?
(pBlt->Gpu.Slice % pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth) :
0;
if(pTexInfo->Flags.Info.StdSwizzle == 1)
{
SwizzledSurface.pBase = (char *)pBlt->Gpu.pData + GFX_ULONG_CAST(GetOffset.StdLayout.Offset);
SwizzledSurface.OffsetX = __OffsetXBytes;
SwizzledSurface.OffsetY = __OffsetY;
SwizzledSurface.OffsetZ = ZOffset;
uint32_t MipWidth = GFX_ULONG_CAST(pTextureCalc->GmmTexGetMipWidth(pTexInfo, pBlt->Gpu.MipLevel));
uint32_t MipHeight = pTextureCalc->GmmTexGetMipHeight(pTexInfo, pBlt->Gpu.MipLevel);
pTextureCalc->AlignTexHeightWidth(pTexInfo, &MipHeight, &MipWidth);
SwizzledSurface.Height = MipHeight;
SwizzledSurface.Pitch = MipWidth * ResPixelPitch;
}
else
{
SwizzledSurface.pBase = (char *)pBlt->Gpu.pData + GFX_ULONG_CAST(GetOffset.Render.Offset64);
SwizzledSurface.Pitch = GFX_ULONG_CAST(pTexInfo->Pitch);
SwizzledSurface.OffsetX = GetOffset.Render.XOffset + __OffsetXBytes;
SwizzledSurface.OffsetY = GetOffset.Render.YOffset + __OffsetY;
SwizzledSurface.OffsetZ = GetOffset.Render.ZOffset + ZOffset;
SwizzledSurface.Height = GFX_ULONG_CAST(pTexInfo->Size / pTexInfo->Pitch);
}
SwizzledSurface.Element.Pitch = ResPixelPitch;
LinearSurface.pBase = pBlt->Sys.pData;
LinearSurface.Pitch = pBlt->Sys.RowPitch;
LinearSurface.Height =
pBlt->Sys.BufferSize /
(pBlt->Sys.RowPitch ?
pBlt->Sys.RowPitch :
pBlt->Sys.BufferSize);
LinearSurface.Element.Pitch =
pBlt->Sys.PixelPitch ?
pBlt->Sys.PixelPitch :
ResPixelPitch;
LinearSurface.Element.Size =
SwizzledSurface.Element.Size =
pBlt->Blt.BytesPerPixel ?
pBlt->Blt.BytesPerPixel :
ResPixelPitch;
SwizzledSurface.pSwizzle = NULL;
if(pTexInfo->Flags.Info.TiledW)
{
SwizzledSurface.pSwizzle = &INTEL_TILE_W;
// Correct for GMM's 2x Pitch handling of stencil...
// (Unlike the HW, CpuSwizzleBlt handles TileW as a natural,
// 64x64=4KB tile, so the pre-Gen10 "double-pitch/half-height"
// kludging to TileY shape must be reversed.)
__GMM_ASSERT((SwizzledSurface.Pitch % 2) == 0);
SwizzledSurface.Pitch /= 2;
SwizzledSurface.Height *= 2;
}
else if(GMM_IS_4KB_TILE(pTexInfo->Flags) &&
!(pTexInfo->Flags.Info.TiledYf ||
GMM_IS_64KB_TILE(pTexInfo->Flags)))
{
if(pGmmGlobalContext->GetSkuTable().FtrTileY)
{
SwizzledSurface.pSwizzle = &INTEL_TILE_Y;
}
else
{
SwizzledSurface.pSwizzle = &INTEL_TILE_4;
}
}
else if(pTexInfo->Flags.Info.TiledX)
{
SwizzledSurface.pSwizzle = &INTEL_TILE_X;
}
else // Yf/s...
{
// clang-format off
#define NA
#define CASE(Layout, Tile, msaa, xD, bpe) \
case bpe: \
SwizzledSurface.pSwizzle = &Layout##_##Tile##_##msaa##xD##bpe; \
break
#define SWITCH_BPP(Layout, Tile, msaa, xD) \
switch(pTexInfo->BitsPerPixel) \
{ \
CASE(Layout, Tile, msaa, xD, 8); \
CASE(Layout, Tile, msaa, xD, 16); \
CASE(Layout, Tile, msaa, xD, 32); \
CASE(Layout, Tile, msaa, xD, 64); \
CASE(Layout, Tile, msaa, xD, 128); \
}
#define SWITCH_MSAA_TILE64(Layout, Tile, xD) \
{\
switch(pTexInfo->MSAA.NumSamples) \
{ \
case 0: \
SWITCH_BPP(Layout, Tile, , xD); \
break; \
case 1: \
SWITCH_BPP(Layout, Tile, , xD); \
break; \
case 2: \
SWITCH_BPP(Layout, Tile, MSAA2_, xD); \
break; \
case 4: \
case 8: \
case 16: \
SWITCH_BPP(Layout, Tile, MSAA_, xD); \
break; \
}\
}
#define SWITCH_MSAA(Layout, Tile, xD) \
{\
switch(pTexInfo->MSAA.NumSamples) \
{ \
case 0: \
SWITCH_BPP(Layout, Tile, , xD); \
break; \
case 1: \
SWITCH_BPP(Layout, Tile, , xD); \
break; \
case 2: \
SWITCH_BPP(Layout, Tile, MSAA2_, xD); \
break; \
case 4: \
SWITCH_BPP(Layout, Tile, MSAA4_, xD); \
break; \
case 8: \
SWITCH_BPP(Layout, Tile, MSAA8_, xD); \
break; \
case 16: \
SWITCH_BPP(Layout, Tile, MSAA16_, xD); \
break; \
}\
}
// clang-format on
if(pTexInfo->Type == RESOURCE_3D)
{
if(pTexInfo->Flags.Info.TiledYf)
{
SWITCH_BPP(INTEL, TILE_YF, , 3D_);
}
else if(GMM_IS_64KB_TILE(pTexInfo->Flags))
{
if(pGmmGlobalContext->GetSkuTable().FtrTileY)
{
SWITCH_BPP(INTEL, TILE_YS, , 3D_);
}
else
{
SWITCH_BPP(INTEL, TILE_64, , 3D_);
}
}
}
else // 2D/Cube...
{
if(pTexInfo->Flags.Info.TiledYf)
{
SWITCH_MSAA(INTEL, TILE_YF, );
}
else if(GMM_IS_64KB_TILE(pTexInfo->Flags))
{
if(pGmmGlobalContext->GetSkuTable().FtrTileY)
{
SWITCH_MSAA(INTEL, TILE_YS, );
}
else
{
SWITCH_MSAA_TILE64(INTEL, TILE_64, );
}
}
}
}
__GMM_ASSERT(SwizzledSurface.pSwizzle);
if(pBlt->Blt.Upload)
{
CpuSwizzleBlt(&SwizzledSurface, &LinearSurface, __CopyWidthBytes, __CopyHeight);
}
else
{
CpuSwizzleBlt(&LinearSurface, &SwizzledSurface, __CopyWidthBytes, __CopyHeight);
}
}
}
EXIT:
return Success;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Helper function that helps UMDs map in the surface in a layout that
/// our HW understands. Clients call this function in a loop until it
/// returns failure. Clients will get back information in pMapping->Span,
/// which they can use to map Span.Size bytes to Span.VirtualOffset gfx
/// address with Span.PhysicalOffset physical page.
///
/// @param[in] pMapping: Clients call the function with initially zero'd out GMM_GET_MAPPING.
/// @return 1 if more span descriptors to report, 0 if all mapping is done
/////////////////////////////////////////////////////////////////////////////////////
uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetMappingSpanDesc(GMM_GET_MAPPING *pMapping)
{
const GMM_PLATFORM_INFO *pPlatform;
uint8_t WasFinalSpan = 0;
GMM_TEXTURE_INFO * pTexInfo;
GMM_TEXTURE_CALC * pTextureCalc;
GMM_TEXTURE_INFO RedescribedPlaneInfo;
__GMM_ASSERT(Surf.Flags.Info.StdSwizzle);
pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf);
pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
__GMM_ASSERT(pTextureCalc != NULL);
pTexInfo = &Surf;
if(pMapping->Type == GMM_MAPPING_GEN9_YS_TO_STDSWIZZLE)
{
const uint32_t TileSize = GMM_KBYTE(64);
__GMM_ASSERT(Surf.Flags.Info.TiledYs);
__GMM_ASSERT(
(Surf.Type == RESOURCE_2D) ||
(Surf.Type == RESOURCE_3D) ||
(Surf.Type == RESOURCE_CUBE));
__GMM_ASSERT(Surf.Flags.Gpu.Depth == 0); // TODO(Minor): Proper StdSwizzle exemptions?
__GMM_ASSERT(Surf.Flags.Gpu.SeparateStencil == 0);
__GMM_ASSERT(AuxSurf.Size == 0); // TODO(Medium): Support not yet implemented, but DX12 UMD not using yet.
__GMM_ASSERT(Surf.Flags.Gpu.MMC == 0); // TODO(Medium): Support not yet implemented, but not yet needed for DX12.
// For planar surfaces we need to reorder the planes into what HW expects.
// OS will provide planes in [Y0][Y1][U0][U1][V0][V1] order while
// HW requires them to be in [Y0][U0][V0][Y1][U1][V1] order
if(Surf.Flags.Info.RedecribedPlanes)
{
if(pMapping->Scratch.Plane == GMM_NO_PLANE)
{
pMapping->Scratch.Plane = GMM_PLANE_Y;
if(GmmLib::Utility::GmmGetNumPlanes(Surf.Format) == GMM_PLANE_V)
{
pMapping->Scratch.LastPlane = GMM_PLANE_V;
}
else
{
pMapping->Scratch.LastPlane = GMM_PLANE_U;
}
}
else if(pMapping->Scratch.Row == pMapping->Scratch.Rows)
{
// If we've crossed into a new plane then need to reset
// the current mapping info and adjust the mapping
// params accordingly
GMM_REQ_OFFSET_INFO ReqInfo = {0};
uint32_t Plane = pMapping->Scratch.Plane + 1;
GMM_YUV_PLANE LastPlane = pMapping->Scratch.LastPlane;
memset(pMapping, 0, sizeof(*pMapping));
pMapping->Type = GMM_MAPPING_GEN9_YS_TO_STDSWIZZLE;
pMapping->Scratch.Plane = GMM_YUV_PLANE(Plane);
pMapping->Scratch.LastPlane = LastPlane;
ReqInfo.ReqRender = ReqInfo.ReqStdLayout = 1;
ReqInfo.Plane = GMM_YUV_PLANE(Plane);
this->GetOffset(ReqInfo);
pMapping->__NextSpan.PhysicalOffset = ReqInfo.StdLayout.Offset;
pMapping->__NextSpan.VirtualOffset = ReqInfo.Render.Offset64;
}
pTextureCalc->GetRedescribedPlaneParams(pTexInfo, GMM_PLANE_Y, &RedescribedPlaneInfo);
pTexInfo = &RedescribedPlaneInfo;
}
// Initialization of Mapping Params...
if(pMapping->Scratch.Element.Width == 0) // i.e. initially zero'ed struct.
{
uint32_t BytesPerElement = pTexInfo->BitsPerPixel / CHAR_BIT;
pMapping->Scratch.EffectiveLodMax = GFX_MIN(pTexInfo->MaxLod, pTexInfo->Alignment.MipTailStartLod);
pTextureCalc->GetCompressionBlockDimensions(
pTexInfo->Format,
&pMapping->Scratch.Element.Width,
&pMapping->Scratch.Element.Height,
&pMapping->Scratch.Element.Depth);
{ // Tile Dimensions...
GMM_TILE_MODE TileMode = pTexInfo->TileMode;
__GMM_ASSERT(TileMode < GMM_TILE_MODES);
// Get Tile Logical Tile Dimensions (i.e. uncompressed pixels)...
pMapping->Scratch.Tile.Width =
(pPlatform->TileInfo[TileMode].LogicalTileWidth / BytesPerElement) *
pMapping->Scratch.Element.Width;
pMapping->Scratch.Tile.Height =
pPlatform->TileInfo[TileMode].LogicalTileHeight *
pMapping->Scratch.Element.Height;
pMapping->Scratch.Tile.Depth =
pPlatform->TileInfo[TileMode].LogicalTileDepth *
pMapping->Scratch.Element.Depth;
pMapping->Scratch.RowPitchVirtual =
GFX_ULONG_CAST(pTexInfo->Pitch) *
pPlatform->TileInfo[TileMode].LogicalTileHeight *
pPlatform->TileInfo[TileMode].LogicalTileDepth;
}
{ // Slice...
uint32_t Lod;
uint32_t LodsPerSlice =
(pTexInfo->Type != RESOURCE_3D) ?
pMapping->Scratch.EffectiveLodMax + 1 :
1; // 3D Std Swizzle traverses slices before MIP's.
if(pMapping->Scratch.Plane)
{
// If planar then we need the parent descriptors planar pitch
pMapping->Scratch.SlicePitch.Virtual =
GFX_ULONG_CAST(Surf.OffsetInfo.Plane.ArrayQPitch) *
(pMapping->Scratch.Tile.Depth / pMapping->Scratch.Element.Depth);
}
else
{
pMapping->Scratch.SlicePitch.Virtual =
GFX_ULONG_CAST(pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender) *
(pMapping->Scratch.Tile.Depth / pMapping->Scratch.Element.Depth);
}
// SlicePitch.Physical...
__GMM_ASSERT(pMapping->Scratch.SlicePitch.Physical == 0);
for(Lod = 0; Lod < LodsPerSlice; Lod++)
{
uint32_t MipCols, MipRows;
GMM_GFX_SIZE_T MipWidth;
uint32_t MipHeight;
MipWidth = pTextureCalc->GmmTexGetMipWidth(pTexInfo, Lod);
MipHeight = pTextureCalc->GmmTexGetMipHeight(pTexInfo, Lod);
MipCols = GFX_ULONG_CAST(
GFX_CEIL_DIV(
MipWidth,
pMapping->Scratch.Tile.Width));
MipRows =
GFX_CEIL_DIV(
MipHeight,
pMapping->Scratch.Tile.Height);
pMapping->Scratch.SlicePitch.Physical +=
MipCols * MipRows * TileSize;
}
}
{ // Mip0...
if(pTexInfo->Type != RESOURCE_3D)
{
pMapping->Scratch.Slices =
GFX_MAX(pTexInfo->ArraySize, 1) *
((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1);
}
else
{
pMapping->Scratch.Slices =
GFX_CEIL_DIV(pTexInfo->Depth, pMapping->Scratch.Tile.Depth);
}
if(pTexInfo->Pitch ==
(GFX_ALIGN(pTexInfo->BaseWidth, pMapping->Scratch.Tile.Width) /
pMapping->Scratch.Element.Width * BytesPerElement))
{
// Treat Each LOD0 MIP as Single, Large Mapping Row...
pMapping->Scratch.Rows = 1;
pMapping->__NextSpan.Size =
GFX_CEIL_DIV(pTexInfo->BaseWidth, pMapping->Scratch.Tile.Width) *
GFX_CEIL_DIV(pTexInfo->BaseHeight, pMapping->Scratch.Tile.Height) *
TileSize;
}
else
{
pMapping->Scratch.Rows =
GFX_CEIL_DIV(pTexInfo->BaseHeight, pMapping->Scratch.Tile.Height);
pMapping->__NextSpan.Size =
GFX_CEIL_DIV(pTexInfo->BaseWidth, pMapping->Scratch.Tile.Width) *
TileSize;
}
}
}
// This iteration's span descriptor...
pMapping->Span = pMapping->__NextSpan;
// Prepare for Next Iteration...
// for(Lod = 0; Lod <= EffectiveLodMax; Lod += 1)
// for(Row = 0; Row < Rows; Row += 1)
// for(Slice = 0; Slice < Slices; Slice += 1)
if((pMapping->Scratch.Slice += 1) < pMapping->Scratch.Slices)
{
pMapping->__NextSpan.PhysicalOffset += pMapping->Scratch.SlicePitch.Physical;
pMapping->__NextSpan.VirtualOffset += pMapping->Scratch.SlicePitch.Virtual;
}
else
{
pMapping->Scratch.Slice = 0;
if((pMapping->Scratch.Row += 1) < pMapping->Scratch.Rows)
{
pMapping->__NextSpan.PhysicalOffset =
pMapping->Scratch.Slice0MipOffset.Physical += pMapping->Span.Size;
pMapping->__NextSpan.VirtualOffset =
pMapping->Scratch.Slice0MipOffset.Virtual += pMapping->Scratch.RowPitchVirtual;
}
else if((pMapping->Scratch.Lod += 1) <= pMapping->Scratch.EffectiveLodMax)
{
GMM_REQ_OFFSET_INFO GetOffset = {0};
GMM_GFX_SIZE_T MipWidth;
uint32_t MipHeight, MipCols;
MipWidth = pTextureCalc->GmmTexGetMipWidth(pTexInfo, pMapping->Scratch.Lod);
MipHeight = pTextureCalc->GmmTexGetMipHeight(pTexInfo, pMapping->Scratch.Lod);
MipCols = GFX_ULONG_CAST(
GFX_CEIL_DIV(
MipWidth,
pMapping->Scratch.Tile.Width));
pMapping->Scratch.Row = 0;
pMapping->Scratch.Rows =
GFX_CEIL_DIV(
MipHeight,
pMapping->Scratch.Tile.Height);
if(pTexInfo->Type != RESOURCE_3D)
{
pMapping->__NextSpan.PhysicalOffset =
pMapping->Scratch.Slice0MipOffset.Physical += pMapping->Span.Size;
}
else
{
uint32_t MipDepth;
MipDepth = pTextureCalc->GmmTexGetMipDepth(pTexInfo, pMapping->Scratch.Lod);
// 3D Std Swizzle traverses slices before MIP's...
pMapping->Scratch.Slice0MipOffset.Physical =
pMapping->__NextSpan.PhysicalOffset += pMapping->Span.Size;
pMapping->Scratch.Slices =
GFX_CEIL_DIV(
MipDepth,
pMapping->Scratch.Tile.Depth);
pMapping->Scratch.SlicePitch.Physical =
MipCols * pMapping->Scratch.Rows * TileSize;
}
GetOffset.ReqRender = 1;
GetOffset.MipLevel = pMapping->Scratch.Lod;
this->GetOffset(GetOffset);
pMapping->__NextSpan.VirtualOffset =
pMapping->Scratch.Slice0MipOffset.Virtual =
GFX_ALIGN_FLOOR(GetOffset.Render.Offset64, TileSize); // Truncate for packed MIP Tail.
pMapping->__NextSpan.Size = MipCols * TileSize;
}
else
{
// If the resource was a planar surface then need to iterate over the remaining planes
WasFinalSpan = pMapping->Scratch.Plane == pMapping->Scratch.LastPlane;
}
}
}
else
{
__GMM_ASSERT(0);
}
return !WasFinalSpan;
}
//=============================================================================
//
// Function: GetTiledResourceMipPacking
//
// Desc: Get number of packed mips and total #tiles for packed mips
//
// Parameters:
// See function arguments.
//
// Returns:
// void
//-----------------------------------------------------------------------------
void GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetTiledResourceMipPacking(uint32_t *pNumPackedMips,
uint32_t *pNumTilesForPackedMips)
{
if(GetMaxLod() == 0)
{
*pNumPackedMips = 0;
*pNumTilesForPackedMips = 0;
return;
}
if(GetResFlags().Info.TiledYf ||
GMM_IS_64KB_TILE(GetResFlags()))
{
if(Surf.Alignment.MipTailStartLod == GMM_TILED_RESOURCE_NO_MIP_TAIL)
{
*pNumPackedMips = 0;
*pNumTilesForPackedMips = 0;
}
else
{
*pNumPackedMips = GetMaxLod() -
Surf.Alignment.MipTailStartLod + 1;
*pNumTilesForPackedMips = 1;
}
}
else
{
// Error, unsupported format.
__GMM_ASSERT(false);
}
}
//=============================================================================
//
// Function: GetPackedMipTailStartLod
//
// Desc: Get Lod of first packed Mip.
//
// Parameters:
// See function arguments.
//
// Returns:
// Lod of first packed Mip
//-----------------------------------------------------------------------------
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetPackedMipTailStartLod()
{
uint32_t NumPackedMips = 0, NumTilesForPackedMips = 0;
const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf);
GetTiledResourceMipPacking(&NumPackedMips,
&NumTilesForPackedMips);
return (GetMaxLod() == 0) ?
pPlatform->MaxLod :
GetMaxLod() - NumPackedMips + 1; //GetMaxLod srarts at index 0, while NumPackedMips is just
//the number of mips. So + 1 to bring them to same units.
}
/////////////////////////////////////////////////////////////////////////////////////
/// Verifies if all mips are RCC-aligned
/// @return true/false
/////////////////////////////////////////////////////////////////////////////////////
bool GMM_STDCALL GmmLib::GmmResourceInfoCommon::IsMipRCCAligned(uint8_t &MisAlignedLod)
{
const uint8_t RCCCachelineWidth = 32;
const uint8_t RCCCachelineHeight = 4;
for(uint8_t lod = 0; lod <= GetMaxLod(); lod++)
{
if(!(GFX_IS_ALIGNED(GetMipWidth(lod), RCCCachelineWidth) &&
GFX_IS_ALIGNED(GetMipHeight(lod), RCCCachelineHeight)))
{
MisAlignedLod = lod;
return false;
}
}
return true;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns the resource's compressions block width
/// @return Compression block width
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetCompressionBlockWidth()
{
GMM_RESOURCE_FORMAT Format;
Format = Surf.Format;
__GMM_ASSERT((Format > GMM_FORMAT_INVALID) &&
(Format < GMM_RESOURCE_FORMATS));
return pGmmGlobalContext->GetPlatformInfo().FormatTable[Format].Element.Width;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns the resource's compressions block height
/// @return Compression block width
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetCompressionBlockHeight()
{
GMM_RESOURCE_FORMAT Format;
Format = Surf.Format;
__GMM_ASSERT((Format > GMM_FORMAT_INVALID) &&
(Format < GMM_RESOURCE_FORMATS));
return pGmmGlobalContext->GetPlatformInfo().FormatTable[Format].Element.Height;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns the resource's compressions block depth
/// @return Compression block width
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetCompressionBlockDepth()
{
GMM_RESOURCE_FORMAT Format;
Format = Surf.Format;
__GMM_ASSERT((Format > GMM_FORMAT_INVALID) &&
(Format < GMM_RESOURCE_FORMATS));
return pGmmGlobalContext->GetPlatformInfo().FormatTable[Format].Element.Depth;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns whether resource uses LOD0-only or Full array spacing
/// @return 1/0
/////////////////////////////////////////////////////////////////////////////////////
uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::IsArraySpacingSingleLod()
{
__GMM_ASSERT(GFX_GET_CURRENT_RENDERCORE(pGmmGlobalContext->GetPlatformInfo().Platform) < IGFX_GEN8_CORE);
return Surf.Alignment.ArraySpacingSingleLod;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns whether resource is ASTC
/// @return 1/0
/////////////////////////////////////////////////////////////////////////////////////
uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::IsASTC()
{
GMM_RESOURCE_FORMAT Format;
Format = Surf.Format;
return (Format > GMM_FORMAT_INVALID) &&
(Format < GMM_RESOURCE_FORMATS) &&
pGmmGlobalContext->GetPlatformInfo().FormatTable[Format].ASTC;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns MOCS associated with the resource
/// @param[in] MOCS
/////////////////////////////////////////////////////////////////////////////////////
MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetMOCS()
{
const GMM_CACHE_POLICY_ELEMENT *CachePolicy = pGmmGlobalContext->GetCachePolicyUsage();
__GMM_ASSERT(CachePolicy[GetCachePolicyUsage()].Initialized);
// Prevent wrong Usage for XAdapter resources. UMD does not call GetMemoryObject on shader resources but,
// when they add it someone could call it without knowing the restriction.
if(Surf.Flags.Info.XAdapter &&
GetCachePolicyUsage() != GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE)
{
__GMM_ASSERT(false);
}
if((CachePolicy[GetCachePolicyUsage()].Override & CachePolicy[GetCachePolicyUsage()].IDCode) ||
(CachePolicy[GetCachePolicyUsage()].Override == ALWAYS_OVERRIDE))
{
return CachePolicy[GetCachePolicyUsage()].MemoryObjectOverride;
}
return CachePolicy[GetCachePolicyUsage()].MemoryObjectNoOverride;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns the surface state value for Standard Tiling Mode Extension
/// @return Standard Tiling Mode Extension
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetStdTilingModeExtSurfaceState()
{
const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf);
GMM_UNREFERENCED_LOCAL_VARIABLE(pPlatform); // Only used for debug
__GMM_ASSERT(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) > IGFX_GEN10_CORE);
if(pGmmGlobalContext->GetSkuTable().FtrStandardMipTailFormat)
{
return 1;
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Returns the surface state value for Resource Format
/// @return Resource Format
/////////////////////////////////////////////////////////////////////////////////////
GMM_SURFACESTATE_FORMAT GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetResourceFormatSurfaceState()
{
GMM_RESOURCE_FORMAT Format;
Format = Surf.Format;
__GMM_ASSERT((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS));
return pGmmGlobalContext->GetPlatformInfo().FormatTable[Format].SurfaceStateFormat;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Return the logical width of mip level
/// @param[in] MipLevel: Mip level for which the info is needed
/// @return Mip width
/////////////////////////////////////////////////////////////////////////////////////
GMM_GFX_SIZE_T GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetMipWidth(uint32_t MipLevel)
{
GMM_TEXTURE_CALC *pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
return pTextureCalc->GmmTexGetMipWidth(&Surf, MipLevel);
}
/////////////////////////////////////////////////////////////////////////////////////
/// Return the logical height of mip level
/// @param[in] MipLevel: Mip level for which the info is needed
/// @return Mip width
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetMipHeight(uint32_t MipLevel)
{
GMM_TEXTURE_CALC *pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
return pTextureCalc->GmmTexGetMipHeight(&Surf, MipLevel);
}
/////////////////////////////////////////////////////////////////////////////////////
/// Return the logical depth of mip level
/// @param[in] MipLevel Mip level for which the info is needed
/// @return Mip width
/////////////////////////////////////////////////////////////////////////////////////
uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetMipDepth(uint32_t MipLevel)
{
GMM_TEXTURE_CALC *pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf);
return pTextureCalc->GmmTexGetMipDepth(&Surf, MipLevel);
}