Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/VT/RuntimeVirtualTextureSceneProxy.cpp
jeremy moore 69e2d4e901 Don't allocate the runtime virtual texture in the proxy if the asset is disabled
#ROBOMERGE-SOURCE: CL 8030248 via CL 8041686
#ROBOMERGE-BOT: (v400-8057353)

[CL 8062582 by jeremy moore in Main branch]
2019-08-15 13:51:44 -04:00

120 lines
4.5 KiB
C++

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "VT/RuntimeVirtualTextureSceneProxy.h"
#include "Components/RuntimeVirtualTextureComponent.h"
#include "VirtualTextureSystem.h"
#include "VT/RuntimeVirtualTexture.h"
#include "VT/RuntimeVirtualTextureProducer.h"
int32 FRuntimeVirtualTextureSceneProxy::ProducerIdGenerator = 1;
FRuntimeVirtualTextureSceneProxy::FRuntimeVirtualTextureSceneProxy(URuntimeVirtualTextureComponent* InComponent)
: SceneIndex(0)
, ProducerId(0)
, VirtualTexture(nullptr)
, CombinedDirtyRect(0, 0, 0, 0)
{
if (InComponent->GetVirtualTexture() != nullptr && InComponent->GetVirtualTexture()->GetEnabled())
{
VirtualTexture = InComponent->GetVirtualTexture();
// We store a ProducerId here so that we will be able to find our SceneIndex from the Producer during rendering.
// We will need the SceneIndex to determine which primitives should render to this Producer.
ProducerId = ProducerIdGenerator++;
const ERuntimeVirtualTextureMaterialType MaterialType = VirtualTexture->GetMaterialType();
// Transform is based on bottom left of the URuntimeVirtualTextureComponent unit box (which is centered on the origin)
Transform = FTransform(FVector(-0.5f, -0.5f, 0.f)) * InComponent->GetComponentTransform();
// The producer description is calculated using the transform to determine the aspect ratio
FVTProducerDescription Desc;
VirtualTexture->GetProducerDescription(Desc, Transform);
VirtualTextureSize = FIntPoint(Desc.WidthInBlocks * Desc.BlockWidthInTiles * Desc.TileSize, Desc.HeightInBlocks * Desc.BlockHeightInTiles * Desc.TileSize);
// The Producer object created here will be passed into the virtual texture system which will take ownership.
// The Initialize() call will allocate the virtual texture by spawning work on the render thread.
FRuntimeVirtualTextureProducer* Producer = new FRuntimeVirtualTextureProducer(Desc, ProducerId, MaterialType, InComponent->GetScene(), Transform);
VirtualTexture->Initialize(Producer, Transform);
}
}
FRuntimeVirtualTextureSceneProxy::~FRuntimeVirtualTextureSceneProxy()
{
checkSlow(IsInRenderingThread());
}
void FRuntimeVirtualTextureSceneProxy::Release()
{
if (VirtualTexture != nullptr)
{
VirtualTexture->Release();
VirtualTexture = nullptr;
}
}
void FRuntimeVirtualTextureSceneProxy::Dirty(FBoxSphereBounds const& Bounds)
{
// Transform world bounds into Virtual Texture UV space
const FVector O = Transform.GetTranslation();
const FVector U = Transform.GetUnitAxis(EAxis::X) * 1.f / Transform.GetScale3D().X;
const FVector V = Transform.GetUnitAxis(EAxis::Y) * 1.f / Transform.GetScale3D().Y;
const FVector P = Bounds.GetSphere().Center - O;
const FVector2D UVCenter = FVector2D(FVector::DotProduct(P, U), FVector::DotProduct(P, V));
const float Scale = FMath::Max(1.f / Transform.GetScale3D().X, 1.f / Transform.GetScale3D().Y);
const float UVRadius = Bounds.GetSphere().W * Scale;
const FVector2D UVExtent(UVRadius, UVRadius);
const FBox2D UVRect = FBox2D(UVCenter - UVExtent, UVCenter + UVExtent);
// Convert to Texel coordinate space
const FIntRect TextureRect(0, 0, VirtualTextureSize.X, VirtualTextureSize.Y);
FIntRect TexelRect(
FMath::FloorToInt(UVRect.Min.X * VirtualTextureSize.X),
FMath::FloorToInt(UVRect.Min.Y * VirtualTextureSize.Y),
FMath::CeilToInt(UVRect.Max.X * VirtualTextureSize.X),
FMath::CeilToInt(UVRect.Max.Y * VirtualTextureSize.Y));
TexelRect.Clip(TextureRect);
// Only add rect if it has some area
if (TexelRect.Min != TexelRect.Max)
{
const bool bFirst = DirtyRects.Add(TexelRect) == 0;
if (bFirst)
{
CombinedDirtyRect = TexelRect;
}
else
{
CombinedDirtyRect.Union(TexelRect);
}
}
}
void FRuntimeVirtualTextureSceneProxy::FlushDirtyPages()
{
// If Producer handle is not initialized yet it's safe to do nothing because we won't have rendered anything to the VT that needs flushing.
if (ProducerHandle.PackedValue != 0)
{
//todo[vt]:
// Profile to work out best heuristic for when we should use the CombinedDirtyRect
// Also consider using some other structure to represent dirty area such as a course 2D bitfield
const bool bCombinedFlush = (DirtyRects.Num() > 2 || CombinedDirtyRect == FIntRect(0, 0, VirtualTextureSize.X, VirtualTextureSize.Y));
if (bCombinedFlush)
{
FVirtualTextureSystem::Get().FlushCache(ProducerHandle, CombinedDirtyRect);
}
else
{
for (FIntRect Rect : DirtyRects)
{
FVirtualTextureSystem::Get().FlushCache(ProducerHandle, Rect);
}
}
}
DirtyRects.Reset();
CombinedDirtyRect = FIntRect(0, 0, 0, 0);
}