| /*============================================================================== |
| 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" |
| |
| int32_t GmmLib::GmmTextureCalc::RefCount = 0; |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| /// This functions sets the Tile Mode of the graphics surface |
| /// |
| /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO |
| /// |
| ///////////////////////////////////////////////////////////////////////////////////// |
| void GmmLib::GmmTextureCalc::SetTileMode(GMM_TEXTURE_INFO *pTexInfo) |
| { |
| const GMM_PLATFORM_INFO *pPlatform; |
| |
| pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo); |
| |
| if(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) |
| { |
| // clang-format off |
| #define SET_TILE_MODE(Tile, Submode) \ |
| { \ |
| pTexInfo->TileMode = \ |
| (pTexInfo->BitsPerPixel == 128) ? TILE_##Tile##_##Submode##_128bpe : \ |
| (pTexInfo->BitsPerPixel == 64) ? TILE_##Tile##_##Submode##_64bpe : \ |
| (pTexInfo->BitsPerPixel == 32) ? TILE_##Tile##_##Submode##_32bpe : \ |
| (pTexInfo->BitsPerPixel == 16) ? TILE_##Tile##_##Submode##_16bpe : \ |
| TILE_##Tile##_##Submode##_8bpe; \ |
| } \ |
| |
| #define GENERATE_TILE_MODE(T, M1d, M2d, M2d_2x, M2d_4x, M2d_8x, M2d_16x, M3d) \ |
| {\ |
| switch (pTexInfo->Type)\ |
| {\ |
| case RESOURCE_1D:\ |
| SET_TILE_MODE(T, M1d);\ |
| break;\ |
| case RESOURCE_2D:\ |
| case RESOURCE_CUBE:\ |
| switch (pTexInfo->MSAA.NumSamples)\ |
| {\ |
| case 1:\ |
| SET_TILE_MODE(T, M2d);\ |
| break;\ |
| case 2:\ |
| SET_TILE_MODE(T, M2d_2x);\ |
| break;\ |
| case 4:\ |
| SET_TILE_MODE(T, M2d_4x);\ |
| break;\ |
| case 8:\ |
| SET_TILE_MODE(T, M2d_8x);\ |
| break;\ |
| case 16:\ |
| SET_TILE_MODE(T, M2d_16x);\ |
| break;\ |
| default:\ |
| __GMM_ASSERT(0);\ |
| }\ |
| break;\ |
| case RESOURCE_3D:\ |
| SET_TILE_MODE(T, M3d);\ |
| break;\ |
| default:\ |
| __GMM_ASSERT(0);\ |
| }\ |
| } |
| |
| |
| // clang-format on |
| if(pTexInfo->Flags.Info.TiledYf) |
| { |
| GENERATE_TILE_MODE(YF, 1D, 2D, 2D_2X, 2D_4X, 2D_8X, 2D_16X, 3D); |
| |
| pTexInfo->Flags.Info.TiledYf = 1; |
| pTexInfo->Flags.Info.TiledYs = 0; |
| } |
| else |
| { |
| if(pGmmGlobalContext->GetSkuTable().FtrTileY) |
| { |
| GENERATE_TILE_MODE(YS, 1D, 2D, 2D_2X, 2D_4X, 2D_8X, 2D_16X, 3D); |
| } |
| |
| pTexInfo->Flags.Info.TiledYf = 0; |
| GMM_SET_64KB_TILE(pTexInfo->Flags, 1); |
| } |
| |
| |
| GMM_SET_4KB_TILE(pTexInfo->Flags, pGmmGlobalContext->GetSkuTable().FtrTileY ? 1 : 0); |
| |
| pTexInfo->Flags.Info.TiledX = 0; |
| pTexInfo->Flags.Info.TiledW = 0; |
| pTexInfo->Flags.Info.Linear = 0; |
| #undef SET_TILE_MODE |
| } |
| else if(GMM_IS_4KB_TILE(pTexInfo->Flags)) |
| { |
| GMM_SET_4KB_TILE(pTexInfo->Flags, 1); |
| pTexInfo->Flags.Info.TiledYf = 0; |
| pTexInfo->Flags.Info.TiledYs = 0; |
| pTexInfo->Flags.Info.TiledX = 0; |
| pTexInfo->Flags.Info.TiledW = 0; |
| pTexInfo->Flags.Info.Linear = 0; |
| GMM_SET_4KB_TILE_MODE(pTexInfo->TileMode); |
| } |
| else if(pTexInfo->Flags.Info.TiledX) |
| { |
| pTexInfo->Flags.Info.TiledY = 0; |
| pTexInfo->Flags.Info.TiledYf = 0; |
| pTexInfo->Flags.Info.TiledYs = 0; |
| pTexInfo->Flags.Info.TiledX = 1; |
| pTexInfo->Flags.Info.TiledW = 0; |
| pTexInfo->Flags.Info.Linear = 0; |
| pTexInfo->TileMode = LEGACY_TILE_X; |
| } |
| else if(pTexInfo->Flags.Info.TiledW) |
| { |
| pTexInfo->Flags.Info.TiledY = 0; |
| pTexInfo->Flags.Info.TiledYf = 0; |
| pTexInfo->Flags.Info.TiledYs = 0; |
| pTexInfo->Flags.Info.TiledX = 0; |
| pTexInfo->Flags.Info.TiledW = 1; |
| pTexInfo->Flags.Info.Linear = 0; |
| pTexInfo->TileMode = LEGACY_TILE_Y; |
| } |
| else if(pTexInfo->Flags.Info.Linear) |
| { |
| pTexInfo->Flags.Info.TiledY = 0; |
| pTexInfo->Flags.Info.TiledYf = 0; |
| pTexInfo->Flags.Info.TiledYs = 0; |
| pTexInfo->Flags.Info.TiledX = 0; |
| pTexInfo->Flags.Info.TiledW = 0; |
| pTexInfo->Flags.Info.Linear = 1; |
| pTexInfo->TileMode = TILE_NONE; |
| } |
| else |
| { |
| GMM_ASSERTDPF(0, "No tiling preference set!"); |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| /// C Wrapper function for allocating a mip map or planar surface. The function |
| /// outputs offset, size and pitch information by enforcing all the h/w alignment |
| /// and restrictions. |
| /// |
| /// @param[in] pTexInfo: Reference to GMM_TEXTURE_INFO |
| /// |
| /// @return ::GMM_STATUS |
| ///////////////////////////////////////////////////////////////////////////////////// |
| #if(defined(__GMM_KMD__)) |
| GMM_STATUS GmmTexAlloc(GMM_TEXTURE_INFO *pTexInfo) |
| { |
| GMM_TEXTURE_CALC *pTextureCalc = pGmmGlobalContext->GetTextureCalc(); |
| return (pTextureCalc->AllocateTexture(pTexInfo)); |
| } |
| |
| GMM_STATUS GmmTexLinearCCS(GMM_TEXTURE_INFO *pTexInfo, GMM_TEXTURE_INFO *pAuxTexInfo) |
| { |
| GMM_TEXTURE_CALC *pTextureCalc = pGmmGlobalContext->GetTextureCalc(); |
| return (pTextureCalc->FillTexCCS(pTexInfo, pAuxTexInfo)); |
| } |
| #endif |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| /// Top level function for allocating a mip map or planar surface. The function |
| /// outputs offset, size and pitch information by enforcing all the h/w alignment |
| /// and restrictions. |
| /// |
| /// @param[in] pTexInfo: Reference to GMM_TEXTURE_INFO |
| /// |
| /// @return ::GMM_STATUS |
| ///////////////////////////////////////////////////////////////////////////////////// |
| GMM_STATUS GmmLib::GmmTextureCalc::AllocateTexture(GMM_TEXTURE_INFO *pTexInfo) |
| { |
| __GMM_BUFFER_TYPE Restrictions = {0}; |
| GMM_STATUS Status; |
| |
| __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); |
| __GMM_ASSERTPTR(pGmmGlobalContext, GMM_ERROR); |
| |
| GMM_DPF_ENTER; |
| |
| GetTexRestrictions(pTexInfo, &Restrictions); |
| |
| if((Status = __GmmTexFillHAlignVAlign(pTexInfo)) != GMM_SUCCESS) |
| { |
| return Status; |
| } |
| |
| // Planar YUV resources treated special. Packed YUV treated like 2D/3D/Cube... |
| if(GmmIsPlanar(pTexInfo->Format)) |
| { |
| Status = FillTexPlanar(pTexInfo, &Restrictions); |
| |
| if((Status == GMM_SUCCESS) && |
| (ValidateTexInfo(pTexInfo, &Restrictions) == false)) |
| { |
| return GMM_ERROR; |
| } |
| if(GMM_SUCCESS != FillTexCCS(pTexInfo, pTexInfo)) |
| { |
| return GMM_ERROR; |
| } |
| return Status; |
| } |
| else |
| { |
| SetTileMode(pTexInfo); |
| } |
| |
| switch(pTexInfo->Type) |
| { |
| 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 |
| { |
| Status = FillTex2D(pTexInfo, &Restrictions); |
| |
| break; |
| } |
| case RESOURCE_1D: |
| { |
| Status = FillTex1D(pTexInfo, &Restrictions); |
| |
| break; |
| } |
| case RESOURCE_3D: |
| { |
| Status = FillTex3D(pTexInfo, &Restrictions); |
| |
| break; |
| } |
| case RESOURCE_CUBE: |
| { |
| Status = FillTexCube(pTexInfo, &Restrictions); |
| |
| break; |
| } |
| case RESOURCE_SCRATCH: |
| case RESOURCE_BUFFER: |
| case RESOURCE_FBC: |
| case RESOURCE_PWR_CONTEXT: |
| case RESOURCE_KMD_BUFFER: |
| case RESOURCE_NULL_CONTEXT_INDIRECT_STATE: |
| case RESOURCE_PERF_DATA_QUEUE: |
| case RESOURCE_HW_CONTEXT: |
| case RESOURCE_TAG_PAGE: |
| case RESOURCE_OVERLAY_DMA: |
| case RESOURCE_GTT_TRANSFER_REGION: |
| case RESOURCE_GLOBAL_BUFFER: |
| case RESOURCE_CURSOR: |
| case RESOURCE_GFX_CLIENT_BUFFER: |
| #if _WIN32 |
| case RESOURCE_WGBOX_ENCODE_STATE: |
| case RESOURCE_WGBOX_ENCODE_TFD: |
| #endif |
| { |
| Status = FillTexBlockMem(pTexInfo, &Restrictions); |
| break; |
| } |
| default: |
| { |
| GMM_ASSERTDPF(0, "GmmTexAlloc: Unknown surface type!"); |
| return GMM_INVALIDPARAM; |
| } |
| }; |
| |
| if(ValidateTexInfo(pTexInfo, &Restrictions) == false) |
| { |
| return GMM_ERROR; |
| } |
| |
| if(GMM_SUCCESS != FillTexCCS(pTexInfo, pTexInfo)) |
| { |
| return GMM_ERROR; |
| } |
| |
| return Status; |
| } |
| |
| GMM_STATUS GmmLib::GmmTextureCalc::FillTexCCS(GMM_TEXTURE_INFO *pBaseSurf, GMM_TEXTURE_INFO *pTexInfo) |
| { |
| GMM_UNREFERENCED_PARAMETER(pBaseSurf); |
| GMM_UNREFERENCED_PARAMETER(pTexInfo); |
| return GMM_SUCCESS; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| /// This function will validate pTexInfo to make sure all the surface creation |
| /// parameters are valid. |
| /// |
| /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO |
| /// @param[in] pRestrictions: Reference to surface alignment and size restrictions |
| /// |
| /// @return true/false |
| ///////////////////////////////////////////////////////////////////////////////////// |
| bool GmmLib::GmmTextureCalc::ValidateTexInfo(GMM_TEXTURE_INFO * pTexInfo, |
| __GMM_BUFFER_TYPE *pRestrictions) |
| { |
| __GMM_ASSERTPTR(pTexInfo, false); |
| __GMM_ASSERTPTR(pRestrictions, false); |
| |
| GMM_DPF_ENTER; |
| |
| if(pTexInfo->Pitch > pRestrictions->MaxPitch) |
| { |
| GMM_ASSERTDPF(0, |
| "GmmLib::GmmTextureCalc::ValidateTexInfo: Pitch" |
| "exceeds max HW pitch restriction.\r\n"); |
| return false; |
| } |
| |
| GMM_DPF_EXIT; |
| return true; |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| /// Sets the tiling type based on the required alignment parameters. |
| /// |
| /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO |
| /// @param[in] WidthBytesPhysical: Width in bytes of the surface |
| /// @param[in] Height: Height of the surface |
| /// @param[in] pBufferType: Reference to surface alignment and size restrictions |
| /// |
| /// @return ::GMM_STATUS |
| ///////////////////////////////////////////////////////////////////////////////////// |
| GMM_STATUS GmmLib::GmmTextureCalc::FillTexPitchAndSize(GMM_TEXTURE_INFO * pTexInfo, |
| GMM_GFX_SIZE_T WidthBytesPhysical, |
| uint32_t Height, |
| __GMM_BUFFER_TYPE *pBufferType) |
| { |
| GMM_STATUS Status = GMM_SUCCESS; |
| GMM_GFX_SIZE_T WidthBytesRender = 0; |
| GMM_GFX_SIZE_T WidthBytesLock = 0; |
| |
| __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); |
| __GMM_ASSERTPTR(pBufferType, GMM_ERROR); |
| |
| GMM_DPF_ENTER; |
| |
| const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo); |
| |
| // Make sure that we meet the minimum HW requirment for that buffer type |
| WidthBytesPhysical = GFX_MAX(WidthBytesPhysical, pBufferType->MinPitch); |
| |
| if(pTexInfo->TileMode >= GMM_TILE_MODES) |
| { |
| GMM_ASSERTDPF(0, "Invalid parameter!"); |
| return GMM_ERROR; |
| } |
| |
| if(GMM_ISNOT_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) |
| { |
| pTexInfo->LegacyFlags |= GMM_LINEAR; |
| |
| // For linear surace we need to make sure that physical pitch |
| // meet the HW alignment (i.e DWORD or QWORD, ETC) |
| WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, |
| pBufferType->PitchAlignment); |
| |
| WidthBytesRender = WidthBytesPhysical; |
| WidthBytesLock = WidthBytesPhysical; |
| } |
| else |
| { |
| if(pTexInfo->Flags.Info.TiledY || |
| pTexInfo->Flags.Info.TiledYf || |
| pTexInfo->Flags.Info.TiledYs) |
| { |
| pTexInfo->LegacyFlags |= GMM_TILE_Y; |
| } |
| else if(pTexInfo->Flags.Info.TiledX == 1) |
| { |
| pTexInfo->LegacyFlags |= GMM_TILE_X; |
| } |
| else if(pTexInfo->Flags.Info.TiledW == 1) |
| { |
| pTexInfo->LegacyFlags |= GMM_TILE_W; |
| } |
| |
| // Align Height to tile height boundary |
| Height = GFX_ALIGN(Height, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); |
| |
| // Align Width to next tile boundary |
| WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, |
| pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth); |
| |
| if(pTexInfo->Flags.Info.RenderCompressed || pTexInfo->Flags.Info.MediaCompressed) |
| { |
| if(!GMM_IS_64KB_TILE(pTexInfo->Flags)) //Ys is naturally aligned to required 4 YF pages |
| { |
| // Align Pitch to 4-tile boundary |
| WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, |
| 4 * pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth); |
| } |
| } |
| |
| // Calculate Alignment Restriction for rendering on the surface |
| // NOTE: |
| // WidthBytesPhysical == true physical pitch used to determine amount |
| // of Pages need for a surface |
| // WidthBytesRender == HW require pitch of a surface for rendering |
| // (i.e. power2 |
| // WidthBytesLock == Pitch when a surface is visible via Fence region. |
| |
| WidthBytesRender = WidthBytesLock = WidthBytesPhysical; |
| |
| // Align pitch to meet our HW requirment for each buffer |
| WidthBytesRender = GFX_ALIGN(WidthBytesRender, |
| pBufferType->RenderPitchAlignment); |
| |
| // Media Memory Compression : Allocate one memory tile wider than is required... |
| pGmmGlobalContext->GetTextureCalc()->AllocateOneTileThanRequied(pTexInfo, WidthBytesRender, |
| WidthBytesPhysical, WidthBytesLock); |
| |
| // check if locking a particular suface need to be power 2 or not |
| if(pBufferType->NeedPow2LockAlignment) |
| { |
| WidthBytesLock = GFX_POW2_SIZE(WidthBytesPhysical); |
| } |
| |
| // Align pitch to meet our HW requirment for each buffer |
| // [1] 8K lock pitch is needed on Gen3 when we internally remap the |
| // display surface in GmmGetDisplayStartAddress ( ). Gen4, |
| // we don't remap due to Persurface tiling and stick to 64byte |
| // lock pitch alignment. |
| WidthBytesLock = GFX_ALIGN(WidthBytesLock, |
| pBufferType->LockPitchAlignment); |
| |
| if((pTexInfo->Type == RESOURCE_PRIMARY) || pTexInfo->Flags.Gpu.FlipChain) |
| { |
| // [2] At creation time, we tell OS the Render size, not |
| // SurfaceSizePhysical like other surfaces. Therefore, we change |
| // the SurfaceSizePhysical to match render size for simplicity. |
| WidthBytesPhysical = WidthBytesRender; |
| } |
| |
| if(pGmmGlobalContext->GetWaTable().WaMsaa8xTileYDepthPitchAlignment && |
| (pTexInfo->MSAA.NumSamples == 8) && |
| pTexInfo->Flags.Info.TiledY && |
| pTexInfo->Flags.Gpu.Depth) |
| { |
| WidthBytesLock = |
| WidthBytesRender = |
| WidthBytesPhysical = GFX_ALIGN(WidthBytesLock, GMM_BYTES(256)); |
| } |
| } |
| |
| __GMM_ASSERT(WidthBytesLock == WidthBytesPhysical && |
| WidthBytesRender == WidthBytesPhysical && |
| WidthBytesLock == WidthBytesRender); |
| pTexInfo->Pitch = WidthBytesLock; |
| |
| //VirtualPadding override |
| if(pTexInfo->Flags.Info.AllowVirtualPadding && |
| pTexInfo->OverridePitch) |
| { |
| pTexInfo->Pitch = pTexInfo->OverridePitch; |
| } |
| |
| // When lossless compression is enabled with plane width greater than 3840 and |
| // horizontal panning, the surface pitch should be a multiple of 4 tiles. Since |
| // GMM doesn't know about lossless compression status at allocation time, here |
| // we apply the WA to all unified aux surfaces. |
| if(pGmmGlobalContext->GetWaTable().WaLosslessCompressionSurfaceStride && |
| pTexInfo->Flags.Gpu.UnifiedAuxSurface && |
| (pTexInfo->BaseWidth > 3840)) |
| { |
| pTexInfo->Pitch = GFX_ALIGN(pTexInfo->Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * 4); |
| } |
| |
| // If FBC is enabled with a linear surface, the surface pitch should be a multiple of |
| // 8 cache lines (512 bytes). Since GMM doesn't know about FBC status, here we apply |
| // the WA to all linear surfaces. |
| // Xadapter surfaces has to be 128 Bytes aligned and hence we don't want this 512B alignment |
| // for Xadapter. Eventually FBC will be disabled in case of Xadapter Linear surfaces |
| if(pGmmGlobalContext->GetSkuTable().FtrFbc && |
| pGmmGlobalContext->GetWaTable().WaFbcLinearSurfaceStride && |
| pTexInfo->Flags.Gpu.FlipChain && |
| pTexInfo->Flags.Info.Linear && |
| !pTexInfo->Flags.Info.XAdapter) |
| { |
| if(pTexInfo->Flags.Gpu.FlipChainPreferred) |
| { |
| // Moderate down displayable flags if input parameters (.FlipChainPrefered) |
| // deprioritise it, over Pitch alignement in this case. |
| pTexInfo->Flags.Gpu.FlipChain = __GMM_IS_ALIGN(pTexInfo->Pitch, 512); |
| } |
| else |
| { |
| pTexInfo->Pitch = GFX_ALIGN(pTexInfo->Pitch, 512); |
| } |
| } |
| |
| // For CCS Aux Display Surf the surface stride should not exceed 8 times the LogicalTileWidth. |
| if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs && pTexInfo->Flags.Gpu.FlipChain && |
| (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE)) |
| { |
| __GMM_ASSERT(pTexInfo->Pitch <= (pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * 8)); |
| pTexInfo->Pitch = GFX_MIN(pTexInfo->Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * 8); |
| } |
| |
| if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs && |
| (pTexInfo->Pitch > pPlatform->TexAlign.CCS.MaxPitchinTiles * pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth)) |
| { |
| GMM_ASSERTDPF(0, "Aux Surface pitch too large!"); |
| Status = GMM_ERROR; |
| } |
| |
| // For NV12 Linear FlipChain surfaces, UV plane distance should be 4k Aligned. |
| // Hence make the stride to align to 4k, so that UV distance will be 4k aligned. |
| if(pGmmGlobalContext->GetWaTable().Wa4kAlignUVOffsetNV12LinearSurface && |
| (pTexInfo->Format == GMM_FORMAT_NV12 || GmmIsP0xx(pTexInfo->Format)) && pTexInfo->Flags.Info.Linear && |
| (!pTexInfo->Flags.Info.XAdapter) && |
| ((pTexInfo->Type == RESOURCE_PRIMARY) || pTexInfo->Flags.Gpu.FlipChain)) |
| { |
| if(pTexInfo->Flags.Gpu.FlipChainPreferred) |
| { |
| // Moderate down displayable flags if input parameters (.FlipChainPrefered) |
| // deprioritise it, over Pitch alignement in this case. |
| pTexInfo->Flags.Gpu.FlipChain = __GMM_IS_ALIGN(pTexInfo->Pitch, GMM_KBYTE(4)); |
| } |
| else |
| { |
| pTexInfo->Pitch = GFX_ALIGN(pTexInfo->Pitch, GMM_KBYTE(4)); |
| } |
| } |
| |
| { // Surface Sizes |
| int64_t Size; |
| |
| if(pTexInfo->Flags.Gpu.S3d) |
| { |
| if(pGmmGlobalContext->GetSkuTable().FtrDisplayEngineS3d) // BDW+ Display Engine S3D (Tiled) |
| { |
| __GMM_ASSERT(!pTexInfo->Flags.Info.Linear); |
| |
| pTexInfo->S3d.BlankAreaOffset = 0; |
| |
| if(pTexInfo->Flags.Gpu.S3dDx && (pTexInfo->ArraySize == 2)) |
| { |
| pTexInfo->S3d.RFrameOffset = GFX_ULONG_CAST(pTexInfo->Pitch * pTexInfo->Alignment.QPitch); |
| pTexInfo->S3d.TallBufferHeight = Height; |
| } |
| else |
| { |
| if(pTexInfo->Flags.Gpu.Overlay) |
| { |
| pTexInfo->S3d.RFrameOffset = GFX_ULONG_CAST(pTexInfo->Pitch * Height); |
| |
| Height = pTexInfo->S3d.TallBufferHeight = Height * 2; |
| } |
| else if(pTexInfo->Flags.Gpu.FlipChain) |
| { |
| pTexInfo->S3d.RFrameOffset = 0; |
| pTexInfo->S3d.TallBufferHeight = Height; |
| } |
| else |
| { |
| // Something must be wrong. Not an S3D resource! |
| __GMM_ASSERT(0); |
| } |
| } |
| |
| __GMM_ASSERT(__GMM_IS_ALIGN(pTexInfo->S3d.RFrameOffset, PAGE_SIZE)); |
| } |
| else if(pTexInfo->Flags.Gpu.S3dDx) // DX S3D (Tiled) |
| { |
| __GMM_ASSERT(!pTexInfo->Flags.Info.Linear || !pTexInfo->Flags.Gpu.Overlay); |
| __GMM_ASSERT(pTexInfo->ArraySize <= 1); // S3D framebuffer arrays are not supported (pre-BDW). |
| |
| pTexInfo->S3d.BlankAreaOffset = GFX_ULONG_CAST(pTexInfo->Pitch * pTexInfo->BaseHeight); |
| |
| pTexInfo->S3d.RFrameOffset = |
| GFX_ULONG_CAST(pTexInfo->Pitch * |
| (pTexInfo->S3d.DisplayModeHeight + pTexInfo->S3d.NumBlankActiveLines)); |
| |
| Height = |
| pTexInfo->S3d.TallBufferHeight = |
| GFX_ALIGN( |
| (pTexInfo->BaseHeight * 2) + pTexInfo->S3d.NumBlankActiveLines, |
| pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); |
| } |
| else // Legacy S3D |
| { |
| __GMM_ASSERT(pTexInfo->Flags.Info.Linear); |
| |
| pTexInfo->S3d.BlankAreaOffset = GFX_ULONG_CAST(pTexInfo->Pitch * pTexInfo->BaseHeight); |
| |
| pTexInfo->S3d.RFrameOffset = |
| GFX_ULONG_CAST(pTexInfo->Pitch * |
| (pTexInfo->S3d.DisplayModeHeight + pTexInfo->S3d.NumBlankActiveLines)); |
| |
| if(pTexInfo->Flags.Gpu.Overlay) |
| { |
| Height = |
| pTexInfo->S3d.TallBufferHeight = |
| pTexInfo->BaseHeight + |
| pTexInfo->S3d.NumBlankActiveLines + |
| pTexInfo->S3d.DisplayModeHeight; |
| } |
| else if(pTexInfo->Flags.Gpu.FlipChain) |
| { |
| __GMM_ASSERT(pTexInfo->S3d.DisplayModeHeight == pTexInfo->BaseHeight); |
| |
| pTexInfo->S3d.TallBufferHeight = |
| (pTexInfo->BaseHeight * 2) + |
| pTexInfo->S3d.NumBlankActiveLines; |
| } |
| else |
| { |
| // Something must be wrong. Not an S3D resource! |
| __GMM_ASSERT(0); |
| } |
| |
| __GMM_ASSERT(__GMM_IS_ALIGN(pTexInfo->S3d.RFrameOffset, PAGE_SIZE)); |
| __GMM_ASSERT(__GMM_IS_ALIGN(pTexInfo->S3d.BlankAreaOffset, PAGE_SIZE)); |
| } |
| |
| // Calculate surface size (physical). |
| Size = pTexInfo->Pitch * Height; |
| |
| // Calculate tall buffer size (virtual). |
| pTexInfo->S3d.TallBufferSize = GFX_ULONG_CAST(pTexInfo->Pitch * pTexInfo->S3d.TallBufferHeight); |
| } |
| else |
| { |
| Size = (int64_t)pTexInfo->Pitch * Height; |
| |
| if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) |
| { |
| Size *= pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth; |
| } |
| |
| if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && |
| (pTexInfo->MSAA.NumSamples > 1) && |
| (pTexInfo->Flags.Gpu.Depth == 0 && pTexInfo->Flags.Gpu.SeparateStencil == 0)) |
| { |
| // For color buffer (meaning not depth or stencil buffer) |
| // The width/height for TileYf/Ys MSAA surfaces are not expanded (using GmmExpandWidth/Height functions) |
| // because pitch for these surfaces is in their non-expanded dimensions. So, the pitch |
| // is also non-expanded units. That's why, we multiply by the sample size here to get the correct size. |
| if(pGmmGlobalContext->GetSkuTable().FtrTileY) |
| { |
| Size *= pTexInfo->MSAA.NumSamples; |
| } |
| } |
| |
| if((pTexInfo->Flags.Info.TiledY && pTexInfo->Flags.Gpu.TiledResource)) |
| { |
| //Pad align surface to 64KB ie Tile size |
| Size = GFX_ALIGN(Size, GMM_KBYTE(64)); |
| } |
| |
| // Buffer Sampler Padding... |
| if((pTexInfo->Type == RESOURCE_BUFFER) && |
| pGmmGlobalContext->GetWaTable().WaNoMinimizedTrivialSurfacePadding && |
| !pTexInfo->Flags.Wa.NoBufferSamplerPadding && |
| !pTexInfo->Flags.Info.ExistingSysMem && // <-- Currently using separate padding WA in OCL (and rarity/luck in other UMD's). |
| // <-- Never sampled from. |
| !pTexInfo->Flags.Gpu.Query && |
| !pTexInfo->Flags.Gpu.HistoryBuffer && |
| !pTexInfo->Flags.Gpu.State && |
| !pTexInfo->Flags.Gpu.StateDx9ConstantBuffer) |
| // These can be sampled from, so they need the padding... |
| // pTexInfo->Flags.Gpu.Constant |
| // pTexInfo->Flags.Gpu.Index |
| // pTexInfo->Flags.Gpu.Stream |
| // pTexInfo->Flags.Gpu.Vertex |
| |
| { |
| uint32_t BufferSizeAlignment; |
| uint32_t BufferSizePadding; |
| |
| // SURFTYPE_BUFFER's that can be sampled from must have their size |
| // padded to a multiple of 256 buffer elements and then have an |
| // additional 16 bytes of padding beyond that. Currently, the GMM |
| // doesn't receive a buffer's element type/size, so (until that's |
| // revamped) we'll assume the worst-case of 128-bit elements--which |
| // means padding to 256 * 128 / 8 = 4KB and then adding 16 bytes. |
| // In the case of BDW:A0, size is padded to a multiple of 512 buffer |
| // elements instead of 256--which means padding to 8KB. |
| |
| BufferSizeAlignment = |
| (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE) ? |
| 8192 : |
| 4096; |
| |
| BufferSizePadding = 16; |
| |
| Size = GFX_ALIGN(Size, BufferSizeAlignment) + BufferSizePadding; |
| } |
| |
| // HiZ Clear Color requires some small data at the end of the allocation to |
| // store the color data. |
| if(pTexInfo->Flags.Gpu.HiZ && pTexInfo->Flags.Gpu.IndirectClearColor) |
| { |
| Size += GMM_HIZ_CLEAR_COLOR_SIZE; |
| } |
| |
| if(pTexInfo->Flags.Info.ExistingSysMem && |
| !pTexInfo->ExistingSysMem.IsGmmAllocated && |
| !pTexInfo->ExistingSysMem.IsPageAligned) |
| { |
| // Do not modify Size |
| } |
| else |
| { |
| Size = GFX_ALIGN(Size, PAGE_SIZE); |
| } |
| } |
| |
| int64_t SurfaceMaxSize = 0; |
| |
| if(pTexInfo->Flags.Gpu.NoRestriction) |
| { |
| SurfaceMaxSize = pPlatform->NoRestriction.MaxWidth; |
| } |
| else |
| { |
| SurfaceMaxSize = pPlatform->SurfaceMaxSize; |
| } |
| |
| if(Size <= SurfaceMaxSize) |
| { |
| pTexInfo->Size = Size; |
| } |
| else |
| { |
| #if defined(__GMM_KMD__) || defined(__linux__) |
| GMM_ASSERTDPF(0, "Surface too large!"); |
| #endif |
| Status = GMM_ERROR; |
| } |
| } |
| |
| { |
| uint64_t TotalAlignment = (((uint64_t)((uint32_t)(pTexInfo->Alignment.BaseAlignment))) * ((uint32_t)(pBufferType->Alignment))); |
| |
| if(!pTexInfo->Alignment.BaseAlignment || __GMM_IS_ALIGN(pBufferType->Alignment, pTexInfo->Alignment.BaseAlignment)) |
| { |
| pTexInfo->Alignment.BaseAlignment = pBufferType->Alignment; |
| } |
| else if(__GMM_IS_ALIGN(pTexInfo->Alignment.BaseAlignment, pBufferType->Alignment)) |
| { |
| // Do nothing: pTexInfo->Alignment.BaseAlignment is properly alighned |
| } |
| else if(TotalAlignment > 0xFFFFFFFF) |
| { |
| GMM_ASSERTDPF(0, "Client requested alignment is too high, failing the allocation to match HW requiremnets. \r\n"); |
| Status = GMM_ERROR; |
| } |
| else |
| { |
| pTexInfo->Alignment.BaseAlignment = pTexInfo->Alignment.BaseAlignment * pBufferType->Alignment; |
| GMM_ASSERTDPF(0, |
| "Client requested alignment that is not properly aligned to HW requirements." |
| "Alignment is going to be much higher to match both client and HW requirements.\r\n"); |
| } |
| } |
| |
| if((pTexInfo->Flags.Gpu.TilePool && (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE)) || |
| (pTexInfo->Flags.Info.Undefined64KBSwizzle)) |
| { |
| pTexInfo->Alignment.BaseAlignment = GMM_KBYTE(64); |
| } |
| |
| if(pGmmGlobalContext->GetWaTable().WaCompressedResourceRequiresConstVA21 && pTexInfo->Flags.Gpu.MMC) |
| { |
| pTexInfo->Alignment.BaseAlignment = GMM_MBYTE(4); |
| } |
| |
| GMM_DPF_EXIT; |
| |
| return (Status); |
| } // FillTexPitchAndSize |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| /// Sets the tiling type based on the required alignment parameters. |
| /// |
| /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO |
| /// @param[in] CreateParams: Flags which specify what sort of resource to create |
| /// @param[in] YHeight: Height of Y plane |
| /// @param[in] YHeightAlignmentNeeded: Alignment requirement of Y plane |
| /// @param[in] VHeight: Height of UV plane |
| /// @param[in] VHeightAlignmentNeeded: Alignment requirement of UV plane |
| /// |
| ///////////////////////////////////////////////////////////////////////////////////// |
| void GmmLib::GmmTextureCalc::FillTexPlanar_SetTilingBasedOnRequiredAlignment( |
| GMM_TEXTURE_INFO *pTexInfo, |
| uint32_t YHeight, bool YHeightAlignmentNeeded, |
| uint32_t VHeight, bool VHeightAlignmentNeeded) |
| { |
| uint32_t YHeightAlignment, VHeightAlignment; |
| bool ClientAllowsTileFormat; |
| enum |
| { |
| X, |
| Y, |
| Yf, |
| Ys |
| }; |
| int32_t TileType; |
| |
| const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo); |
| |
| // First try Tile-Y, then Tile-X (then fallback to linear if necessary)... |
| for(TileType = Ys; TileType >= X; TileType--) |
| { |
| switch(TileType) |
| { |
| case Ys: |
| ClientAllowsTileFormat = (pTexInfo->Flags.Info.TiledYs != 0); |
| break; |
| case Yf: |
| ClientAllowsTileFormat = (pTexInfo->Flags.Info.TiledYf != 0); |
| break; |
| case Y: |
| ClientAllowsTileFormat = (pTexInfo->Flags.Info.TiledY != 0); |
| break; |
| default: |
| ClientAllowsTileFormat = (pTexInfo->Flags.Info.TiledX != 0); |
| } |
| |
| if(ClientAllowsTileFormat) |
| { |
| // When planar surfaces are tiled, there are HW alignment |
| // restrictions about where the U and V planes can be located. |
| // Prior to SURFACE_STATE.X/YOffset support, planes needed to start |
| // on tile boundaries; with X/YOffset support, the alignment |
| // restrictions were reduced (but not eliminated). |
| // |
| // Horizontal alignment is only an issue for IMC2/4 surfaces, since |
| // the planes of all other formats are always on the left-edge. |
| // This IMC2/4 horizontal alignment is handled in GmmTexFillPlanar. |
| // Here we will only consider vertical alignment. |
| // |
| // For IMC1/3 surfaces, we must ensure that both the U/V planes are |
| // properly aligned--That is, both the YHeight and VHeight must be |
| // properly aligned. For all other surfaces (since the U/V data |
| // starts at a common vertical location) only YHeight must be |
| // properly aligned. |
| |
| // Y/VHeight Alignments... |
| YHeightAlignment = |
| VHeightAlignment = |
| pPlatform->SurfaceStateYOffsetGranularity; |
| |
| // WA for PLANAR_420_* Formats... |
| if(pGmmGlobalContext->GetWaTable().WaSurfaceStatePlanarYOffsetAlignBy2 && |
| ((pTexInfo->Format == GMM_FORMAT_IMC1) || |
| (pTexInfo->Format == GMM_FORMAT_IMC2) || |
| (pTexInfo->Format == GMM_FORMAT_IMC3) || |
| (pTexInfo->Format == GMM_FORMAT_IMC4) || |
| (pTexInfo->Format == GMM_FORMAT_NV12) || |
| (pTexInfo->Format == GMM_FORMAT_YV12))) |
| { |
| YHeightAlignment = VHeightAlignment = 2; |
| } |
| |
| // Filter-Out Unneeded Alignments... |
| YHeightAlignment = YHeightAlignmentNeeded ? YHeightAlignment : 1; |
| VHeightAlignment = VHeightAlignmentNeeded ? VHeightAlignment : 1; |
| |
| if((TileType == Ys || TileType == Yf) || |
| ((YHeight == GFX_ALIGN(YHeight, YHeightAlignment)) && |
| (VHeight == GFX_ALIGN(VHeight, VHeightAlignment)))) |
| { |
| // clang-format off |
| #define SET_TILE_MODE(Submode) \ |
| (pTexInfo->BitsPerPixel == 128) ? TILE_##Submode##_128bpe : \ |
| (pTexInfo->BitsPerPixel == 64) ? TILE_##Submode##_64bpe : \ |
| (pTexInfo->BitsPerPixel == 32) ? TILE_##Submode##_32bpe : \ |
| (pTexInfo->BitsPerPixel == 16) ? TILE_##Submode##_16bpe : \ |
| TILE_##Submode##_8bpe |
| // clang-format on |
| // Cool--Drop other possibilities... |
| pTexInfo->Flags.Info.Linear = 0; |
| switch(TileType) |
| { |
| case Ys: |
| pTexInfo->Flags.Info.TiledX = 0; |
| pTexInfo->Flags.Info.TiledY = 0; |
| pTexInfo->Flags.Info.TiledYf = 0; |
| pTexInfo->TileMode = (pTexInfo->Type == RESOURCE_2D) ? SET_TILE_MODE(YS_2D) : SET_TILE_MODE(YS_3D); |
| break; |
| case Yf: |
| pTexInfo->Flags.Info.TiledX = 0; |
| pTexInfo->Flags.Info.TiledY = 0; |
| pTexInfo->Flags.Info.TiledYs = 0; |
| pTexInfo->TileMode = (pTexInfo->Type == RESOURCE_2D) ? SET_TILE_MODE(YF_2D) : SET_TILE_MODE(YF_3D); |
| break; |
| case Y: |
| pTexInfo->Flags.Info.TiledX = 0; |
| pTexInfo->Flags.Info.TiledYs = 0; |
| pTexInfo->Flags.Info.TiledYf = 0; |
| pTexInfo->TileMode = LEGACY_TILE_Y; |
| break; |
| default: |
| pTexInfo->Flags.Info.TiledY = 0; |
| pTexInfo->Flags.Info.TiledYs = 0; |
| pTexInfo->Flags.Info.TiledYf = 0; |
| pTexInfo->TileMode = LEGACY_TILE_X; |
| } |
| #undef SET_TILE_MODE |
| } |
| else |
| { |
| // Can't use this tiling format... |
| switch(TileType) |
| { |
| case Y: |
| pTexInfo->Flags.Info.TiledY = 0; |
| break; |
| case X: |
| pTexInfo->Flags.Info.TiledX = 0; |
| break; |
| default: |
| break; |
| } |
| } |
| } // if(ClientAllowsTileFormat) |
| } // for(TileType) |
| } // FillTexPlanar_SetTilingBasedOnRequiredAlignment |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| /// This function will Setup a planar surface allocation. |
| /// |
| /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO |
| /// @param[in] pRestrictions: Reference to surface alignment and size restrictions. |
| /// |
| /// @return ::GMM_STATUS |
| ///////////////////////////////////////////////////////////////////////////////////// |
| GMM_STATUS GMM_STDCALL GmmLib::GmmTextureCalc::FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo, |
| __GMM_BUFFER_TYPE *pRestrictions) |
| { |
| uint32_t WidthBytesPhysical, Height, YHeight, VHeight; |
| GMM_STATUS Status; |
| bool UVPacked = false; |
| |
| GMM_DPF_ENTER; |
| |
| __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); |
| __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); |
| __GMM_ASSERT(!pTexInfo->Flags.Info.TiledW); |
| pTexInfo->TileMode = TILE_NONE; |
| |
| const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo); |
| |
| WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3; |
| Height = VHeight = 0; |
| |
| YHeight = pTexInfo->BaseHeight; |
| |
| switch(pTexInfo->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 |
| { |
| VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); |
| |
| YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); |
| |
| Height = YHeight + 2 * VHeight; // One VHeight for V and one for U. |
| |
| pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; |
| |
| 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 |
| { |
| VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); |
| |
| YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); |
| |
| Height = YHeight + 2 * VHeight; |
| |
| pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; |
| |
| 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. |
| #if _WIN32 |
| case GMM_FORMAT_WGBOX_YUV444: |
| case GMM_FORMAT_WGBOX_PLANAR_YUV444: |
| #endif |
| // YYYYYYYY |
| // YYYYYYYY |
| // YYYYYYYY |
| // YYYYYYYY |
| // UUUUUUUU |
| // UUUUUUUU |
| // UUUUUUUU |
| // UUUUUUUU |
| // VVVVVVVV |
| // VVVVVVVV |
| // VVVVVVVV |
| // VVVVVVVV |
| { |
| YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); |
| VHeight = YHeight; |
| |
| Height = YHeight + 2 * VHeight; |
| |
| pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; |
| |
| break; |
| } |
| case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V |
| case GMM_FORMAT_IMC4: |
| { |
| // YYYYYYYY |
| // YYYYYYYY |
| // YYYYYYYY |
| // YYYYYYYY |
| // UUUUVVVV |
| // UUUUVVVV |
| |
| YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); |
| VHeight = GFX_CEIL_DIV(YHeight, 2); |
| |
| WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. |
| |
| Height = YHeight + VHeight; |
| |
| // With SURFACE_STATE.XOffset support, the U-V interface has |
| // much lighter restrictions--which will be naturally met by |
| // surface pitch restrictions (i.e. dividing an IMC2/4 pitch |
| // by 2--to get the U/V interface--will always produce a safe |
| // XOffset value). |
| |
| // Not technically UV packed but sizing works out the same |
| // if the resource is std swizzled |
| UVPacked = true; |
| pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2; |
| |
| 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(pTexInfo->BaseHeight, __GMM_EVEN_ROW); |
| if((pTexInfo->Format == GMM_FORMAT_NV12) || |
| (pTexInfo->Format == GMM_FORMAT_NV21) || |
| (pTexInfo->Format == GMM_FORMAT_P010) || |
| (pTexInfo->Format == GMM_FORMAT_P012) || |
| (pTexInfo->Format == GMM_FORMAT_P016)) |
| { |
| VHeight = GFX_CEIL_DIV(YHeight, 2); // U/V plane half of Y |
| Height = YHeight + VHeight; |
| } |
| else |
| { |
| VHeight = YHeight; // U/V plane is same as Y |
| Height = YHeight + VHeight; |
| } |
| |
| if((pTexInfo->Format == GMM_FORMAT_NV12) || |
| (pTexInfo->Format == GMM_FORMAT_NV21) || |
| (pTexInfo->Format == GMM_FORMAT_P010) || |
| (pTexInfo->Format == GMM_FORMAT_P012) || |
| (pTexInfo->Format == GMM_FORMAT_P016) || |
| (pTexInfo->Format == GMM_FORMAT_P208)) |
| { |
| WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. |
| } |
| else //if(pTexInfo->Format == GMM_FORMAT_NV11) |
| { |
| // Tiling not supported, since YPitch != UVPitch... |
| pTexInfo->Flags.Info.TiledY = 0; |
| pTexInfo->Flags.Info.TiledYf = 0; |
| pTexInfo->Flags.Info.TiledYs = 0; |
| pTexInfo->Flags.Info.TiledX = 0; |
| pTexInfo->Flags.Info.Linear = 1; |
| } |
| |
| UVPacked = true; |
| pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2; |
| break; |
| } |
| case GMM_FORMAT_I420: // IYUV & I420: are identical to YV12 except, |
| case GMM_FORMAT_IYUV: // U & V pl.s are reversed. |
| 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, UVSize, YVSizeRShift; |
| uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment; |
| |
| YSize = WidthBytesPhysical * YHeight; |
| |
| // 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 = (pTexInfo->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 = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; |
| YSizeForUVPurposes = |
| GFX_ALIGN(WidthBytesPhysical, YSizeForUVPurposesDimensionalAlignment) * |
| GFX_ALIGN(YHeight, YSizeForUVPurposesDimensionalAlignment); |
| |
| UVSize = 2 * // <-- U + V |
| (YSizeForUVPurposes >> YVSizeRShift); |
| |
| Height = GFX_CEIL_DIV(YSize + UVSize, WidthBytesPhysical); |
| |
| // Tiling not supported, since YPitch != UVPitch... |
| pTexInfo->Flags.Info.TiledY = 0; |
| pTexInfo->Flags.Info.TiledYf = 0; |
| pTexInfo->Flags.Info.TiledYs = 0; |
| pTexInfo->Flags.Info.TiledX = 0; |
| pTexInfo->Flags.Info.Linear = 1; |
| pTexInfo->OffsetInfo.Plane.NoOfPlanes = 1; |
| break; |
| } |
| default: |
| { |
| GMM_ASSERTDPF(0, "Unexpected format"); |
| return GMM_ERROR; |
| } |
| } |
| |
| // Align Height to even row to avoid hang if HW over-fetch |
| Height = GFX_ALIGN(Height, __GMM_EVEN_ROW); |
| |
| SetTileMode(pTexInfo); |
| |
| // MMC is not supported for linear formats. |
| if(pTexInfo->Flags.Gpu.MMC) |
| { |
| if(!(pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)) |
| { |
| pTexInfo->Flags.Gpu.MMC = 0; |
| } |
| } |
| |
| // Legacy Planar "Linear Video" Restrictions... |
| if(pTexInfo->Flags.Info.Linear && !pTexInfo->Flags.Wa.NoLegacyPlanarLinearVideoRestrictions) |
| { |
| pRestrictions->LockPitchAlignment = GFX_MAX(pRestrictions->LockPitchAlignment, GMM_BYTES(64)); |
| pRestrictions->MinPitch = GFX_MAX(pRestrictions->MinPitch, GMM_BYTES(64)); |
| pRestrictions->PitchAlignment = GFX_MAX(pRestrictions->PitchAlignment, GMM_BYTES(64)); |
| pRestrictions->RenderPitchAlignment = GFX_MAX(pRestrictions->RenderPitchAlignment, GMM_BYTES(64)); |
| } |
| |
| // Multiply overall pitch alignment for surfaces whose U/V planes have a |
| // pitch down-scaled from that of Y--Since the U/V pitches must meet the |
| // original restriction, the Y pitch must meet a scaled-up multiple. |
| if((pTexInfo->Format == GMM_FORMAT_I420) || |
| (pTexInfo->Format == GMM_FORMAT_IYUV) || |
| (pTexInfo->Format == GMM_FORMAT_NV11) || |
| (pTexInfo->Format == GMM_FORMAT_YV12) || |
| (pTexInfo->Format == GMM_FORMAT_YVU9)) |
| { |
| uint32_t LShift = |
| (pTexInfo->Format != GMM_FORMAT_YVU9) ? |
| 1 : // UVPitch = 1/2 YPitch |
| 2; // UVPitch = 1/4 YPitch |
| |
| pRestrictions->LockPitchAlignment <<= LShift; |
| pRestrictions->MinPitch <<= LShift; |
| pRestrictions->PitchAlignment <<= LShift; |
| pRestrictions->RenderPitchAlignment <<= LShift; |
| } |
| |
| // For Tiled Planar surfaces, the planes must be tile-boundary aligned. |
| // Actual alignment is handled in FillPlanarOffsetAddress, but height |
| // and width must be adjusted for correct size calculation |
| if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) |
| { |
| uint32_t TileHeight = pGmmGlobalContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; |
| uint32_t TileWidth = pGmmGlobalContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; |
| |
| pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes = true; |
| |
| Height = GFX_ALIGN(YHeight, TileHeight) + (GFX_ALIGN(VHeight, TileHeight) * (UVPacked ? 1 : 2)); |
| |
| if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns |
| pTexInfo->Format == GMM_FORMAT_IMC4) |
| { |
| // If the UV planes are packed then the surface pitch must be |
| // padded out so that the tile-aligned UV data will fit. |
| // This means that an odd Y plane width must be padded out |
| // with an additional tile. Even widths do not need padding |
| uint32_t TileCols = GFX_CEIL_DIV(WidthBytesPhysical, TileWidth); |
| if(TileCols % 2) |
| { |
| WidthBytesPhysical = (TileCols + 1) * TileWidth; |
| } |
| } |
| |
| if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf) |
| { |
| pTexInfo->Flags.Info.RedecribedPlanes = true; |
| } |
| } |
| |
| //Special case LKF MMC compressed surfaces |
| if(pTexInfo->Flags.Gpu.MMC && |
| pTexInfo->Flags.Gpu.UnifiedAuxSurface && |
| pTexInfo->Flags.Info.TiledY) |
| { |
| uint32_t TileHeight = pGmmGlobalContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; |
| uint32_t TileWidth = pGmmGlobalContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; |
| |
| Height = GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(VHeight, TileHeight); |
| } |
| |
| // Vary wide planar tiled planar formats do not support MMC pre gen11. All formats do not support |
| // MMC above 16k bytes wide, while Yf NV12 does not support above 8k - 128 bytes. |
| if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) <= IGFX_GEN10_CORE) && |
| (pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)) |
| { |
| if(((pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= GMM_KBYTE(16)) || |
| (pTexInfo->Format == GMM_FORMAT_NV12 && pTexInfo->Flags.Info.TiledYf && |
| (pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= (GMM_KBYTE(8) - 128))) |
| { |
| pTexInfo->Flags.Gpu.MMC = 0; |
| } |
| } |
| |
| if((Status = // <-- Note assignment. |
| FillTexPitchAndSize( |
| pTexInfo, WidthBytesPhysical, Height, pRestrictions)) == GMM_SUCCESS) |
| { |
| FillPlanarOffsetAddress(pTexInfo); |
| } |
| |
| // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout |
| // is defined by SW requirements; Y plane must be 4KB aligned. |
| if(pTexInfo->ArraySize > 1) |
| { |
| GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size; |
| int64_t LargeSize; |
| |
| // Size should always be page aligned. |
| __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0); |
| |
| if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize) |
| { |
| pTexInfo->OffsetInfo.Plane.ArrayQPitch = ElementSizeBytes; |
| pTexInfo->Size = LargeSize; |
| } |
| else |
| { |
| GMM_ASSERTDPF(0, "Surface too large!"); |
| Status = GMM_ERROR; |
| } |
| } |
| |
| GMM_DPF_EXIT; |
| return (Status); |
| } // FillTexPlanar |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| /// This function calculates the size and pitch for the linear buffer based on h/w |
| /// alignment and size restrictions. |
| /// |
| /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO |
| /// @param[in] pRestrictions: Reference to surface alignment and size restrictions |
| /// |
| /// @return ::GMM_STATUS |
| ///////////////////////////////////////////////////////////////////////////////////// |
| GMM_STATUS GmmLib::GmmTextureCalc::FillTexBlockMem(GMM_TEXTURE_INFO * pTexInfo, |
| __GMM_BUFFER_TYPE *pRestrictions) |
| { |
| GMM_GFX_SIZE_T WidthBytesPhysical; |
| uint32_t BitsPerPixel; |
| GMM_STATUS Status; |
| |
| __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); |
| __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); |
| __GMM_ASSERT(pTexInfo->BitsPerPixel == GMM_BITS(8) || (pTexInfo->Flags.Info.AllowVirtualPadding)); |
| __GMM_ASSERT(pTexInfo->BaseHeight == 1); |
| __GMM_ASSERT(pTexInfo->Flags.Info.Linear == 1); |
| __GMM_ASSERT(pTexInfo->Flags.Info.TiledW == 0); |
| __GMM_ASSERT(pTexInfo->Flags.Info.TiledX == 0); |
| __GMM_ASSERT(pTexInfo->Flags.Info.TiledY == 0); |
| __GMM_ASSERT(pTexInfo->Flags.Info.TiledYf == 0); |
| __GMM_ASSERT(pTexInfo->Flags.Info.TiledYs == 0); |
| |
| GMM_DPF_ENTER; |
| |
| // Width interpreted in bytes. |
| BitsPerPixel = pTexInfo->BitsPerPixel; |
| WidthBytesPhysical = pTexInfo->BaseWidth * BitsPerPixel >> 3; |
| |
| Status = GMM_SUCCESS; |
| |
| // Clients can allocate Buffers and Structured Buffers by specifying either |
| // total size (in BaseWidth) or as an array of structs with the ArraySize |
| // and BaseWidth parameters (where BaseWidth = size of the arrayed struct). |
| if((pTexInfo->Type == RESOURCE_BUFFER) && |
| (pTexInfo->ArraySize > 1)) |
| { |
| uint64_t __WidthBytesPhysical = WidthBytesPhysical; |
| |
| __WidthBytesPhysical *= pTexInfo->ArraySize; |
| |
| if(__WidthBytesPhysical <= pRestrictions->MaxPitch) |
| { |
| WidthBytesPhysical = (GMM_GFX_SIZE_T)__WidthBytesPhysical; |
| } |
| else |
| { |
| GMM_ASSERTDPF(0, "Surface too large!"); |
| Status = GMM_ERROR; |
| } |
| } |
| |
| if(Status == GMM_SUCCESS) |
| { |
| // Make sure minimum width and alignment is met. |
| WidthBytesPhysical = GFX_MAX(WidthBytesPhysical, pRestrictions->MinPitch); |
| WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, pRestrictions->PitchAlignment); |
| |
| Status = FillTexPitchAndSize(pTexInfo, WidthBytesPhysical, pTexInfo->BaseHeight, pRestrictions); |
| } |
| |
| GMM_DPF_EXIT; |
| return (Status); |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| /// This function does any special-case conversion from client-provided pseudo creation |
| /// parameters to actual parameters for CCS. |
| /// |
| /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO |
| /// |
| /// @return ::GMM_STATUS |
| ///////////////////////////////////////////////////////////////////////////////////// |
| GMM_STATUS GMM_STDCALL GmmLib::GmmTextureCalc::MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo) |
| { |
| GMM_STATUS Status = GMM_SUCCESS; |
| //const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo); |
| |
| if(pTexInfo->MSAA.NumSamples > 1) // CCS for MSAA Compression |
| { |
| Status = MSAACompression(pTexInfo); |
| } |
| else // Non-MSAA CCS Use (i.e. Render Target Fast Clear) |
| { |
| if(!pTexInfo->Flags.Info.TiledW && |
| ((!pTexInfo->Flags.Info.Linear) || |
| (GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags) || |
| (pTexInfo->Type == RESOURCE_BUFFER && pTexInfo->Flags.Info.Linear))) && //!Yf - deprecate Yf |
| ((pTexInfo->MaxLod == 0) && |
| (pTexInfo->ArraySize <= 1)) && |
| (((pTexInfo->BitsPerPixel == 32) || |
| (pTexInfo->BitsPerPixel == 64) || |
| (pTexInfo->BitsPerPixel == 128)))) |
| { |
| // For non-MSAA CCS usage, the four tables of |
| // requirements: |
| // (1) RT Alignment (GMM Don't Care: Occurs Naturally) |
| // (2) ClearRect Alignment |
| // (3) ClearRect Scaling (GMM Don't Care: GHAL3D Matter) |
| // (4) Non-MSAA CCS Sizing |
| |
| // Gen8+: |
| // Since mip-mapped and arrayed surfaces are supported, we |
| // deal with alignment later at per mip level. Here, we set |
| // tiling type only. TileX is not supported on Gen9+. |
| // Pre-Gen8: |
| // (!) For all the above, there are separate entries for |
| // 32/64/128bpp--and then deals with PIXEL widths--Here, |
| // though, we will unify by considering 8bpp table entries |
| // (unlisted--i.e. do the math)--and deal with BYTE widths. |
| |
| // (1) RT Alignment -- The surface width and height don't |
| // need to be padded to RT CL granularity. On HSW, all tiled |
| // RT's will have appropriate alignment (given 4KB surface |
| // base and no mip-map support) and appropriate padding |
| // (due to tile padding). On BDW+, GMM uses H/VALIGN that |
| // will guarantee the MCS RT alignment for all subresources. |
| |
| // (2) ClearRect Alignment -- I.e. FastClears must be done |
| // with certain granularity: |
| // TileY: 512 Bytes x 128 Lines |
| // TileX: 1024 Bytes x 64 Lines |
| // So a CCS must be sized to match that granularity (though |
| // the RT itself need not be fully padded to that |
| // granularity to use FastClear). |
| |
| // (4) Non-MSAA CCS Sizing -- CCS sizing is based on the |
| // size of the FastClear (with granularity padding) for the |
| // paired RT. CCS's (byte widths and heights) are scaled |
| // down from their RT's by: |
| // TileY: 32 x 32 |
| // TileX: 64 x 16 |
| |
| // ### Example ############################################# |
| // RT: 800x600, 32bpp, TileY |
| // 8bpp: 3200x600 |
| // FastClear: 3584x640 (for TileY FastClear Granularity of 512x128) |
| // CCS: 112x20 (for TileY RT:CCS Sizing Downscale of 32x32) |
| |
| uint32_t AlignmentFactor = pGmmGlobalContext->GetWaTable().WaDoubleFastClearWidthAlignment ? 2 : 1; |
| |
| pTexInfo->BaseWidth = pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8; |
| pTexInfo->BitsPerPixel = 8; |
| pTexInfo->Format = GMM_FORMAT_R8_UINT; |
| |
| if(GMM_IS_4KB_TILE(pTexInfo->Flags)) //-------- Fast Clear Granularity |
| { // /--- RT:CCS Sizing Downscale |
| pTexInfo->BaseWidth = GFX_ALIGN(pTexInfo->BaseWidth, 512 * AlignmentFactor) / 32; |
| pTexInfo->BaseHeight = GFX_ALIGN(pTexInfo->BaseHeight, 128) / 32; |
| } |
| else //if(pTexInfo->Flags.Info.TiledX) |
| { |
| pTexInfo->BaseWidth = GFX_ALIGN(pTexInfo->BaseWidth, 1024 * AlignmentFactor) / 64; |
| pTexInfo->BaseHeight = GFX_ALIGN(pTexInfo->BaseHeight, 64) / 16; |
| } |
| } |
| else |
| { |
| GMM_ASSERTDPF(0, "Illegal CCS creation parameters!"); |
| Status = GMM_ERROR; |
| } |
| } |
| return Status; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| /// This function does any special-case conversion from client-provided pseudo creation |
| /// parameters to actual parameters for CCS for MSAA Compression. |
| /// |
| /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO |
| /// |
| /// @return ::GMM_STATUS |
| ///////////////////////////////////////////////////////////////////////////////////// |
| GMM_STATUS GmmLib::GmmTextureCalc::MSAACompression(GMM_TEXTURE_INFO *pTexInfo) |
| { |
| GMM_STATUS Status = GMM_SUCCESS; |
| |
| if((pTexInfo->MSAA.NumSamples == 2) || (pTexInfo->MSAA.NumSamples == 4)) |
| { |
| pTexInfo->BitsPerPixel = 8; |
| pTexInfo->Format = GMM_FORMAT_R8_UINT; |
| } |
| else if(pTexInfo->MSAA.NumSamples == 8) |
| { |
| pTexInfo->BitsPerPixel = 32; |
| pTexInfo->Format = GMM_FORMAT_R32_UINT; |
| } |
| else //if(pTexInfo->MSAA.NumSamples == 16) |
| { |
| pTexInfo->BitsPerPixel = 64; |
| pTexInfo->Format = GMM_FORMAT_GENERIC_64BIT; |
| } |
| |
| if((Status = __GmmTexFillHAlignVAlign(pTexInfo)) != GMM_SUCCESS) // Need to get our alignment (matching RT) before overwriting our RT's MSAA setting. |
| { |
| return Status; |
| } |
| pTexInfo->MSAA.NumSamples = 1; // CCS itself isn't MSAA'ed. |
| pTexInfo->Flags.Gpu.__MsaaTileMcs = 1; |
| |
| return Status; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////////////// |
| ///Allocate one memory tile wider than is required for Media Memory Compression |
| /// |
| /// @param[in] See function definition. |
| /// |
| /// @return :: |
| ///////////////////////////////////////////////////////////////////////////////////// |
| void GMM_STDCALL GmmLib::GmmTextureCalc::AllocateOneTileThanRequied(GMM_TEXTURE_INFO *pTexInfo, |
| GMM_GFX_SIZE_T & WidthBytesRender, |
| GMM_GFX_SIZE_T & WidthBytesPhysical, |
| GMM_GFX_SIZE_T & WidthBytesLock) |
| { |
| const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo); |
| |
| if(pTexInfo->Flags.Gpu.MMC && !pTexInfo->Flags.Gpu.UnifiedAuxSurface) |
| { |
| WidthBytesRender += pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth; |
| WidthBytesPhysical = WidthBytesLock = WidthBytesRender; |
| } |
| } |