From edb82f49e5905b2dbe282e5a3bad36df43c6393e Mon Sep 17 00:00:00 2001 From: vipuldas Date: Thu, 1 Mar 2018 13:12:15 -0800 Subject: [PATCH] Fix LCU alignment for surfaces Change-Id: I185776db51a8b0a3f4d301fc3c79e206a08afb1b --- Source/GmmLib/Texture/GmmGen10Texture.cpp | 715 ++++++++++++++++++ Source/GmmLib/Utility/GmmUtility.cpp | 36 +- Source/GmmLib/inc/External/Common/GmmConst.h | 3 +- .../inc/External/Common/GmmResourceInfoExt.h | 1 + .../Common/Texture/GmmGen10TextureCalc.h | 8 + Source/inc/common/sku_wa.h | 6 + 6 files changed, 765 insertions(+), 4 deletions(-) diff --git a/Source/GmmLib/Texture/GmmGen10Texture.cpp b/Source/GmmLib/Texture/GmmGen10Texture.cpp index 3ae16fc..07154cb 100644 --- a/Source/GmmLib/Texture/GmmGen10Texture.cpp +++ b/Source/GmmLib/Texture/GmmGen10Texture.cpp @@ -256,4 +256,719 @@ uint32_t GmmLib::GmmGen10TextureCalc::GetAligned3DBlockHeight(GMM_TEXTURE_INFO * return BlockHeight; } +///////////////////////////////////////////////////////////////////////////////////// +/// Allocates the 2D mip layout for surface state programming. +/// +/// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, +/// @param[in] pRestrictions: ptr to surface alignment and size restrictions +/// +/// @return ::GMM_STATUS +///////////////////////////////////////////////////////////////////////////////////// +GMM_STATUS GMM_STDCALL GmmLib::GmmGen10TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo, + __GMM_BUFFER_TYPE *pRestrictions) +{ + uint32_t Width, Height, BitsPerPixel; + uint32_t HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth; + uint32_t AlignedWidth, BlockHeight, ExpandedArraySize, Pitch; + uint8_t Compress = 0; + GMM_STATUS Status; + + GMM_DPF_ENTER; + + __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); + __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); + + const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo); + + BitsPerPixel = pTexInfo->BitsPerPixel; + if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) + { + // Aux Surfaces are 8bpp. + BitsPerPixel = 8; + } + + Height = pTexInfo->BaseHeight; + Width = GFX_ULONG_CAST(pTexInfo->BaseWidth); + + pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1); + + if(pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) + { + FindMipTailStartLod(pTexInfo); + } + + ExpandedArraySize = + GFX_MAX(pTexInfo->ArraySize, 1) * + ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays. + ((pTexInfo->Type == RESOURCE_3D) ? pTexInfo->Depth : 1) * // 3D's simply 2D arrays. + ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil || + (pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf)) ? // MSAA Ys samples are NOT stored as array planes. + 1 : + pTexInfo->MSAA.NumSamples); // MSAA (non-Depth/Stencil) RT samples stored as array planes. + + if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf) + { + ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth); + } + + // + // Check for color separation + // + if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX) + { + bool csRestrictionsMet = (((ExpandedArraySize <= 2) && + (ExpandedArraySize == pTexInfo->ArraySize) && + ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) || + (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) || + (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) || + (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) || + (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) || + (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) && + ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) || + (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0)))); + + if(csRestrictionsMet) + { + ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE; + } + else + { + pTexInfo->Flags.Gpu.ColorSeparation = false; + pTexInfo->Flags.Gpu.ColorSeparationRGBX = false; + } + } + + HAlign = pTexInfo->Alignment.HAlign; + VAlign = pTexInfo->Alignment.VAlign; + DAlign = pTexInfo->Alignment.DAlign; + GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); + + Compress = GmmIsCompressed(pTexInfo->Format); + + ///////////////////////////////// + // Calculate Block Surface Height + ///////////////////////////////// + + if(ExpandedArraySize > 1) + { + uint32_t Alignment = VAlign; + if((pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) || + (pTexInfo->Flags.Gpu.S3dDx && pGmmGlobalContext->GetSkuTable().FtrDisplayEngineS3d)) + { + Alignment = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; + } + + // Calculate the overall Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) + BlockHeight = Get2DMipMapTotalHeight(pTexInfo); + BlockHeight = GFX_ALIGN_NP2(BlockHeight, Alignment); + + // GMM internally uses QPitch as the logical distance between slices, but translates + // as appropriate to service client queries in GmmResGetQPitch. + pTexInfo->Alignment.QPitch = BlockHeight; + + if(Compress) + { + BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight); + + BlockHeight = GetAligned3DBlockHeight(pTexInfo, BlockHeight, ExpandedArraySize); + } + else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) + { + BlockHeight /= 2; + } + else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) + { + BlockHeight /= 16; + } + + BlockHeight *= ExpandedArraySize; + } + else + { + pTexInfo->Alignment.QPitch = 0; + + BlockHeight = Get2DMipMapHeight(pTexInfo); + } + + /////////////////////////////////// + // Calculate Pitch + /////////////////////////////////// + + AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo); + + // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths + // are greater than LOD0. e.g. dimensions 4x4 and MinPitch == 1 + if((pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) && + (pTexInfo->Alignment.MipTailStartLod < 2)) + { + // Do nothing -- all mips are in LOD0/LOD1, which is already width aligned. + } + else if(pTexInfo->MaxLod >= 2) + { + uint32_t AlignedWidthLod1, AlignedWidthLod2; + + AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo); + AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo); + + AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2); + } + + if(Compress) + { + AlignedWidth = GFX_CEIL_DIV(AlignedWidth, CompressWidth); + } + else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) + { + AlignedWidth *= 2; + } + else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) + { + switch(pTexInfo->BitsPerPixel) + { + case 32: + AlignedWidth /= 8; + break; + case 64: + AlignedWidth /= 4; + break; + case 128: + AlignedWidth /= 2; + break; + default: + __GMM_ASSERT(0); + } + } + else if(pTexInfo->Flags.Gpu.ColorSeparation) + { + AlignedWidth *= pTexInfo->ArraySize; + __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION)); + AlignedWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION; + } + else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX) + { + AlignedWidth *= pTexInfo->ArraySize; + __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION)); + AlignedWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION; + } + + // Default pitch + Pitch = AlignedWidth * BitsPerPixel >> 3; + + // Make sure the pitch satisfy linear min pitch requirment + Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch); + + // Make sure pitch satisfy alignment restriction + Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment); + + //////////////////// + // Adjust for Tiling + //////////////////// + + if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) + { + Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth); + BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); + } + + GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!"); + pTexInfo->Flags.Info.LayoutBelow = 1; + pTexInfo->Flags.Info.LayoutRight = 0; + + // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of + // padding needs to be added. Since this will create a none pitch aligned + // surface the padding is aligned to the next row + if(GmmIsYUVPacked(pTexInfo->Format) || + (pTexInfo->BitsPerPixel == GMM_BITS(96)) || + (pTexInfo->BitsPerPixel == GMM_BITS(48))) + { + BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch); + } + + // For Non-planar surfaces, the alignment is done on the entire height of the allocation + if(pGmmGlobalContext->GetWaTable().WaAlignYUVResourceToLCU && + GmmIsYUVFormatLCUAligned(pTexInfo->Format) && + !GmmIsPlanar(pTexInfo->Format)) + { + BlockHeight = GFX_ALIGN(BlockHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE)); + } + + // Align height to even row to cover for HW over-fetch + BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW); + + if((Status = // <-- Note assignment. + FillTexPitchAndSize( + pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS) + { + Fill2DTexOffsetAddress(pTexInfo); + } + + GMM_DPF_EXIT; + + return (Status); +} + +///////////////////////////////////////////////////////////////////////////////////// +/// 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::GmmGen10TextureCalc::FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo, + __GMM_BUFFER_TYPE *pRestrictions) +{ + uint32_t WidthBytesPhysical, Height, YHeight, VHeight; + uint32_t AdjustedVHeight = 0; + 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); + // Client should always give us linear-fallback option for planar surfaces, + // except for MMC surfaces, which are TileY. + //__GMM_ASSERT(pTexInfo->Flags.Info.Linear || pTexInfo->Flags.Gpu.MMC); + pTexInfo->Flags.Info.Linear = 1; + 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. + + FillTexPlanar_SetTilingBasedOnRequiredAlignment( + pTexInfo, + YHeight, true, // <-- YHeight alignment needed (so U is properly aligned). + VHeight, true); // <-- VHeight alignment needed (so V is properly aligned). + + 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; + + FillTexPlanar_SetTilingBasedOnRequiredAlignment( + pTexInfo, + YHeight, true, // <-- YHeight alignment needed (so U is properly aligned). + VHeight, true); // <-- VHeight alignment needed (so V is properly aligned). + + 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(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); + VHeight = YHeight; + + Height = YHeight + 2 * VHeight; + + FillTexPlanar_SetTilingBasedOnRequiredAlignment( + pTexInfo, + YHeight, true, // <-- YHeight alignment needed (so U is properly aligned). + YHeight, true); // <-- VHeight alignment needed (so V is properly aligned). + + 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; + + FillTexPlanar_SetTilingBasedOnRequiredAlignment( + pTexInfo, + YHeight, true, // <-- YHeight alignment needed (so U/V are properly aligned, vertically). + 0, false); // <-- VHeight alignment NOT needed (since U/V aren't on top of eachother). + + // 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 = pTexInfo->Flags.Info.StdSwizzle ? true : false; + + break; + } + case GMM_FORMAT_NV12: + case GMM_FORMAT_NV21: + { + // Allocate SW defined layout (Y0)(Y1)(UV0)(UV1) + if(pTexInfo->Flags.Info.YUVShaderFriendlyLayout) + { + uint32_t UnitAlignHeight, BlockHeightY, BlockHeightUV; + + __GMM_ASSERT(pTexInfo->ArraySize == 2); + + pTexInfo->ArraySize = 2; + + UnitAlignHeight = pTexInfo->Alignment.VAlign; + + // Get total height for one Y plane + BlockHeightY = GFX_ALIGN(YHeight, UnitAlignHeight); + + if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) < IGFX_GEN8_CORE) + { + pTexInfo->Alignment.ArraySpacingSingleLod = 1; + } + + // Get total height for one UV plane + BlockHeightUV = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 2), UnitAlignHeight); + + // Save plane offset information + pTexInfo->OffsetInfo.Plane.ArrayQPitch = 0; + pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_3D_Y0] = 0; + pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_3D_Y1] = BlockHeightY; + pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_3D_UV0] = BlockHeightY * 2; + pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_3D_UV1] = (BlockHeightY * 2) + BlockHeightUV; + + // Get total height for (Y0)(Y1)(UV0)(UV1) + Height = (BlockHeightY * 2) + (BlockHeightUV * 2); + break; + } + // else drop down to NV11, P208. + } + 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] + + 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. + + FillTexPlanar_SetTilingBasedOnRequiredAlignment( + pTexInfo, + YHeight, true, // <-- YHeight alignment needed (so UV is properly aligned). + 0, false); // <-- VHeight alignment NOT needed (since U/V aren't on top of eachother). + } + 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; + + 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; + + 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); + + // If the Surface has Odd height dimension, we will fall back to Linear Format. + // If MMC is enabled, disable MMC during such cases. + 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; + } + + AdjustedVHeight = VHeight; + // In case of Planar surfaces, only the last Plane has to be aligned to 64 for LCU access + if(pGmmGlobalContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format) && VHeight > 0) + { + AdjustedVHeight = GFX_ALIGN(VHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE)); + Height += AdjustedVHeight - VHeight; + } + + // For std swizzled and UV packed tile Ys/Yf cases, 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((pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf) && + (pTexInfo->Flags.Info.StdSwizzle || UVPacked)) + { + uint32_t TileHeight = pGmmGlobalContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; + uint32_t TileWidth = pGmmGlobalContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; + + //for separate U and V planes, use U plane unaligned and V plane aligned + Height = GFX_ALIGN(YHeight, TileHeight) + (UVPacked ? GFX_ALIGN(AdjustedVHeight, TileHeight) : + (GFX_ALIGN(VHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight))); + + if(UVPacked) + { + // 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; + } + } + + pTexInfo->Flags.Info.RedecribedPlanes = 1; + } + + //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; + + Height = GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, 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) && !pTexInfo->Flags.Info.YUVShaderFriendlyLayout) + { + 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 #endif // #if (IGFX_GEN >= IGFX_GEN10) diff --git a/Source/GmmLib/Utility/GmmUtility.cpp b/Source/GmmLib/Utility/GmmUtility.cpp index 594d54b..be325cd 100644 --- a/Source/GmmLib/Utility/GmmUtility.cpp +++ b/Source/GmmLib/Utility/GmmUtility.cpp @@ -160,6 +160,35 @@ uint8_t GMM_STDCALL GmmIsUVPacked(GMM_RESOURCE_FORMAT Format) return Status; } +///////////////////////////////////////////////////////////////////////////////////// +/// Checks if format can be accessed by LCU +/// +/// @param[in] pSurf: ptr to ::GMM_TEXTURE_INFO of main surface +/// @param[in] pAuxTexInfo: ptr to ::GMM_TEXTURE_INFO of Aux surface +/// +///////////////////////////////////////////////////////////////////////////////////// +bool GMM_STDCALL GmmIsYUVFormatLCUAligned(GMM_RESOURCE_FORMAT Format) +{ + bool Status = 0; + + switch(Format) + { + case GMM_FORMAT_NV12: + case GMM_FORMAT_P010: + case GMM_FORMAT_P016: + case GMM_FORMAT_YUY2: + case GMM_FORMAT_Y216: + case GMM_FORMAT_Y416: + case GMM_FORMAT_AYUV: + Status = true; + break; + default: + Status = false; + break; + } + return Status; +} + //============================================================================= // Function: // GmmIsYUVPacked @@ -329,7 +358,6 @@ void GMM_STDCALL GmmGetCacheSizes(GMM_CACHE_SIZES *pCacheSizes) GMM_DPF_EXIT; } - namespace GmmLib { namespace Utility @@ -544,8 +572,10 @@ namespace GmmLib Invalid: return (GMM_FORMAT_INVALID); } - } -} + + + } // namespace Utility +} // namespace GmmLib //============================================================================= // diff --git a/Source/GmmLib/inc/External/Common/GmmConst.h b/Source/GmmLib/inc/External/Common/GmmConst.h index 3fd148d..193938a 100644 --- a/Source/GmmLib/inc/External/Common/GmmConst.h +++ b/Source/GmmLib/inc/External/Common/GmmConst.h @@ -50,4 +50,5 @@ OTHER DEALINGS IN THE SOFTWARE. #define GMM_MSAA_SAMPLES_MAX 16 #define GMM_HIZ_CLEAR_COLOR_SIZE (8) #define GMM_MEDIA_COMPRESSION_STATE_SIZE (64) -#define GMM_CLEAR_COLOR_FLOAT_SIZE (16) \ No newline at end of file +#define GMM_CLEAR_COLOR_FLOAT_SIZE (16) +#define GMM_MAX_LCU_SIZE 64 // Media Largest coding Unit \ No newline at end of file diff --git a/Source/GmmLib/inc/External/Common/GmmResourceInfoExt.h b/Source/GmmLib/inc/External/Common/GmmResourceInfoExt.h index 57b3eb8..4134fb5 100644 --- a/Source/GmmLib/inc/External/Common/GmmResourceInfoExt.h +++ b/Source/GmmLib/inc/External/Common/GmmResourceInfoExt.h @@ -438,6 +438,7 @@ typedef struct GMM_GET_MAPPING_REC uint8_t GMM_STDCALL GmmIsPlanar(GMM_RESOURCE_FORMAT Format); uint8_t GMM_STDCALL GmmIsP0xx(GMM_RESOURCE_FORMAT Format); uint8_t GMM_STDCALL GmmIsUVPacked(GMM_RESOURCE_FORMAT Format); +bool GMM_STDCALL GmmIsYUVFormatLCUAligned(GMM_RESOURCE_FORMAT Format); #define GmmIsYUVPlanar GmmIsPlanar // TODO(Benign): Support old name until we have a chance to correct in UMD(s) using this. No longer YUV since there are now RGB planar formats. uint8_t GMM_STDCALL GmmIsCompressed(GMM_RESOURCE_FORMAT Format); uint8_t GMM_STDCALL GmmIsYUVPacked(GMM_RESOURCE_FORMAT Format); diff --git a/Source/GmmLib/inc/Internal/Common/Texture/GmmGen10TextureCalc.h b/Source/GmmLib/inc/Internal/Common/Texture/GmmGen10TextureCalc.h index 0ec95fd..3135561 100644 --- a/Source/GmmLib/inc/Internal/Common/Texture/GmmGen10TextureCalc.h +++ b/Source/GmmLib/inc/Internal/Common/Texture/GmmGen10TextureCalc.h @@ -74,6 +74,14 @@ namespace GmmLib /* Function prototypes */ + virtual GMM_STATUS GMM_STDCALL FillTex2D( + GMM_TEXTURE_INFO *pTexInfo, + __GMM_BUFFER_TYPE *pRestrictions); + + virtual GMM_STATUS GMM_STDCALL FillTexPlanar( + GMM_TEXTURE_INFO *pTexInfo, + __GMM_BUFFER_TYPE *pRestrictions); + /* inline functions */ }; } diff --git a/Source/inc/common/sku_wa.h b/Source/inc/common/sku_wa.h index 801c2df..96d6116 100644 --- a/Source/inc/common/sku_wa.h +++ b/Source/inc/common/sku_wa.h @@ -430,6 +430,12 @@ typedef struct _WA_TABLE WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) + WA_DECLARE( + WaAlignYUVResourceToLCU, + "source and recon surfaces need to be aligned to the LCU size", + WA_BUG_TYPE_CORRUPTION, + WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) + } WA_TABLE, *PWA_TABLE; //********************************** SKU/WA Macros *************************************