2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-06-11 18:27:07 -04:00
# include "AllocatedVirtualTexture.h"
2020-10-22 19:19:16 -04:00
2019-10-10 23:28:29 -04:00
# include "VT/VirtualTextureScalability.h"
# include "VT/VirtualTextureSystem.h"
# include "VT/VirtualTextureSpace.h"
# include "VT/VirtualTexturePhysicalSpace.h"
2021-02-19 16:48:18 -04:00
# include "Misc/StringBuilder.h"
2019-06-11 18:27:07 -04:00
FAllocatedVirtualTexture : : FAllocatedVirtualTexture ( FVirtualTextureSystem * InSystem ,
uint32 InFrame ,
const FAllocatedVTDescription & InDesc ,
FVirtualTextureProducer * const * InProducers ,
uint32 InBlockWidthInTiles ,
uint32 InBlockHeightInTiles ,
uint32 InWidthInBlocks ,
uint32 InHeightInBlocks ,
uint32 InDepthInTiles )
2020-01-24 18:07:01 -05:00
: IAllocatedVirtualTexture ( InDesc , InBlockWidthInTiles , InBlockHeightInTiles , InWidthInBlocks , InHeightInBlocks , InDepthInTiles )
2019-06-11 18:27:07 -04:00
, FrameAllocated ( InFrame )
2020-01-24 18:07:01 -05:00
, Space ( nullptr )
2019-06-11 18:27:07 -04:00
{
check ( IsInRenderingThread ( ) ) ;
2019-09-17 20:33:19 -04:00
FMemory : : Memzero ( TextureLayers ) ;
2021-12-03 13:43:10 -05:00
FMemory : : Memzero ( FallbackColorPerTextureLayer ) ;
2019-06-11 18:27:07 -04:00
2019-09-17 20:33:19 -04:00
for ( uint32 LayerIndex = 0u ; LayerIndex < Description . NumTextureLayers ; + + LayerIndex )
2019-06-11 18:27:07 -04:00
{
2019-09-17 20:33:19 -04:00
FVirtualTextureProducer const * Producer = InProducers [ LayerIndex ] ;
2019-10-23 14:08:35 -04:00
// Can't have missing entries for null producers if we're not merging duplicate layers
if ( Producer | | ! Description . bShareDuplicateLayers )
2019-06-11 18:27:07 -04:00
{
2019-10-23 14:08:35 -04:00
const uint32 UniqueProducerIndex = AddUniqueProducer ( InDesc . ProducerHandle [ LayerIndex ] , Producer ) ;
2019-09-17 20:33:19 -04:00
const int32 ProducerLayerIndex = InDesc . ProducerLayerIndex [ LayerIndex ] ;
2019-10-23 14:08:35 -04:00
uint32 ProducerPhysicalGroupIndex = 0u ;
FVirtualTexturePhysicalSpace * PhysicalSpace = nullptr ;
if ( Producer )
{
ProducerPhysicalGroupIndex = Producer - > GetPhysicalGroupIndexForTextureLayer ( ProducerLayerIndex ) ;
PhysicalSpace = Producer - > GetPhysicalSpaceForPhysicalGroup ( ProducerPhysicalGroupIndex ) ;
}
2019-09-17 20:33:19 -04:00
const uint32 UniquePhysicalSpaceIndex = AddUniquePhysicalSpace ( PhysicalSpace , UniqueProducerIndex , ProducerPhysicalGroupIndex ) ;
UniquePageTableLayers [ UniquePhysicalSpaceIndex ] . ProducerTextureLayerMask | = 1 < < ProducerLayerIndex ;
const uint8 PageTableLayerLocalIndex = UniquePageTableLayers [ UniquePhysicalSpaceIndex ] . TextureLayerCount + + ;
TextureLayers [ LayerIndex ] . UniquePageTableLayerIndex = UniquePhysicalSpaceIndex ;
TextureLayers [ LayerIndex ] . PhysicalTextureIndex = PageTableLayerLocalIndex ;
2021-12-03 13:43:10 -05:00
if ( Producer )
{
FallbackColorPerTextureLayer [ LayerIndex ] = Producer - > GetDescription ( ) . LayerFallbackColor [ ProducerLayerIndex ] . ToFColor ( false ) . DWColor ( ) ;
}
2019-06-11 18:27:07 -04:00
}
}
// Must have at least 1 valid layer/producer
2019-09-17 20:33:19 -04:00
check ( UniqueProducers . Num ( ) > 0u ) ;
2019-06-11 18:27:07 -04:00
// Max level of overall allocated VT is limited by size in tiles
// With multiple layers of different sizes, some layers may have mips smaller than a single tile
2021-03-25 12:40:35 -04:00
// We can either use the Min or Max of Width/Height to determine the number of mips
// - Using Max will allow more mips for rectangular VTs, which could potentially reduce aliasing in certain situations
// - Using Min will relax alignment requirements for the page table allocator, which will tend to reduce overall VRAM usage
MaxLevel = FMath : : Min ( MaxLevel , FMath : : CeilLogTwo ( FMath : : Min ( GetWidthInTiles ( ) , GetHeightInTiles ( ) ) ) ) ;
2019-06-11 18:27:07 -04:00
2021-01-25 16:45:24 -04:00
MaxLevel = FMath : : Min ( MaxLevel , VIRTUALTEXTURE_LOG2_MAX_PAGETABLE_SIZE - 1u ) ;
2020-01-24 18:07:01 -05:00
2021-12-03 01:10:59 -05:00
// Get the persistent hash that we will use for identification of AllocatedVT objects across runs.
PersistentHash = CalculatePersistentHash ( InDesc , InProducers ) ;
2021-05-04 11:48:09 -04:00
// Lock tiles
LockOrUnlockTiles ( InSystem , true ) ;
2019-06-11 18:27:07 -04:00
2020-03-23 15:55:34 -04:00
// Use 16bit page table entries if all physical spaces are small enough
bool bSupport16BitPageTable = true ;
for ( int32 Index = 0 ; Index < UniquePageTableLayers . Num ( ) ; + + Index )
{
2020-07-02 13:45:03 -04:00
const FVirtualTexturePhysicalSpace * PhysicalSpace = UniquePageTableLayers [ Index ] . PhysicalSpace ;
if ( PhysicalSpace & & ! PhysicalSpace - > DoesSupport16BitPageTable ( ) )
2020-03-23 15:55:34 -04:00
{
bSupport16BitPageTable = false ;
break ;
}
}
2020-01-24 18:07:01 -05:00
FVTSpaceDescription SpaceDesc ;
SpaceDesc . Dimensions = InDesc . Dimensions ;
SpaceDesc . NumPageTableLayers = UniquePageTableLayers . Num ( ) ;
SpaceDesc . TileSize = InDesc . TileSize ;
SpaceDesc . TileBorderSize = InDesc . TileBorderSize ;
SpaceDesc . bPrivateSpace = InDesc . bPrivateSpace ;
2020-10-22 19:19:16 -04:00
SpaceDesc . MaxSpaceSize = InDesc . MaxSpaceSize > 0 ? InDesc . MaxSpaceSize : SpaceDesc . MaxSpaceSize ;
SpaceDesc . IndirectionTextureSize = InDesc . IndirectionTextureSize ;
2020-03-23 15:55:34 -04:00
SpaceDesc . PageTableFormat = bSupport16BitPageTable ? EVTPageTableFormat : : UInt16 : EVTPageTableFormat : : UInt32 ;
2020-10-22 19:19:16 -04:00
Space = InSystem - > AcquireSpace ( SpaceDesc , InDesc . ForceSpaceID , this ) ;
2020-01-24 18:07:01 -05:00
SpaceID = Space - > GetID ( ) ;
PageTableFormat = Space - > GetPageTableFormat ( ) ;
2019-06-11 18:27:07 -04:00
}
FAllocatedVirtualTexture : : ~ FAllocatedVirtualTexture ( )
{
}
2020-10-26 15:28:18 -04:00
void FAllocatedVirtualTexture : : AssignVirtualAddress ( uint32 vAddress )
{
checkf ( VirtualAddress = = ~ 0u , TEXT ( " Trying to assign vAddress to AllocatedVT, already assigned " ) ) ;
check ( vAddress ! = ~ 0u ) ;
VirtualAddress = vAddress ;
VirtualPageX = FMath : : ReverseMortonCode2 ( vAddress ) ;
VirtualPageY = FMath : : ReverseMortonCode2 ( vAddress > > 1 ) ;
}
2019-06-11 18:27:07 -04:00
void FAllocatedVirtualTexture : : Destroy ( FVirtualTextureSystem * System )
{
check ( IsInRenderingThread ( ) ) ;
2021-05-05 13:09:24 -04:00
check ( NumRefs = = 0 ) ;
2019-06-11 18:27:07 -04:00
// Unlock any locked tiles
2021-05-04 11:48:09 -04:00
LockOrUnlockTiles ( System , false ) ;
2019-06-11 18:27:07 -04:00
2020-10-22 19:19:16 -04:00
// Physical pool needs to evict all pages that belong to this VT
2019-09-17 20:33:19 -04:00
{
2021-03-25 14:24:11 -04:00
const uint32 WidthInTiles = GetWidthInTiles ( ) ;
const uint32 HeightInTiles = GetHeightInTiles ( ) ;
2020-07-06 18:58:26 -04:00
2019-09-17 20:33:19 -04:00
TArray < FVirtualTexturePhysicalSpace * > UniquePhysicalSpaces ;
for ( int32 PageTableIndex = 0u ; PageTableIndex < UniquePageTableLayers . Num ( ) ; + + PageTableIndex )
2019-06-11 18:27:07 -04:00
{
2019-10-23 14:08:35 -04:00
if ( UniquePageTableLayers [ PageTableIndex ] . PhysicalSpace )
{
UniquePhysicalSpaces . Add ( UniquePageTableLayers [ PageTableIndex ] . PhysicalSpace ) ;
}
2019-09-17 20:33:19 -04:00
}
for ( FVirtualTexturePhysicalSpace * PhysicalSpace : UniquePhysicalSpaces )
{
2021-03-25 14:24:11 -04:00
PhysicalSpace - > GetPagePool ( ) . UnmapAllPagesForSpace ( System , Space - > GetID ( ) , VirtualAddress , WidthInTiles , HeightInTiles , MaxLevel ) ;
2019-09-17 20:33:19 -04:00
}
for ( int32 PageTableIndex = 0u ; PageTableIndex < UniquePageTableLayers . Num ( ) ; + + PageTableIndex )
{
UniquePageTableLayers [ PageTableIndex ] . PhysicalSpace . SafeRelease ( ) ;
2019-06-11 18:27:07 -04:00
}
2020-07-06 18:58:26 -04:00
2021-02-15 15:08:04 -04:00
# if DO_CHECK
2020-07-06 18:58:26 -04:00
for ( uint32 LayerIndex = 0 ; LayerIndex < Space - > GetNumPageTableLayers ( ) ; + + LayerIndex )
{
const FTexturePageMap & PageMap = Space - > GetPageMapForPageTableLayer ( LayerIndex ) ;
2021-02-15 15:08:04 -04:00
TArray < FMappedTexturePage > MappedPages ;
2021-03-25 14:24:11 -04:00
PageMap . GetMappedPagesInRange ( VirtualAddress , WidthInTiles , HeightInTiles , MappedPages ) ;
2021-02-15 15:08:04 -04:00
if ( MappedPages . Num ( ) > 0 )
{
TStringBuilder < 2048 > Message ;
2021-03-25 14:24:11 -04:00
Message . Appendf ( TEXT ( " Mapped pages remain after releasing AllocatedVT - vAddress: %d, Size: %d x %d, PhysicalSpaces: [ " ) , VirtualAddress , WidthInTiles , HeightInTiles ) ;
2021-02-15 15:08:04 -04:00
for ( FVirtualTexturePhysicalSpace * PhysicalSpace : UniquePhysicalSpaces )
{
Message . Appendf ( TEXT ( " %d " ) , PhysicalSpace - > GetID ( ) ) ;
}
Message . Appendf ( TEXT ( " ], MappedPages: [ " ) ) ;
for ( const FMappedTexturePage & MappedPage : MappedPages )
{
Message . Appendf ( TEXT ( " (vAddress: %d, PhysicalSpace: %d) " ) , MappedPage . Page . vAddress , MappedPage . PhysicalSpaceID ) ;
}
Message . Appendf ( TEXT ( " ] " ) ) ;
UE_LOG ( LogVirtualTexturing , Warning , TEXT ( " %s " ) , Message . ToString ( ) ) ;
}
2020-07-06 18:58:26 -04:00
}
2021-02-15 15:08:04 -04:00
# endif // DO_CHECK
2019-06-11 18:27:07 -04:00
}
Space - > FreeVirtualTexture ( this ) ;
System - > ReleaseSpace ( Space ) ;
}
2021-05-04 11:48:09 -04:00
void FAllocatedVirtualTexture : : LockOrUnlockTiles ( FVirtualTextureSystem * InSystem , bool bLock ) const
{
// (Un)Lock lowest resolution mip from each producer
// Depending on the block dimensions of the producers that make up this allocated VT, different allocated VTs may need to lock different low resolution mips from the same producer
// In the common case where block dimensions match, same mip will be locked by all allocated VTs that make use of the same producer
for ( int32 ProducerIndex = 0u ; ProducerIndex < UniqueProducers . Num ( ) ; + + ProducerIndex )
{
FVirtualTextureProducerHandle ProducerHandle = UniqueProducers [ ProducerIndex ] . Handle ;
FVirtualTextureProducer * Producer = InSystem - > FindProducer ( ProducerHandle ) ;
if ( Producer & & Producer - > GetDescription ( ) . bPersistentHighestMip )
{
const uint32 MipBias = UniqueProducers [ ProducerIndex ] . MipBias ;
check ( MipBias < = MaxLevel ) ;
const uint32 Local_vLevel = MaxLevel - MipBias ;
checkf ( Local_vLevel < = Producer - > GetMaxLevel ( ) , TEXT ( " Invalid Local_vLevel %d for VT producer %s, Producer MaxLevel %d, MipBias %d, AllocatedVT MaxLevel %d " ) ,
Local_vLevel ,
* Producer - > GetName ( ) . ToString ( ) ,
Producer - > GetMaxLevel ( ) ,
MipBias ,
MaxLevel ) ;
const uint32 MipScaleFactor = ( 1u < < Local_vLevel ) ;
const uint32 RootWidthInTiles = FMath : : DivideAndRoundUp ( Producer - > GetWidthInTiles ( ) , MipScaleFactor ) ;
const uint32 RootHeightInTiles = FMath : : DivideAndRoundUp ( Producer - > GetHeightInTiles ( ) , MipScaleFactor ) ;
for ( uint32 TileY = 0u ; TileY < RootHeightInTiles ; + + TileY )
{
for ( uint32 TileX = 0u ; TileX < RootWidthInTiles ; + + TileX )
{
const uint32 Local_vAddress = FMath : : MortonCode2 ( TileX ) | ( FMath : : MortonCode2 ( TileY ) < < 1 ) ;
FVirtualTextureLocalTile Tile ( ProducerHandle , Local_vAddress , Local_vLevel ) ;
const uint32 LocalMipBias = Producer - > GetVirtualTexture ( ) - > GetLocalMipBias ( Local_vLevel , Local_vAddress ) ;
if ( LocalMipBias > 0u )
{
Tile . Local_vAddress > > = ( LocalMipBias * Description . Dimensions ) ;
Tile . Local_vLevel + = LocalMipBias ;
}
if ( bLock )
{
InSystem - > LockTile ( Tile ) ;
}
else
{
InSystem - > UnlockTile ( Tile , Producer ) ;
}
}
}
}
}
}
2021-05-12 21:59:47 -04:00
bool FAllocatedVirtualTexture : : TryMapLockedTiles ( FVirtualTextureSystem * InSystem ) const
{
bool bHasMissingTiles = false ;
for ( int32 PageTableLayerIndex = 0u ; PageTableLayerIndex < UniquePageTableLayers . Num ( ) ; + + PageTableLayerIndex )
{
const FPageTableLayerDesc & PageTableLayer = UniquePageTableLayers [ PageTableLayerIndex ] ;
const FProducerDesc & UniqueProducer = UniqueProducers [ PageTableLayer . UniqueProducerIndex ] ;
const FVirtualTextureProducer * Producer = InSystem - > FindProducer ( UniqueProducer . Handle ) ;
if ( ! Producer )
{
continue ;
}
const uint32 WidthInTiles = Producer - > GetWidthInTiles ( ) ;
const uint32 HeightInTiles = Producer - > GetHeightInTiles ( ) ;
const uint32 Local_vLevel = FMath : : Min ( Producer - > GetMaxLevel ( ) , MaxLevel - UniqueProducer . MipBias ) ;
const uint32 MipScaleFactor = ( 1u < < Local_vLevel ) ;
const uint32 RootWidthInTiles = FMath : : DivideAndRoundUp ( WidthInTiles , MipScaleFactor ) ;
const uint32 RootHeightInTiles = FMath : : DivideAndRoundUp ( HeightInTiles , MipScaleFactor ) ;
FTexturePagePool & PagePool = PageTableLayer . PhysicalSpace - > GetPagePool ( ) ;
FTexturePageMap & PageMap = Space - > GetPageMapForPageTableLayer ( PageTableLayerIndex ) ;
uint32 NumNonResidentPages = 0u ;
for ( uint32 TileY = 0u ; TileY < RootHeightInTiles ; + + TileY )
{
for ( uint32 TileX = 0u ; TileX < RootWidthInTiles ; + + TileX )
{
const uint32 vAddress = FMath : : MortonCode2 ( VirtualPageX + ( TileX < < MaxLevel ) ) | ( FMath : : MortonCode2 ( VirtualPageY + ( TileY < < MaxLevel ) ) < < 1 ) ;
uint32 pAddress = PageMap . FindPageAddress ( MaxLevel , vAddress ) ;
if ( pAddress = = ~ 0u )
{
uint32 Local_vAddress = FMath : : MortonCode2 ( TileX ) | ( FMath : : MortonCode2 ( TileY ) < < 1 ) ;
const uint32 LocalMipBias = Producer - > GetVirtualTexture ( ) - > GetLocalMipBias ( Local_vLevel , Local_vAddress ) ;
Local_vAddress > > = ( LocalMipBias * Description . Dimensions ) ;
pAddress = PagePool . FindPageAddress ( UniqueProducer . Handle , PageTableLayer . ProducerPhysicalGroupIndex , Local_vAddress , Local_vLevel + LocalMipBias ) ;
if ( pAddress ! = ~ 0u )
{
PagePool . MapPage ( Space , PageTableLayer . PhysicalSpace , PageTableLayerIndex , MaxLevel , MaxLevel , vAddress , MaxLevel + LocalMipBias , pAddress ) ;
}
else
{
bHasMissingTiles = true ;
2021-12-03 13:43:10 -05:00
// Mark page table entry as invalid if we can't map.
PageMap . InvalidateUnmappedRootPage ( Space , PageTableLayer . PhysicalSpace , PageTableLayerIndex , MaxLevel , MaxLevel , vAddress , MaxLevel + LocalMipBias ) ;
2021-05-12 21:59:47 -04:00
}
}
}
}
}
2021-12-03 13:07:58 -05:00
// Display a warning message if we've failed to map pages for this after a set number of frames
2021-05-12 21:59:47 -04:00
// Generally there should be no delay, but if the system is saturated, it's possible that locked pages may not be loaded immediately
2021-12-03 13:07:58 -05:00
if ( bHasMissingTiles & & InSystem - > GetFrame ( ) > FrameAllocated + 30u )
2021-05-12 21:59:47 -04:00
{
2021-12-03 13:07:58 -05:00
static const auto CVar = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.VT.Verbose " ) ) ;
if ( CVar - > GetValueOnRenderThread ( ) )
{
UE_LOG ( LogVirtualTexturing , Warning , TEXT ( " Failed to map lowest resolution mip for AllocatedVT %s (%d frames) " ) , * Description . Name . ToString ( ) , InSystem - > GetFrame ( ) - FrameAllocated ) ;
}
2021-05-12 21:59:47 -04:00
}
return ! bHasMissingTiles ;
}
2021-12-03 01:10:59 -05:00
uint32 FAllocatedVirtualTexture : : CalculatePersistentHash ( FAllocatedVTDescription const & InDesc , FVirtualTextureProducer * const * InProducers ) const
{
uint32 Hash = 0 ;
for ( uint32 LayerIndex = 0u ; LayerIndex < InDesc . NumTextureLayers ; + + LayerIndex )
{
FVirtualTextureProducer const * Producer = InProducers [ LayerIndex ] ;
if ( Producer ! = nullptr )
{
Hash = HashCombine ( Hash , LayerIndex ) ;
Hash = HashCombine ( Hash , Producer - > GetDescription ( ) . FullNameHash ) ;
}
}
Hash = HashCombine ( Hash , GetTypeHash ( InDesc . TileSize ) ) ;
Hash = HashCombine ( Hash , GetTypeHash ( InDesc . TileBorderSize ) ) ;
Hash = HashCombine ( Hash , GetTypeHash ( InDesc . Dimensions ) ) ;
Hash = HashCombine ( Hash , GetTypeHash ( InDesc . NumTextureLayers ) ) ;
Hash = HashCombine ( Hash , GetTypeHash ( InDesc . PackedFlags ) ) ;
return Hash ;
}
2019-10-23 14:08:35 -04:00
uint32 FAllocatedVirtualTexture : : AddUniqueProducer ( FVirtualTextureProducerHandle const & InHandle , const FVirtualTextureProducer * InProducer )
2019-06-11 18:27:07 -04:00
{
2019-09-17 20:33:19 -04:00
for ( int32 Index = 0u ; Index < UniqueProducers . Num ( ) ; + + Index )
2019-06-11 18:27:07 -04:00
{
2019-09-17 20:33:19 -04:00
if ( UniqueProducers [ Index ] . Handle = = InHandle )
2019-06-11 18:27:07 -04:00
{
return Index ;
}
}
2019-09-17 20:33:19 -04:00
const uint32 Index = UniqueProducers . AddDefaulted ( ) ;
2019-06-11 18:27:07 -04:00
check ( Index < VIRTUALTEXTURE_SPACE_MAXLAYERS ) ;
2019-10-23 14:08:35 -04:00
uint32 MipBias = 0u ;
if ( InProducer )
{
const FVTProducerDescription & ProducerDesc = InProducer - > GetDescription ( ) ;
// maybe these values should just be set by producers, rather than also set on AllocatedVT desc
check ( ProducerDesc . Dimensions = = Description . Dimensions ) ;
check ( ProducerDesc . TileSize = = Description . TileSize ) ;
check ( ProducerDesc . TileBorderSize = = Description . TileBorderSize ) ;
2019-06-11 18:27:07 -04:00
2020-12-02 16:15:40 -04:00
const uint32 MipBiasX = FMath : : CeilLogTwo ( BlockWidthInTiles / ProducerDesc . BlockWidthInTiles ) ;
const uint32 MipBiasY = FMath : : CeilLogTwo ( BlockHeightInTiles / ProducerDesc . BlockHeightInTiles ) ;
check ( ProducerDesc . BlockWidthInTiles < < MipBiasX = = BlockWidthInTiles ) ;
check ( ProducerDesc . BlockHeightInTiles < < MipBiasY = = BlockHeightInTiles ) ;
2019-06-11 18:27:07 -04:00
2020-12-02 16:15:40 -04:00
// If the producer aspect ratio doesn't match the aspect ratio for the AllocatedVT, there's no way to choose a 100% mip bias
// By chossing the minimum of X/Y bias, we'll effectively crop this producer to match the aspect ratio of the AllocatedVT
// This case can happen as base materials will choose to group VTs together into a stack as long as all the textures assigned in the base material share the same aspect ratio
// But it's possible for a MI to overide some of thse textures such that the aspect ratios no longer match
// This will be fine for some cases, especially if the common case where the mismatched texture is a small dummy texture with a constant color
MipBias = FMath : : Min ( MipBiasX , MipBiasY ) ;
2019-06-11 18:27:07 -04:00
2019-10-23 14:08:35 -04:00
MaxLevel = FMath : : Max < uint32 > ( MaxLevel , ProducerDesc . MaxLevel + MipBias ) ;
}
2019-06-11 18:27:07 -04:00
2019-09-17 20:33:19 -04:00
UniqueProducers [ Index ] . Handle = InHandle ;
UniqueProducers [ Index ] . MipBias = MipBias ;
2019-06-11 18:27:07 -04:00
return Index ;
}
2019-09-17 20:33:19 -04:00
uint32 FAllocatedVirtualTexture : : AddUniquePhysicalSpace ( FVirtualTexturePhysicalSpace * InPhysicalSpace , uint32 InUniqueProducerIndex , uint32 InProducerPhysicalSpaceIndex )
{
2019-10-23 14:06:00 -04:00
if ( Description . bShareDuplicateLayers )
2019-09-17 20:33:19 -04:00
{
2019-10-23 14:06:00 -04:00
for ( int32 Index = 0u ; Index < UniquePageTableLayers . Num ( ) ; + + Index )
2019-09-17 20:33:19 -04:00
{
2019-10-23 14:06:00 -04:00
if ( UniquePageTableLayers [ Index ] . PhysicalSpace = = InPhysicalSpace & &
UniquePageTableLayers [ Index ] . UniqueProducerIndex = = InUniqueProducerIndex & &
UniquePageTableLayers [ Index ] . ProducerPhysicalGroupIndex = = InProducerPhysicalSpaceIndex )
{
return Index ;
}
2019-09-17 20:33:19 -04:00
}
}
const uint32 Index = UniquePageTableLayers . AddDefaulted ( ) ;
check ( Index < VIRTUALTEXTURE_SPACE_MAXLAYERS ) ;
UniquePageTableLayers [ Index ] . PhysicalSpace = InPhysicalSpace ;
UniquePageTableLayers [ Index ] . UniqueProducerIndex = InUniqueProducerIndex ;
UniquePageTableLayers [ Index ] . ProducerPhysicalGroupIndex = InProducerPhysicalSpaceIndex ;
UniquePageTableLayers [ Index ] . ProducerTextureLayerMask = 0 ;
UniquePageTableLayers [ Index ] . TextureLayerCount = 0 ;
return Index ;
}
2020-10-22 19:19:16 -04:00
uint32 FAllocatedVirtualTexture : : GetNumPageTableTextures ( ) const
{
return Space - > GetNumPageTableTextures ( ) ;
}
2019-06-11 18:27:07 -04:00
FRHITexture * FAllocatedVirtualTexture : : GetPageTableTexture ( uint32 InPageTableIndex ) const
{
return Space - > GetPageTableTexture ( InPageTableIndex ) ;
}
2020-10-22 19:19:16 -04:00
FRHITexture * FAllocatedVirtualTexture : : GetPageTableIndirectionTexture ( ) const
{
return Space - > GetPageTableIndirectionTexture ( ) ;
}
uint32 FAllocatedVirtualTexture : : GetPhysicalTextureSize ( uint32 InLayerIndex ) const
{
if ( InLayerIndex < Description . NumTextureLayers )
{
const FVirtualTexturePhysicalSpace * PhysicalSpace = UniquePageTableLayers [ TextureLayers [ InLayerIndex ] . UniquePageTableLayerIndex ] . PhysicalSpace ;
return PhysicalSpace ? PhysicalSpace - > GetTextureSize ( ) : 0u ;
}
return 0u ;
}
2019-06-11 18:27:07 -04:00
FRHITexture * FAllocatedVirtualTexture : : GetPhysicalTexture ( uint32 InLayerIndex ) const
{
2019-09-17 20:33:19 -04:00
if ( InLayerIndex < Description . NumTextureLayers )
2019-06-11 18:27:07 -04:00
{
2019-09-17 20:33:19 -04:00
const FVirtualTexturePhysicalSpace * PhysicalSpace = UniquePageTableLayers [ TextureLayers [ InLayerIndex ] . UniquePageTableLayerIndex ] . PhysicalSpace ;
return PhysicalSpace ? PhysicalSpace - > GetPhysicalTexture ( TextureLayers [ InLayerIndex ] . PhysicalTextureIndex ) : nullptr ;
2019-06-11 18:27:07 -04:00
}
return nullptr ;
}
2019-09-29 17:29:22 -04:00
FRHIShaderResourceView * FAllocatedVirtualTexture : : GetPhysicalTextureSRV ( uint32 InLayerIndex , bool bSRGB ) const
2019-06-11 18:27:07 -04:00
{
2019-09-17 20:33:19 -04:00
if ( InLayerIndex < Description . NumTextureLayers )
2019-06-11 18:27:07 -04:00
{
2019-09-17 20:33:19 -04:00
const FVirtualTexturePhysicalSpace * PhysicalSpace = UniquePageTableLayers [ TextureLayers [ InLayerIndex ] . UniquePageTableLayerIndex ] . PhysicalSpace ;
2019-09-29 17:29:22 -04:00
return PhysicalSpace ? PhysicalSpace - > GetPhysicalTextureSRV ( TextureLayers [ InLayerIndex ] . PhysicalTextureIndex , bSRGB ) : nullptr ;
2019-06-11 18:27:07 -04:00
}
return nullptr ;
}
static inline uint32 BitcastFloatToUInt32 ( float v )
{
const union
{
float FloatValue ;
uint32 UIntValue ;
} u = { v } ;
return u . UIntValue ;
}
2020-06-23 18:40:00 -04:00
void FAllocatedVirtualTexture : : GetPackedPageTableUniform ( FUintVector4 * OutUniform ) const
2019-06-11 18:27:07 -04:00
{
2021-04-05 21:56:26 -04:00
const uint32 vPageX = VirtualPageX ;
const uint32 vPageY = VirtualPageY ;
2019-06-11 18:27:07 -04:00
const uint32 vPageSize = GetVirtualTileSize ( ) ;
const uint32 PageBorderSize = GetTileBorderSize ( ) ;
const uint32 WidthInPages = GetWidthInTiles ( ) ;
const uint32 HeightInPages = GetHeightInTiles ( ) ;
const uint32 vPageTableMipBias = FMath : : FloorLog2 ( vPageSize ) ;
2022-02-02 01:49:39 -05:00
const uint32 AdaptiveLevelBias = Description . AdaptiveLevelBias ;
2019-06-11 18:27:07 -04:00
2021-04-02 14:08:28 -04:00
// Here MaxAnisotropy only controls the VT mip level selection
// We don't need to limit this value based on border size, and we can add this factor in even if HW anisotropic filtering is disabled
const uint32 MaxAnisotropy = VirtualTextureScalability : : GetMaxAnisotropy ( ) ;
2020-07-06 18:58:26 -04:00
const uint32 MaxAnisotropyLog2 = ( MaxAnisotropy > 0u ) ? FMath : : FloorLog2 ( MaxAnisotropy ) : 0u ;
2019-06-11 18:27:07 -04:00
// make sure everything fits in the allocated number of bits
checkSlow ( vPageX < 4096u ) ;
checkSlow ( vPageY < 4096u ) ;
checkSlow ( vPageTableMipBias < 16u ) ;
checkSlow ( MaxLevel < 16u ) ;
2020-10-22 19:19:16 -04:00
checkSlow ( AdaptiveLevelBias < 16u ) ;
2019-06-11 18:27:07 -04:00
checkSlow ( SpaceID < 16u ) ;
2020-06-23 18:40:00 -04:00
OutUniform [ 0 ] . X = BitcastFloatToUInt32 ( 1.0f / ( float ) WidthInBlocks ) ;
OutUniform [ 0 ] . Y = BitcastFloatToUInt32 ( 1.0f / ( float ) HeightInBlocks ) ;
2019-06-11 18:27:07 -04:00
OutUniform [ 0 ] . Z = BitcastFloatToUInt32 ( ( float ) WidthInPages ) ;
OutUniform [ 0 ] . W = BitcastFloatToUInt32 ( ( float ) HeightInPages ) ;
OutUniform [ 1 ] . X = BitcastFloatToUInt32 ( ( float ) MaxAnisotropyLog2 ) ;
OutUniform [ 1 ] . Y = vPageX | ( vPageY < < 12 ) | ( vPageTableMipBias < < 24 ) ;
2020-10-22 19:19:16 -04:00
OutUniform [ 1 ] . Z = MaxLevel | ( AdaptiveLevelBias < < 4 ) ;
2019-06-11 18:27:07 -04:00
OutUniform [ 1 ] . W = ( SpaceID < < 28 ) ;
}
void FAllocatedVirtualTexture : : GetPackedUniform ( FUintVector4 * OutUniform , uint32 LayerIndex ) const
{
const uint32 PhysicalTextureSize = GetPhysicalTextureSize ( LayerIndex ) ;
if ( PhysicalTextureSize > 0u )
{
const uint32 vPageSize = GetVirtualTileSize ( ) ;
const uint32 PageBorderSize = GetTileBorderSize ( ) ;
const float RcpPhysicalTextureSize = 1.0f / float ( PhysicalTextureSize ) ;
const uint32 pPageSize = vPageSize + PageBorderSize * 2u ;
2019-09-03 18:15:22 -04:00
2021-12-03 13:43:10 -05:00
OutUniform - > X = FallbackColorPerTextureLayer [ LayerIndex ] ;
2019-06-11 18:27:07 -04:00
OutUniform - > Y = BitcastFloatToUInt32 ( ( float ) vPageSize * RcpPhysicalTextureSize ) ;
OutUniform - > Z = BitcastFloatToUInt32 ( ( float ) PageBorderSize * RcpPhysicalTextureSize ) ;
2021-12-03 13:43:10 -05:00
// Pack page table format bool as sign bit on page size.
const bool bPageTableExtraBits = GetPageTableFormat ( ) = = EVTPageTableFormat : : UInt32 ;
const float PackedSignBit = bPageTableExtraBits ? 1.f : - 1.f ;
OutUniform - > W = BitcastFloatToUInt32 ( ( float ) pPageSize * RcpPhysicalTextureSize * PackedSignBit ) ;
2019-06-11 18:27:07 -04:00
}
else
{
OutUniform - > X = 0u ;
OutUniform - > Y = 0u ;
OutUniform - > Z = 0u ;
OutUniform - > W = 0u ;
}
}