Files
2025-05-18 13:04:45 +08:00

480 lines
14 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "JobArgs.h"
#include "Job.h"
#include "TextureGraphEngine.h"
#include "Model/Mix/MixSettings.h"
#include "Data/Blob.h"
#include "JobBatch.h"
#include "2D/TextureHelper.h"
#include "Device/FX/Device_FX.h"
#include "Device/FX/DeviceBuffer_FX.h"
#include "FxMat/RenderMaterial_FX.h"
#include "FxMat/RenderMaterial_FX_Combined.h"
#include "FxMat/RenderMaterial_BP.h"
#include "Engine/TextureRenderTarget2DArray.h"
#include "FxMat/RenderMaterial_FX_Combined.h"
#include "3D/RenderMesh.h"
#include "Data/Blobber.h"
DECLARE_CYCLE_STAT(TEXT("JobArg_Combined_Bind"), STAT_JobArg_Combined_Bind, STATGROUP_TextureGraphEngine);
DECLARE_CYCLE_STAT(TEXT("JobArg_Combined_UnBind"), STAT_JobArg_Combined_UnBind, STATGROUP_TextureGraphEngine);
DECLARE_CYCLE_STAT(TEXT("JobArg_Blob_Bind"), STAT_JobArg_Blob_Bind, STATGROUP_TextureGraphEngine);
DECLARE_CYCLE_STAT(TEXT("JobArg_Blob_UnBind"), STAT_JobArg_Blob_UnBind, STATGROUP_TextureGraphEngine);
DECLARE_CYCLE_STAT(TEXT("JobArg_Blob_Hash"), STAT_JobArg_Blob_Hash, STATGROUP_TextureGraphEngine);
JobArg_Blob::JobArg_Blob(TiledBlobPtr BlobObj, const ResourceBindInfo& BindInfo)
: JobArg_Resource(BindInfo)
, BlobObjRef(BlobObj)
{
check(BlobObjRef.get());
/// Also check whether it's in the Blobber or not
//auto CachedBlob = TextureGraphEngine::Blobber()->Find(BlobObj.GetHash()->Value());
//check(CachedBlob || BlobObj.IsKeepStrong());
#if DEBUG_BLOB_REF_KEEPING == 1
/// Check whether all the tiles are valid and available
//for (size_t RowId = 0; RowId < BlobObj->Rows(); RowId++)
//{
// for (size_t ColId = 0; ColId < BlobObj->Cols(); ColId++)
// {
// BlobRef Tile = BlobObj->Tile(RowId, ColId);
// check(!Tile.expired());
// }
//}
TextureGraphEngine::Blobber()->AddReferencedBlob((Blob*)BlobObjRef.get().get(), this);
#endif
}
JobArg_Blob::JobArg_Blob(TiledBlobPtr BlobObj, const char* TargetName) : JobArg_Blob(BlobObj, ResourceBindInfo({ FString(TargetName) }))
{
}
JobArg_Blob::~JobArg_Blob()
{
#if DEBUG_BLOB_REF_KEEPING == 1
TextureGraphEngine::Blobber()->RemoveReferencedBlob((Blob*)BlobObjRef.get().get(), this);
#endif
}
bool JobArg::CanHandleTiles() const
{
return true;
}
bool JobArg::ForceNonTiledTransform() const
{
return false;
}
void JobArg_Blob::SetHandleTiles(bool bInCanHandleTiles)
{
bCanHandleTiles = bInCanHandleTiles;
}
bool JobArg_Blob::CanHandleTiles() const
{
return bCanHandleTiles;
}
JobArg_Blob& JobArg_Blob::WithNotHandleTiles()
{
bCanHandleTiles = false;
return (*this);
}
void JobArg_Blob::SetForceNonTiledTransform(bool bInForceNonTiledTransform)
{
bForceNonTiledTransform = bInForceNonTiledTransform;
}
bool JobArg_Blob::ForceNonTiledTransform() const
{
return bForceNonTiledTransform;
}
JobArg_Blob& JobArg_Blob::WithDownsampled4To1()
{
bBindDownsampled4To1 = true;
return (*this);
}
bool JobArg_Blob::IsDownsampled4To1() const
{
return bBindDownsampled4To1;
}
JobArg_Blob& JobArg_Blob::WithNeighborTiles()
{
bBindNeighborTiles = true;
return (*this);
}
bool JobArg_Blob::IsNeighborTiles() const
{
return bBindNeighborTiles;
}
JobArg_Blob& JobArg_Blob::WithArrayOfTiles()
{
bBindArrayOfTiles = true;
return (*this);
}
bool JobArg_Blob::IsArrayOfTiles() const
{
return bBindArrayOfTiles;
}
//////////////////////////////////////////////////////////////////////////
TiledBlobPtr JobArg_Blob::GetRootBlob(JobArgBindInfo JobBindInfo) const
{
TiledBlobPtr RootBlob = BlobObjRef.get();
if (JobBindInfo.LODLevel != 0 && /// LOD is enabled in this cycle
!RootBlob->IsLODLevel() && /// Don't wanna LOD an existing LOD BlobObj
RootBlob->HasLODLevels() && /// Check whether it has LOD levels
RootBlob->HasLODLevel(JobBindInfo.LODLevel)) /// Ensure that it has a valid object in the LOD that we need
{
RootBlob = std::static_pointer_cast<TiledBlob>(RootBlob->GetLODLevel(JobBindInfo.LODLevel).lock());
check(RootBlob);
}
return RootBlob;
}
AsyncJobArgResultPtr JobArg_Blob::Bind(JobArgBindInfo JobBindInfo)
{
check(!bUnbound);
SCOPE_CYCLE_COUNTER(STAT_JobArg_Blob_Bind)
const Job* CurrentJob = JobBindInfo.JobObj;
check(CurrentJob);
BlobTransformPtr transform = JobBindInfo.Transform;
ResourceBindInfo BindInfo = ArgBindInfo;
BindInfo.Dev = JobBindInfo.Dev;
check(BindInfo.Dev);
TiledBlobPtr RootBlob = GetRootBlob(JobBindInfo);
if (IsDownsampled4To1())
{
return RootBlob->TransferTo(BindInfo.Dev)
.then([RootBlob, BindInfo, JobBindInfo](auto)
{
// Collect the individual tile textures from the root tiled BlobObj in an array
std::vector<TexPtr> TileTexObjs;
for (int RowId = 0; RowId < 2; RowId++)
{
for (int ColId = 0; ColId < 2; ColId++)
{
if (RootBlob->IsValidTileIndex(RowId + 2 * JobBindInfo.RowId, ColId + 2 * JobBindInfo.ColId))
{
auto Tile = RootBlob->GetTile(RowId + 2 * JobBindInfo.RowId, ColId + 2 * JobBindInfo.ColId);
auto TileBuffer = std::static_pointer_cast<DeviceBuffer_FX>(Tile->GetBufferRef().GetPtr());
TileTexObjs.push_back(TileBuffer->GetTexture());
}
else
{
auto Black = TextureHelper::GetBlack()->GetTile(0, 0);
auto BlackBuffer = std::static_pointer_cast<DeviceBuffer_FX> (Black->GetBufferRef().GetPtr());
TileTexObjs.push_back(BlackBuffer->GetTexture());
}
}
}
// True binding of the array of textures to the Material
const RenderMaterial* Material = static_cast<const RenderMaterial*>(JobBindInfo.Transform.get());
check(Material);
Material->SetArrayTexture(*BindInfo.Target, TileTexObjs);
return cti::make_ready_continuable(std::make_shared<JobArgResult>());
});
}
else if (IsNeighborTiles())
{
return RootBlob->TransferTo(BindInfo.Dev)
.then([RootBlob, BindInfo, JobBindInfo](auto)
{
// Collect the individual tile textures from the root tiled BlobObj in an array
std::vector<TexPtr> Textures;
auto MainRow = JobBindInfo.RowId;
auto MainCol = JobBindInfo.ColId;
auto GridRow = RootBlob->Rows();
auto GridCol = RootBlob->Cols();
for (int RowId = 0; RowId < 3; RowId++)
{
for (int ColId = 0; ColId < 3; ColId++)
{
// Compute the true tile index
auto InnerRowId = (MainRow - 1 + RowId);
auto InnerColId = (MainCol - 1 + ColId);
if (InnerRowId < 0)
InnerRowId = GridRow - 1;
if (InnerRowId >= GridRow)
InnerRowId = 0;
if (InnerColId < 0)
InnerColId = GridCol - 1;
if (InnerColId >= GridCol)
InnerColId = 0;
if (RootBlob->IsValidTileIndex(InnerRowId, InnerColId))
{
auto Tile = RootBlob->GetTile(InnerRowId, InnerColId);
auto TileBuffer = std::static_pointer_cast<DeviceBuffer_FX>(Tile->GetBufferRef().GetPtr());
Textures.push_back(TileBuffer->GetTexture());
}
else
{
auto Black = TextureHelper::GetBlack()->GetTile(0, 0);
auto BlackBuffer = std::static_pointer_cast<DeviceBuffer_FX> (Black->GetBufferRef().GetPtr());
Textures.push_back(BlackBuffer->GetTexture());
}
}
}
// True binding of the array of textures to the Material
const RenderMaterial* Material = static_cast<const RenderMaterial*>(JobBindInfo.Transform.get());
check(Material);
Material->SetArrayTexture(*BindInfo.Target, Textures);
return cti::make_ready_continuable(std::make_shared<JobArgResult>());
});
}
else if (IsArrayOfTiles())
{
return RootBlob->TransferTo(BindInfo.Dev)
.then([RootBlob, BindInfo, JobBindInfo](auto)
{
// Collect the individual tile textures from the root tiled BlobObj in an array
std::vector<TexPtr> Textures;
int NumX = RootBlob->Cols();
int NumY = RootBlob->Rows();
for (int Y = 0; Y < NumY; ++Y)
{
for (int X = 0; X < NumX; ++X)
{
if (RootBlob->IsValidTileIndex(X, Y))
{
auto Tile = RootBlob->GetTile(X, Y);
auto TileBuffer = std::static_pointer_cast<DeviceBuffer_FX>(Tile->GetBufferRef().GetPtr());
Textures.push_back(TileBuffer->GetTexture());
}
else
{
auto Black = TextureHelper::GetBlack()->GetTile(0, 0);
auto BlackBuffer = std::static_pointer_cast<DeviceBuffer_FX> (Black->GetBufferRef().GetPtr());
Textures.push_back(BlackBuffer->GetTexture());
}
}
}
// True binding of the array of textures to the Material
const RenderMaterial* Material = static_cast<const RenderMaterial*>(JobBindInfo.Transform.get());
check(Material);
Material->SetArrayTexture(*BindInfo.Target, Textures);
return cti::make_ready_continuable(std::make_shared<JobArgResult>());
});
}
else
{
BlobPtr BlobToBind = RootBlob;
check(BlobToBind);
bool bArgCanHandleTiles = CanHandleTiles();
if (bArgCanHandleTiles && transform->CanHandleTiles() && JobBindInfo.RowId >= 0 && JobBindInfo.ColId >= 0)
BlobToBind = BlobObjRef.get()->GetTile(JobBindInfo.RowId, JobBindInfo.ColId).lock();
FString TransformName = CurrentJob->GetTransform()->GetName();
//UE_LOG(LogJob, Log, TEXT("[%s] Binding BlobObj arg: %s => %s [Tile: %s]"), *transformName, *BlobObj->Name(), *BindInfo.TargetName, *blobToBind->Name());
BindInfo.bIsCombined = !bArgCanHandleTiles;
return BlobToBind->Bind(transform.get(), BindInfo)
.then([this]() mutable
{
return std::make_shared<JobArgResult>();
});
}
}
AsyncJobArgResultPtr JobArg_Blob::Unbind(JobArgBindInfo JobBindInfo)
{
check(!bUnbound);
SCOPE_CYCLE_COUNTER(STAT_JobArg_Blob_UnBind)
if (BlobObjRef.expired()) // No references remain , this cause may arise if BlobObj is cleared through sharedPtrs before unbind
return cti::make_ready_continuable(std::make_shared<JobArgResult>());
if (IsDownsampled4To1())
{
// IN this case the arg is only used to read from, nothing to do to unbind
return cti::make_ready_continuable(std::make_shared<JobArgResult>());
}
else if (IsNeighborTiles())
{
// IN this case the arg is only used to read from, nothing to do to unbind
return cti::make_ready_continuable(std::make_shared<JobArgResult>());
}
else
{
check(JobBindInfo.JobObj);
BlobTransformPtr transform = JobBindInfo.Transform;
BlobPtr blobToBind = GetRootBlob(JobBindInfo);
bool bCanArgHandleTiles = CanHandleTiles();
if (bCanArgHandleTiles && transform->CanHandleTiles() && JobBindInfo.RowId >= 0 && JobBindInfo.ColId >= 0)
{
blobToBind = BlobObjRef.get()->GetTile(JobBindInfo.RowId, JobBindInfo.ColId).lock();
}
ArgBindInfo.BatchId = JobBindInfo.Batch->GetBatchId();
ArgBindInfo.bIsCombined = !bCanArgHandleTiles;
return blobToBind->Unbind(transform.get(), ArgBindInfo)
.then([=]() mutable
{
return std::make_shared<JobArgResult>();
});
}
}
bool JobArg_Blob::IsLateBound(uint32 RowId, uint32 ColId) const
{
TiledBlobPtr BlobObj = BlobObjRef.get();
BlobRef TileXY = BlobObj->GetTile(RowId, ColId);
/// If the tile isn't even there then it's definitely late bound
if (TileXY.IsNull())
return true;
BlobPtr TileXYPtr = TileXY.lock();
return BlobObj->IsLateBound() || !TileXYPtr || TileXYPtr->IsNull() || TileXYPtr->IsLateBound();
}
const BufferDescriptor* JobArg_Blob::GetDescriptor() const
{
return BlobObjRef ? &BlobObjRef->GetDescriptor() : nullptr;
}
CHashPtr JobArg_Blob::TileHash(uint32 RowId, uint32 ColId) const
{
TiledBlobPtr BlobObj = BlobObjRef.get();
return BlobObj->GetTile(RowId, ColId)->Hash();
}
CHashPtr JobArg_Blob::Hash() const
{
SCOPE_CYCLE_COUNTER(STAT_JobArg_Blob_Hash);
check(BlobObjRef.get());
return BlobObjRef.GetHash();
}
JobPtrW JobArg_Blob::GeneratingJob() const
{
return BlobObjRef.get() ? BlobObjRef.get()->Job() : JobPtrW();
}
//////////////////////////////////////////////////////////////////////////
AsyncJobArgResultPtr JobArg_Mesh::Bind(JobArgBindInfo JobBindInfo)
{
JobBindInfo.JobObj->SetMesh(Mesh.get());
return cti::make_ready_continuable(std::make_shared<JobArgResult>());
}
AsyncJobArgResultPtr JobArg_Mesh::Unbind(JobArgBindInfo JobBindInfo)
{
return cti::make_ready_continuable(std::make_shared<JobArgResult>());
}
CHashPtr JobArg_Mesh::Hash() const
{
return Mesh->Hash();
}
CHashPtr JobArg_Mesh::TileHash(uint32 RowId, uint32 ColId) const
{
return Mesh->Hash();
}
//////////////////////////////////////////////////////////////////////////
AsyncJobArgResultPtr JobArg_TileInfo::Bind(JobArgBindInfo JobBindInfo)
{
const Job* JobObj = JobBindInfo.JobObj;
check(JobObj);
BlobTransformPtr Transform = JobBindInfo.Transform;
TiledBlobPtr Result = JobObj->GetResult();
float TileWidth = Result->GetWidth() / Result->Cols();
float TileHeight = Result->GetHeight() / Result->Rows();
Value.TileX = JobBindInfo.ColId;
Value.TileCountX = Result->Cols();
Value.TileWidth = TileWidth;
Value.TileY = JobBindInfo.RowId;
Value.TileCountY = Result->Rows();
Value.TileHeight = TileHeight;
Transform->BindStruct<FTileInfo>(Value, ArgBindInfo);
return cti::make_ready_continuable(std::make_shared<JobArgResult>());
}
AsyncJobArgResultPtr JobArg_TileInfo::Unbind(JobArgBindInfo JobBindInfo)
{
return cti::make_ready_continuable(std::make_shared<JobArgResult>());
}
CHashPtr JobArg_TileInfo::Hash() const
{
if (!HashValue)
HashValue = TileHash(-1, -1);
return HashValue;
}
CHashPtr JobArg_TileInfo::TileHash(uint32 RowId, uint32 ColId) const
{
HashTypeVec StructHash =
{
MX_HASH_VAL_DEF(RowId),
MX_HASH_VAL_DEF(Value.TileCountX),
MX_HASH_VAL_DEF(Value.TileWidth),
MX_HASH_VAL_DEF(ColId),
MX_HASH_VAL_DEF(Value.TileCountY),
MX_HASH_VAL_DEF(Value.TileHeight),
MX_HASH_VAL_DEF(sizeof(Value)),
};
return std::make_shared<CHash>(DataUtil::Hash(StructHash), true);
}
//////////////////////////////////////////////////////////////////////////
CHashPtr JobArg_ForceTiling::Hash() const
{
return TileHash(-1, -1);
}
CHashPtr JobArg_ForceTiling::TileHash(uint32 RowId, uint32 ColId) const
{
HashTypeVec StructHash =
{
MX_HASH_VAL_DEF(RowId),
MX_HASH_VAL_DEF(ColId),
};
return std::make_shared<CHash>(DataUtil::Hash(StructHash), true);
}