Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSystem.h
2025-05-18 13:04:45 +08:00

309 lines
13 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#if !UE_BUILD_SHIPPING
#include "Misc/CoreDelegates.h"
#endif
#include "RHI.h"
#include "RendererInterface.h"
#include "Templates/UniquePtr.h"
#include "VT/VirtualTextureProducer.h"
#include "VT/TexturePageLocks.h"
#include "VirtualTexturing.h"
#include "VT/VirtualTextureFeedback.h"
#include "Tasks/Task.h"
#include "Async/RecursiveMutex.h"
class FAdaptiveVirtualTexture;
class FAllocatedVirtualTexture;
class FScene;
class FUniquePageList;
class FUniqueRequestList;
class FVirtualTexturePhysicalSpace;
class FVirtualTextureProducer;
class FVirtualTextureSpace;
class FVirtualTextureSystem;
struct FVTSpaceDescription;
struct FVTPhysicalSpaceDescription;
union FPhysicalSpaceIDAndAddress;
struct FFeedbackAnalysisParameters;
struct FAddRequestedTilesParameters;
struct FGatherRequestsParameters;
struct FPageUpdateBuffer;
class ISceneRenderer;
struct FVirtualTextureUpdateSettings
{
FVirtualTextureUpdateSettings();
/** Force settings so that throttling page uploads is effectively disabled. */
FVirtualTextureUpdateSettings& EnableThrottling(bool bEnable)
{
if (!bEnable)
{
MaxRVTPageUploads = 99999;
MaxSVTPageUploads = 99999;
MaxPagesProduced = 99999;
}
return *this;
}
/** Force virtual texture updates to be done synchronously. */
FVirtualTextureUpdateSettings& EnableAsyncTasks(bool bEnable = true)
{
bEnableAsyncTasks = bEnable;
return *this;
}
/** Do not perform any updates related to read backs. */
FVirtualTextureUpdateSettings& EnablePageRequests(bool bEnable = true)
{
bEnablePageRequests = bEnable;
return *this;
}
bool bEnableAsyncTasks = true;
bool bEnablePageRequests = true;
bool bEnableFeedback;
bool bEnableFeedbackProduce;
bool bEnablePlayback;
bool bForceContinuousUpdate;
bool bParallelFeedbackTasks;
int32 NumFeedbackTasks;
int32 NumGatherTasks;
int32 MaxGatherPagesBeforeFlush;
int32 MaxRVTPageUploads;
int32 MaxSVTPageUploads;
int32 MaxPagesProduced;
int32 MaxContinuousUpdates;
};
class FVirtualTextureUpdater
{
public:
UE::Tasks::FTask GetTask() const
{
return AsyncTask;
}
private:
FVirtualTextureUpdateSettings Settings;
FConcurrentLinearBulkObjectAllocator Allocator;
FUniqueRequestList* MergedRequestList = nullptr;
FVirtualTextureFeedback::FMapResult FeedbackMapResult;
UE::Tasks::FTask AsyncTask;
ERHIFeatureLevel::Type FeatureLevel = ERHIFeatureLevel::Num;
bool bAsyncTaskAllowed = false;
int32 PageUploadBudgetRVT = 0;
int32 PageUploadBudgetSVT = 0;
friend FVirtualTextureSystem;
};
class FVirtualTextureSystem
{
public:
static void Initialize();
static void Shutdown();
static FVirtualTextureSystem& Get();
uint32 GetFrame() const { return Frame; }
void Update(FRDGBuilder& GraphBuilder, ERHIFeatureLevel::Type FeatureLevel, ISceneRenderer* SceneRenderer, const FVirtualTextureUpdateSettings& Settings);
// Called in FSceneRenderer::UpdateScene, before FVirtualTextureSystem::BeginUpdate -- see comments there for more info
void CallPendingCallbacks();
TUniquePtr<FVirtualTextureUpdater> BeginUpdate(FRDGBuilder& GraphBuilder, ERHIFeatureLevel::Type FeatureLevel, ISceneRenderer* SceneRenderer, const FVirtualTextureUpdateSettings& Settings);
void WaitForTasks(FVirtualTextureUpdater* Updater);
void EndUpdate(FRDGBuilder& GraphBuilder, TUniquePtr<FVirtualTextureUpdater>&& Updater, ERHIFeatureLevel::Type FeatureLevel);
void FinalizeRequests(FRDGBuilder& GraphBuilder, ISceneRenderer* SceneRenderer);
void ReleasePendingResources();
IAllocatedVirtualTexture* AllocateVirtualTexture(FRHICommandListBase& RHICmdList, const FAllocatedVTDescription& Desc);
void DestroyVirtualTexture(IAllocatedVirtualTexture* AllocatedVT);
FVirtualTextureProducerHandle RegisterProducer(FRHICommandListBase& RHICmdList, const FVTProducerDescription& InDesc, IVirtualTexture* InProducer);
void ReleaseProducer(const FVirtualTextureProducerHandle& Handle);
bool TryReleaseProducer(const FVirtualTextureProducerHandle& Handle);
void AddProducerDestroyedCallback(const FVirtualTextureProducerHandle& Handle, FVTProducerDestroyedFunction* Function, void* Baton);
uint32 RemoveAllProducerDestroyedCallbacks(const void* Baton);
IAdaptiveVirtualTexture* AllocateAdaptiveVirtualTexture(FRHICommandListBase& RHICmdList, const FAdaptiveVTDescription& AdaptiveVTDesc, const FAllocatedVTDescription& AllocatedVTDesc);
void DestroyAdaptiveVirtualTexture(IAdaptiveVirtualTexture* AdaptiveVT);
void RequestTiles(const FVector2D& InScreenSpaceSize, int32 InMipLevel = -1);
void RequestTiles(const FMaterialRenderProxy* InMaterialRenderProxy, const FVector2D& InScreenSpaceSize, ERHIFeatureLevel::Type InFeatureLevel);
/**
* Helper function to request loading of tiles for a virtual texture that will be displayed in the UI.
* It will request only the tiles that will be visible after clipping to the provided viewport.
* @param AllocatedVT The virtual texture.
* @param InScreenSpaceSize Size on screen at which the texture is to be displayed.
* @param InViewportPosition Position in the viewport where the texture will be displayed.
* @param InViewportSize Size of the viewport.
* @param InUV0 UV coordinate to use for the top left corner of the texture.
* @param InUV1 UV coordinate to use for the bottom right corner of the texture.
* @param InMipLevel [optional] Specific mip level to fetch tiles for.
*/
void RequestTiles(IAllocatedVirtualTexture* AllocatedVT, const FVector2D& InScreenSpaceSize, const FVector2D& InViewportPosition, const FVector2D& InViewportSize, const FVector2D& InUV0, const FVector2D& InUV1, int32 InMipLevel = -1);
UE_DEPRECATED(5.4, "Use RequestTiles() overloads that takes similar parameters. Make sure not to negate the InViewportPosition.")
void RequestTilesForRegion(IAllocatedVirtualTexture* AllocatedVT, const FVector2D& InScreenSpaceSize, const FVector2D& InViewportPosition, const FVector2D& InViewportSize, const FVector2D& InUV0, const FVector2D& InUV1, int32 InMipLevel = -1);
void LoadPendingTiles(FRDGBuilder& GraphBuilder, ERHIFeatureLevel::Type FeatureLevel);
void SetMipLevelToLock(FVirtualTextureProducerHandle ProducerHandle, int32 InMipLevel);
#if WITH_EDITOR
void SetVirtualTextureRequestRecordBuffer(uint64 Handle);
uint64 GetVirtualTextureRequestRecordBuffer(TSet<uint64>& OutPageRequests);
#endif
void RequestRecordedTiles(TArray<uint64>&& InPageRequests);
void FlushCache();
void FlushCache(FVirtualTextureProducerHandle const& ProducerHandle, int32 SpaceID, FIntRect const& TextureRegion, uint32 MaxLevelToEvict, uint32 MaxAgeToKeepMapped, EVTInvalidatePriority InvalidatePriority);
FVector4f GetGlobalMipBias() const;
bool IsPendingRootPageMap(IAllocatedVirtualTexture* AllocatedVT) const;
private:
friend class FFeedbackAnalysisTask;
friend class FAddRequestedTilesTask;
friend class FGatherRequestsTask;
friend class FAllocatedVirtualTexture;
friend class FAdaptiveVirtualTexture;
friend class FVirtualTextureProducer;
friend class FVirtualTextureProducerCollection;
friend class FTexturePageMap;
friend class FTexturePagePool;
FVirtualTextureSystem();
~FVirtualTextureSystem();
FVirtualTextureSpace* AcquireSpace(FRHICommandListBase& RHICmdList, const FVTSpaceDescription& InDesc, uint8 InForceSpaceID, FAllocatedVirtualTexture* AllocatedVT);
void ReleaseSpace(FVirtualTextureSpace* Space);
FVirtualTextureProducer* FindProducer(const FVirtualTextureProducerHandle& Handle);
FVirtualTexturePhysicalSpace* AcquirePhysicalSpace(FRHICommandListBase& RHICmdList, const FVTPhysicalSpaceDescription& InDesc);
FVirtualTextureSpace* GetSpace(uint8 ID) const { check(ID < MaxSpaces); return Spaces[ID].Get(); }
FAdaptiveVirtualTexture* GetAdaptiveVirtualTexture(uint8 ID) const { check(ID < MaxSpaces); return AdaptiveVTs[ID]; }
FVirtualTexturePhysicalSpace* GetPhysicalSpace(uint16 ID) const { check(PhysicalSpaces[ID]); return PhysicalSpaces[ID]; }
void LockTile(const FVirtualTextureLocalTile& Tile);
void UnlockTile(const FVirtualTextureLocalTile& Tile, const FVirtualTextureProducer* Producer);
void ForceUnlockAllTiles(const FVirtualTextureProducerHandle& ProducerHandle, const FVirtualTextureProducer* Producer);
void BeginUpdate(FRDGBuilder& GraphBuilder, FVirtualTextureUpdater* Updater);
void AllocateResources(FRDGBuilder& GraphBuilder);
void DestroyPendingVirtualTextures(bool bForceDestroyAll);
void ReleasePendingSpaces();
void RequestTilesForRegionInternal(const IAllocatedVirtualTexture* AllocatedVT, const FVector2D& InScreenSpaceSize, const FVector2D& InViewportPosition, const FVector2D& InViewportSize, const FVector2D& InUV0, const FVector2D& InUV1, int32 InMipLevel);
void RequestTilesInternal(const IAllocatedVirtualTexture* AllocatedVT, int32 InMipLevel);
void RequestTilesInternal(const IAllocatedVirtualTexture* AllocatedVT, const FVector2D& InScreenSpaceSize, int32 InMipLevel);
int32 SubmitRequestsFromLocalTileRequests(FConcurrentLinearBulkObjectAllocator& Allocator, FRHICommandList& RHICmdList, TSet<FVirtualTextureLocalTileRequest>& OutDeferredTileRequests, const TSet<FVirtualTextureLocalTileRequest>& LocalTileRequests, EVTProducePageFlags Flags, ERHIFeatureLevel::Type FeatureLevel, uint32 MaxRequestsToProduce);
TArrayView<FVTLocalTilePriorityAndIndex> SortLocalTileRequests(FConcurrentLinearBulkObjectAllocator& Allocator, const TConstArrayView<FVirtualTextureLocalTileRequest>& InLocalTileRequests);
void GatherFeedbackRequests(FConcurrentLinearBulkObjectAllocator& Allocator, const FVirtualTextureUpdateSettings& Settings, const FVirtualTextureFeedback::FMapResult& FeedbackResult, FUniqueRequestList* MergedRequestList);
void GatherLockedTileRequests(FUniqueRequestList* MergedRequestList);
void GatherPackedTileRequests(FConcurrentLinearBulkObjectAllocator& Allocator, const FVirtualTextureUpdateSettings& Settings, FUniqueRequestList* MergedRequestList);
enum class EUpdatePhase
{
Begin,
End
};
void SubmitThrottledRequests(FRHICommandList& RHICmdList, FVirtualTextureUpdater* Updater, EUpdatePhase UpdatePhase);
void SubmitRequests(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, FConcurrentLinearBulkObjectAllocator& Allocator, FVirtualTextureUpdateSettings const& Settings, FUniqueRequestList* RequestList, bool bAsync);
void GatherRequests(FUniqueRequestList* MergedRequestList, const FUniquePageList* UniquePageList, uint32 FrameRequested, FConcurrentLinearBulkObjectAllocator& Allocator, FVirtualTextureUpdateSettings const& Settings);
void AddPageUpdate(FPageUpdateBuffer* Buffers, uint32 FlushCount, uint32 PhysicalSpaceID, uint16 pAddress);
void FeedbackAnalysisTask(const FFeedbackAnalysisParameters& Parameters);
void AddRequestedTilesTask(const FAddRequestedTilesParameters& Parameters);
void GatherRequestsTask(const FGatherRequestsParameters& Parameters);
void GetContinuousUpdatesToProduce(FUniqueRequestList const* RequestList, int32 MaxTilesToProduce, int32 MaxContinuousUpdates);
void UpdateResidencyTracking() const;
void GrowPhysicalPools() const;
#if WITH_EDITOR
void RecordPageRequests(FUniquePageList const* UniquePageList, TSet<uint64>& OutPages);
#endif
uint32 Frame;
mutable UE::FRecursiveMutex Mutex;
static const uint32 MaxNumTasks = 16;
static const uint32 MaxSpaces = 16;
uint32 NumAllocatedSpaces = 0;
TUniquePtr<FVirtualTextureSpace> Spaces[MaxSpaces];
TArray<FVirtualTexturePhysicalSpace*> PhysicalSpaces;
FVirtualTextureProducerCollection Producers;
TArray<IAllocatedVirtualTexture*> PendingDeleteAllocatedVTs;
TMap<FAllocatedVTDescription, FAllocatedVirtualTexture*> AllocatedVTs;
TArray<IAllocatedVirtualTexture*> AllocatedVTsToMap;
TMap<uint32, IAllocatedVirtualTexture*> PersistentVTMap;
FAdaptiveVirtualTexture* AdaptiveVTs[MaxSpaces] = { nullptr };
bool bUpdating = false;
bool bFlushCaches;
void FlushCachesFromConsole();
FAutoConsoleCommand FlushCachesCommand;
void DumpFromConsole();
FAutoConsoleCommand DumpCommand;
void ListPhysicalPoolsFromConsole();
FAutoConsoleCommand ListPhysicalPools;
void DumpPoolUsageFromConsole();
FAutoConsoleCommand DumpPoolUsageCommand;
#if WITH_EDITOR
void SaveAllocatorImagesFromConsole();
FAutoConsoleCommand SaveAllocatorImages;
#endif
TArray<uint32> RequestedPackedTiles;
TArray<FVirtualTextureLocalTile> TilesToLock;
TArray<FVirtualTextureLocalTile> TilesToLockForNextFrame;
FTexturePageLocks TileLocks;
TSet<FVirtualTextureLocalTileRequest> ContinuousUpdateTilesToProduce;
TSet<FVirtualTextureLocalTileRequest> MappedTilesToProduce;
TSet<FVirtualTextureLocalTileRequest> TransientCollectedTilesToProduce;
TArray<IVirtualTextureFinalizer*> Finalizers;
#if WITH_EDITOR
uint64 PageRequestRecordHandle;
TSet<uint64> PageRequestRecordBuffer;
#endif
TArray<uint64> PageRequestPlaybackBuffer;
#if !UE_BUILD_SHIPPING
void GetOnScreenMessages(FCoreDelegates::FSeverityMessageMap& OutMessages);
FDelegateHandle OnScreenMessageDelegateHandle;
void DrawResidencyHud(class UCanvas*, class APlayerController*);
FDelegateHandle DrawResidencyHudDelegateHandle;
void UpdateCsvStats();
#endif
};