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