Files
UnrealEngine/Engine/Plugins/TextureGraph/Source/TextureGraphInsight/Private/Model/TextureGraphInsightSession.cpp
2025-05-18 13:04:45 +08:00

925 lines
25 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Model/TextureGraphInsightSession.h"
#include "Job/Job.h"
#include "Data/Blob.h"
#include "TextureGraphEngine.h"
#include "Data/Blobber.h"
#include "Device/DeviceManager.h"
#include "Device/Device.h"
#include "Model/Mix/Mix.h"
#include "TextureGraphInsight.h"
#include "Transform/Mix/T_UpdateTargets.h"
TextureGraphInsightSession::TextureGraphInsightSession() :
Record(new SessionRecord()),
Cache(new LiveCache(this))
{
}
TextureGraphInsightSession::~TextureGraphInsightSession()
{
}
void TextureGraphInsightSession::LiveCache::AddBlob(RecordID RecId, BlobPtr BlobObj)
{
if (RecId.IsBlob())
{
check(RecId.Blob() == Blobs.size());
Blobs.emplace_back(BlobEntry(BlobObj->Hash()->Value()));
}
}
BlobPtr TextureGraphInsightSession::LiveCache::GetBlob(RecordID RecId) const
{
if (RecId.IsBlob() && RecId.Blob() < Blobs.size())
{
const auto& blobEntry = Blobs[RecId.Blob()];
return TextureGraphEngine::GetInstance()->GetBlobber()->Find<Blob>(blobEntry).get();
}
return nullptr;
}
void TextureGraphInsightSession::LiveCache::AddBatch(RecordID RecId, JobBatchPtr Batch)
{
if (RecId.IsBatch())
{
check(RecId.Batch() == Batches.size());
Batches.emplace_back(Batch);
}
}
JobBatchPtr TextureGraphInsightSession::LiveCache::GetBatch(RecordID RecId) const
{
if ((RecId.IsBatch() || RecId.IsJob()) && RecId.Batch() < Batches.size())
{
return Batches[RecId.Batch()].lock();
}
return nullptr;
}
void TextureGraphInsightSession::LiveCache::AddMix(RecordID RecId, MixPtr MixObj)
{
if (RecId.IsMix())
{
check(RecId.Mix() == Mixes.size());
Mixes.emplace_back(MixObj);
}
}
MixPtr TextureGraphInsightSession::LiveCache::GetMix(RecordID RecId) const
{
if (RecId.IsMix() && RecId.Mix() < Mixes.size())
{
//return _mixes[RecId.Mix()].lock();
return Mixes[RecId.Mix()];
}
return nullptr;
}
DeviceBufferPtr TextureGraphInsightSession::LiveCache::GetDeviceBuffer(RecordID RecId) const
{
if (RecId.IsBuffer())
{
auto BufferRecord = Session->GetRecord().GetBuffer(RecId);
auto SourceBlob = BufferRecord.SourceID;
auto SourceBlobPtr = GetBlob(SourceBlob);
auto Hash = BufferRecord.HashValue;
if (SourceBlobPtr)
Hash = SourceBlobPtr->Hash()->Value();
// Try to find the buffer in the device under the first hash
auto Dev = TextureGraphEngine::GetInstance()->GetDeviceManager()->GetDevice(RecId.Buffer_DeviceType());
auto Buffer = Dev->Find(Hash, false);
// Couldn't find with what we think is final hash, try with prev hash if exists ?
if (!Buffer) {
if (BufferRecord.PrevHashValue != 0)
{
Buffer = Dev->Find(BufferRecord.PrevHashValue, false);
}
}
for (int32 i = RecId.Buffer_DeviceType() + 1; i < (int32) DeviceType::Count; i++)
{
Dev = TextureGraphEngine::GetInstance()->GetDeviceManager()->GetDevice(i);
if (Dev && !Buffer) {
Buffer = Dev->Find(Hash, false);
if (Buffer)
break;
}
}
// Couldn't find in the device cache... then look up in the blobber
if (!Buffer)
{
auto BlobPtr = TextureGraphEngine::GetInstance()->GetBlobber()->Find(BufferRecord.HashValue);
if (BlobPtr) {
Buffer = BlobPtr->GetBufferRef();
}
else
{
UE_LOG(LogTextureGraphInsight, Log, TEXT("TextureGraphInsightActionManagerObserver::GetDeviceBuffer find the buffer from hash but no buffer"));
}
}
// Couldn't find in the blobber under final hash ? try the prev hash
if (!Buffer) {
if (BufferRecord.PrevHashValue != 0)
{
auto blobPtr = TextureGraphEngine::GetInstance()->GetBlobber()->Find(BufferRecord.PrevHashValue);
if (blobPtr) {
Buffer = blobPtr->GetBufferRef();
}
else
{
UE_LOG(LogTextureGraphInsight, Log, TEXT("TextureGraphInsightActionManagerObserver::GetDeviceBuffer find the buffer from prevHash but no buffer"));
}
}
else
{
UE_LOG(LogTextureGraphInsight, Log, TEXT("TextureGraphInsightActionManagerObserver::GetDeviceBuffer cannot find the buffer in the cache, missing second hash"));
}
}
return Buffer;
}
return nullptr;
}
void TextureGraphInsightSession::EngineCreated()
{
if (TextureGraphEngine::IsTestMode())
return;
UE_LOG(LogTextureGraphInsight, Log, TEXT("TextureGraphInsightActionManagerObserver::EngineCreated"));
// Record and Cache should be defined, empty and ready to be used
RecordIDArray addedRecordIDs;
for (int32 i = 0; i < (int32) DeviceType::Count; ++i)
ParseDeviceBuffersCache((DeviceType)i, addedRecordIDs);
EmitOnEngineReset(true);
}
void TextureGraphInsightSession::EngineDestroyed()
{
if (TextureGraphEngine::IsTestMode())
return;
UE_LOG(LogTextureGraphInsight, Log, TEXT("TextureGraphInsightActionManagerObserver::EngineDestroyed"));
// Need to reset record and cache
{
std::lock_guard<std::mutex> Lock(RecordMutex);
Record = std::make_shared<SessionRecord>();
Cache = std::make_shared<LiveCache>(this);
}
EmitOnEngineReset(false);
}
void TextureGraphInsightSession::EmitOnEngineReset(bool createOrDestroy)
{
int32 PrevEngineID = EngineID;
if (createOrDestroy)
{
EngineID = abs(PrevEngineID) + 1;
}
else
{
EngineID = -abs(PrevEngineID);
}
OnEngineResetEvent.Broadcast(EngineID);
}
uint32 TextureGraphInsightSession::ParseDeviceBuffersCache(DeviceType DevType, RecordIDArray& AddedBufferIDs)
{
uint32 NumNewBuffers = 0;
auto DevIndex = (int32) DevType;
auto Dev = TextureGraphEngine::GetInstance()->GetDeviceManager()->GetDevice(DevType);
if (Dev)
{
auto Version = Dev->GetObserverSource()->GetVersion();
if (Version > GetCache().DeviceCacheVersions[DevIndex])
{
GetCache().DeviceCacheVersions[DevIndex] = Version;
auto NumBuffers = Dev->GetNumDeviceBuffersUsed();
DeviceObserverSource::HashArray buffers(NumBuffers, 0);
DeviceObserverSource::HashNDescArray hashNDescs(NumBuffers);
Dev->TraverseBufferCache([this,&buffers, &hashNDescs](const DeviceBufferPtr& buffer, uint32 index)
{
auto& Entry = hashNDescs[index];
Entry.Raw = (uint64)buffer.get();
Entry.First = buffer->Hash()->Value();
Entry.Second = buffer->Descriptor();
buffers[index] = Entry.Raw;
});
if (buffers.size())
{
// now compare against what we know
RecordIDArray LeakedRecIds;
auto BufferRecordIDs = GetRecord().FindActiveDeviceBufferRecords(DevType, buffers, LeakedRecIds);
for (auto i = 0; i < BufferRecordIDs.size(); ++i)
{
auto& RecId = BufferRecordIDs[i];
if (RecId.IsBuffer() && (RecId.Buffer_DeviceType() == DevIndex))
{
// everything happened as expected, all good, update the rank
auto& BuffRecord = GetRecord().GetBuffer(RecId);
BuffRecord.Rank = i;
BuffRecord.bLeaked = false;
}
else {
// We just discovered a buffer, let's create it in the records
DeviceBufferRecord DevBufferRec;
DevBufferRec.DevType = DevType;
DevBufferRec.ID = hashNDescs[i].Raw;
DevBufferRec.HashValue = hashNDescs[i].First;
DevBufferRec.Descriptor = hashNDescs[i].Second;
DevBufferRec.bLeaked = true;
DevBufferRec.Rank = i;
bool bAdded = false;
std::tie(RecId, bAdded) = GetRecord().NewDeviceBufferRecord(DevType, DevBufferRec.ID, DevBufferRec);
if (bAdded)
AddedBufferIDs.emplace_back(RecId);
++NumNewBuffers;
}
}
for (auto lid : LeakedRecIds)
{
auto& BufferRecord = GetRecord().GetBuffer(lid);
BufferRecord.bLeaked = true;
BufferRecord.Rank = -1;
}
}
}
}
if (NumNewBuffers)
{
auto t = Device::DeviceType_Names(DevType);
UE_LOG(LogTextureGraphInsight, VeryVerbose, TEXT("TextureGraphInsightSession::ParseDeviceBuffersCache[%s]: %d new unknown buffers"), *t, NumNewBuffers);
}
return NumNewBuffers;
}
void TextureGraphInsightSession::DeviceBuffersUpdated(DeviceType DevType, TextureGraphInsightDeviceObserver::HashNDescArray&& AddedBuffers, TextureGraphInsightDeviceObserver::HashArray&& RemovedBuffers)
{
RecordIDArray AddedRecIds;
for (auto& AddedBuffer : AddedBuffers)
{
DeviceBufferRecord DevBuffRec;
DevBuffRec.DevType = DevType;
DevBuffRec.ID = AddedBuffer.Raw;
DevBuffRec.HashValue = AddedBuffer.First;
DevBuffRec.Descriptor = AddedBuffer.Second;
auto key = AddedBuffer.Raw;
UE_LOG(LogTextureGraphInsight, VeryVerbose, TEXT("TextureGraphInsightSession::DeviceBuffersAdded : ptr 0x%llx - hash %llu"), key, AddedBuffer.First);
RecordID RecId;
bool bAdded;
std::tie(RecId, bAdded) = GetRecord().NewDeviceBufferRecord(DevType, key, DevBuffRec);
if (RecId.IsValid())
{
if (bAdded)
{
UE_LOG(LogTextureGraphInsight, VeryVerbose, TEXT("TextureGraphInsightSession::DeviceBuffersAdded : %d - hash %llu"), RecId.Buffer(), DevBuffRec.HashValue);
AddedRecIds.emplace_back(RecId);
}
else
{
UE_LOG(LogTextureGraphInsight, VeryVerbose, TEXT("TextureGraphInsightSession::DeviceBuffers Updated hash : %d - hash %llu"), RecId.Buffer(), DevBuffRec.HashValue);
}
}
else
{
UE_LOG(LogTextureGraphInsight, VeryVerbose, TEXT("TextureGraphInsightSession::DeviceBuffersAdded ERROR invalid buffer: ptr 0x%llx - hash %llu"), DevBuffRec.ID, DevBuffRec.HashValue);
}
}
RecordIDArray RemovedRecIds;
for (int i = 0; i < RemovedBuffers.size(); ++i)
{
auto bp = RemovedBuffers[i];
++i;
auto h = RemovedBuffers[i];
++i;
auto ph = RemovedBuffers[i];
UE_LOG(LogTextureGraphInsight, VeryVerbose, TEXT("TextureGraphInsightSession::DeviceBuffersRemoved : ptr 0x%llx - hash %llu - prevhash %llu"), bp, h, ph);
auto RecId = GetRecord().EraseDeviceBufferRecord(DevType, bp);
if (RecId.IsValid())
{
UE_LOG(LogTextureGraphInsight, VeryVerbose, TEXT("TextureGraphInsightSession::DeviceBuffersRemoved : %d"), RecId.Buffer());
RemovedRecIds.emplace_back(RecId);
}
else
{
UE_LOG(LogTextureGraphInsight, VeryVerbose, TEXT("TextureGraphInsightSession::DeviceBuffersAdded ERROR invalid buffer ?"));
}
}
// There was some changes, let's parse and eventually collect some new buffers that we would have missed ?
ParseDeviceBuffersCache(DevType, AddedRecIds);
OnDeviceBufferAddedEvent.Broadcast(AddedRecIds);
OnDeviceBufferRemovedEvent.Broadcast(RemovedRecIds);
}
void TextureGraphInsightSession::BlobberHashesUpdated(TextureGraphInsightBlobberObserver::HashArray&& AddedHashes, TextureGraphInsightBlobberObserver::HashArray&& RemappedHashes)
{
//for (auto a : addedHashes)
for (auto it = AddedHashes.rbegin(); it != AddedHashes.rend(); ++it)
{
auto a = (*it);
// UE_LOG(LogTextureGraphInsight, Log, TEXT("TextureGraphInsightSession::BlobberHashesUpdated::Added hash %llu"), a);
// Try to find the hash BlobObj
// auto n = FindOrCreateBlobRecordFromHash(a);
}
int32 numRemapped = RemappedHashes.size() >> 1;
for (int i = 0; i < numRemapped; ++i)
{
UE_LOG(LogTextureGraphInsight, VeryVerbose, TEXT("TextureGraphInsightSession::BlobberHashesUpdated::Remapped hash old %llu ==> new %llu"), RemappedHashes[2 * i], RemappedHashes[2 * i + 1]);
auto o = RemappedHashes[2 * i];
auto n = RemappedHashes[2 * i + 1];
if (o != n)
{
auto RecId = RemapBlobHash(o, n);
}
}
if (numRemapped)
EmitOnMappedBlob();
}
void TextureGraphInsightSession::UpdateIdle()
{
OnUpdateIdleEvent.Broadcast();
}
void TextureGraphInsightSession::BatchAdded(JobBatchPtr Batch)
{
UE_LOG(LogTextureGraphInsight, Log, TEXT("TextureGraphInsightSchedulerObserver::BatchAdded"));
}
void TextureGraphInsightSession::BatchDone(JobBatchPtr Batch)
{
UE_LOG(LogTextureGraphInsight, Log, TEXT("TextureGraphInsightSchedulerObserver::BatchDone"));
auto recordID = Record->NewBatchRecord(Batch->GetBatchId(),
[this, Batch](RecordID RecId) -> BatchRecord
{
return MakeBatchRecord(RecId, Batch);
});
if (recordID.IsValid())
{
// Cache the live job bath ptr
GetCache().AddBatch(recordID, Batch);
OnBatchAddedEvent.Broadcast(recordID);
}
if (recordID.IsValid())
{
OnBatchDoneEvent.Broadcast(recordID);
}
}
void TextureGraphInsightSession::BatchJobsDone(JobBatchPtr Batch)
{
UE_LOG(LogTextureGraphInsight, Log, TEXT("TextureGraphInsightSchedulerObserver::BatchDone"));
auto recordID = GetRecord().FindBatchRecord(Batch->GetBatchId());
GetRecord().EditBatchRecord(recordID,
[this, Batch](BatchRecord& BufferRecord)
{
UpdateBatchRecord(Batch, BufferRecord);
BufferRecord.bIsJobsDone = true;
return true;
});
if (recordID.IsValid())
{
OnBatchJobsDoneEvent.Broadcast(recordID);
}
}
void TextureGraphInsightSession::SendToInspector(RecordID recordID) const
{
if (recordID.IsValid())
{
if (recordID.IsBatch())
{
OnBatchInspectedEvent.Broadcast(recordID);
}
else if (recordID.IsJob())
{
OnJobInspectedEvent.Broadcast(recordID);
}
else if (recordID.IsBlob())
{
OnBlobInspectedEvent.Broadcast(recordID);
}
else if (recordID.IsBuffer())
{
OnBufferInspectedEvent.Broadcast(recordID);
}
}
}
BatchRecord TextureGraphInsightSession::MakeBatchRecord(RecordID RecId, JobBatchPtr Batch, bool isDone)
{
auto MixObj = Batch->GetCycle()->GetMix();
auto mixRid = AssociateBatchToMix(RecId, MixObj);
BatchRecord record;
record.SelfID = RecId;
record.BatchID = Batch->GetBatchId();
record.FrameID = Batch->GetFrameId();
record.BeginTimeMS = Batch->GetStartTime();
record.ReplayCount = Batch->GetReplayCount();
record.MixID = mixRid;
record.bIsDone = isDone;
record.bIsNoCache = Batch->GetCycle()->NoCache();
record.bIsFromIdle = Batch->IsIdle();
size_t numJobs = Batch->NumJobs();
record.Jobs.resize(numJobs);
std::vector<Job*> jobPtrs(numJobs, nullptr); // an array of the job pointers to retreive dependencies
size_t jobIndex = 0;
for (size_t j = 0; j < numJobs; ++j)
{
JobPtrW job = Batch->GetJobAt(j);
jobPtrs[j] = job.lock().get();
Job* generatorJobPtr = jobPtrs[j]->GeneratorJob().lock().get();
if (generatorJobPtr && generatorJobPtr != jobPtrs[j])
{
// find the generator job in the list of knwon jobs
auto genJobIdx = std::find(jobPtrs.begin(), jobPtrs.begin() + j, generatorJobPtr);
if (genJobIdx == jobPtrs.end())
check(false); /// Should never happen
record.Jobs[jobIndex++] = MakeJobRecord(job, (genJobIdx - jobPtrs.begin()), -1);
}
else
{
record.Jobs[jobIndex++] = MakeJobRecord(job, j);
}
}
/// RVO should handle this
return record;
}
void TextureGraphInsightSession::UpdateBatchRecord(JobBatchPtr Batch, BatchRecord& record) {
record.BeginTimeMS = Batch->GetStartTime();
record.EndTimeMS = Batch->GetEndTime();
record.ReplayCount = Batch->GetReplayCount();
auto cycle = Batch->GetCycle();
auto numJobs = Batch->NumJobs();
for (uint64_t j = 0; j < numJobs; ++j)
{
JobPtrW job = Batch->GetJobAt(j);
auto& rj = record.Jobs[j];
UpdateJobRecord(job, rj, record.BeginTimeMS, record.EndTimeMS);
rj.bIsDone = record.bIsDone;
record.NumInvalidatedTiles += rj.GetNumInvalidated();
record.NumTiles += rj.GetNumTiles();
}
// Capture the result target blobs
record.ResultBlobs.resize((int32)TextureType::Count);
if (cycle->GetNumTargets() && cycle->GetTarget(0))
{
TextureSet& lastRender = cycle->GetTarget(0)->GetLastRender();
for (int32 tti = 0; tti < (int32)TextureType::Count; tti++)
{
auto BlobObj = lastRender.GetTexture(tti);
if (BlobObj)
{
//auto bid = FindOrCreateBlobRecord(BlobObj, record._selfID);
//record._resultBlobs[tti] = bid;
}
}
}
EmitOnNewBlob();
}
JobRecord TextureGraphInsightSession::MakeJobRecord(JobPtrW job, uint32 idx, int32 phaseIdx)
{
JobRecord record;
JobPtr sjob = job.lock();
// record._jobID = job->ID();
record.JobIdx = idx;
record.PhaseIdx = phaseIdx;
record.Priority = sjob->GetPriority();
record.ReplayCount = sjob->GetReplayCount();
if (sjob->GetTiled()) {
record.Tiles.Resize(1, 1);
}
auto r = sjob->GetResult();
if (r)
{
record.TexWidth = r->GetWidth();
record.TexHeight = r->GetHeight();
record.Tiles.Resize(r->Rows(), r->Cols());
}
auto stats = sjob->GetStats();
record.BeginTimeMS = stats.BeginNativeTime;
record.BeginRunTimeMS = stats.BeginRunTime;
record.EndTimeMS = stats.EndNativeTime;
record.TransformName = sjob->GetTransform()->GetName();
return record;
}
void TextureGraphInsightSession::UpdateJobRecord(JobPtrW job, JobRecord& record, double batchBeginTime_ms, double batchEndTime_ms)
{
JobPtr sjob = job.lock();
if (sjob->IsCulled())
return;
record.JobHash = sjob->Hash()->Value();
auto stats = sjob->GetStats();
if (stats.BeginNativeTime < batchBeginTime_ms)
record.BeginTimeMS = batchBeginTime_ms;
else
record.BeginTimeMS = stats.BeginNativeTime;
if (stats.BeginRunTime == 0)
record.BeginRunTimeMS = 0; // record._beginTime_ms; // If the "runtime" stat is invalid then use the begin time
else
record.BeginRunTimeMS = stats.BeginRunTime;
if (stats.EndNativeTime < record.BeginRunTimeMS)
record.EndTimeMS = record.BeginRunTimeMS;
else if (stats.EndNativeTime > batchEndTime_ms)
record.EndTimeMS = batchEndTime_ms;
else
record.EndTimeMS = stats.EndNativeTime;
record.ReplayCount = sjob->GetReplayCount();
// Only on first replay capture all the inputs
if (record.ReplayCount == 0)
{
record.InputBlobIds.clear();
for (uint32_t i = 0; i < sjob->NumArgs(); ++i)
{
auto arg = sjob->GetArg(i);
auto blobArg = std::dynamic_pointer_cast<JobArg_Blob>(arg);
if (blobArg)
{
auto inputBlob = blobArg->GetBlob();
if (inputBlob)
{
record.InputBlobIds.emplace_back(FindOrCreateBlobRecord(inputBlob.get()));
record.InputArgNames.emplace_back(blobArg->Target());
}
}
}
}
// Deal with output
{
auto r = sjob->GetResult();
// In case of a replay update, all the inputs should be the same,
// the generated blobs are replayed too, let's imply call for an update
if (record.ReplayCount && record.ResultBlobId.IsValid())
{
UpdateBlobRecord(record.ResultBlobId, std::static_pointer_cast<Blob>(r.get()));
}
// Not a replay but the first time the job is over, generate the resulting BlobObj(s)
else if (r)
{
record.ResultBlobId = FindOrCreateBlobRecord(std::static_pointer_cast<Blob>(r.get()), record.SelfID);
record.TexWidth = r->GetWidth();
record.TexHeight = r->GetHeight();
record.Tiles.Resize(r->Rows(), r->Cols());
record.Tiles.ForEach([&](uint8_t tx, uint8_t ty)
{
record.Tiles(tx, ty) = sjob->GetTileInvalidation(tx, ty);
});
}
}
}
RecordID TextureGraphInsightSession::FindOrCreateBlobRecordFromHash(HashType hash)
{
//auto RecId = Record().FindBlobRecord((uint64_t)BlobObj.get());
auto RecId = GetRecord().FindBlobRecord(hash);
if (!RecId.IsValid())
{
auto BlobObj = TextureGraphEngine::GetInstance()->GetBlobber()->Find(hash);
if (BlobObj)
{
return FindOrCreateBlobRecord(BlobObj.get());
}
return RecordID();
}
else
return RecId;
}
RecordID TextureGraphInsightSession::FindOrCreateBlobRecord(BlobPtr BlobObj, RecordID sourceID)
{
if (BlobObj)
{
auto hash = BlobObj->Hash()->Value();
auto hashIsFinal = BlobObj->Hash()->IsFinal();
//auto RecId = Record().FindBlobRecord((uint64_t)BlobObj.get());
auto RecId = GetRecord().FindBlobRecord(hash);
if (!RecId.IsValid())
{
// Record the BlobObj right away (without tiling information)
//RecId = Record().NewBlobRecord((uint64_t)BlobObj.get(), MakeBlobRecord(BlobObj, sourceID));
RecId = GetRecord().NewBlobRecord(hash,
[this, BlobObj, sourceID](RecordID srid)
{
return MakeBlobRecord(srid, BlobObj, sourceID);
});
// Cache the live pointer to the BlobObj
GetCache().AddBlob(RecId, BlobObj);
// Remember the recordID of the new BlobObj for notification (from the batchRecord handler)
NewBlobsToNotify.emplace_back(RecId);
// Parse the sub tiles next (probably creating the BlobObj records)
if (BlobObj->IsTiled())
{
TiledBlobPtr tiledBlob = std::static_pointer_cast<TiledBlob>(BlobObj);
RecordIDTiles subTiles(tiledBlob->Rows(), tiledBlob->Cols());
subTiles.ForEach([&](uint8_t tx, uint8_t ty) {
subTiles(tx, ty) = FindOrCreateBlobRecord(tiledBlob->GetTile(tx, ty).get(), RecId);
});
// And then update the tiled BlobObj record of the parent
GetRecord().EditBlobRecord(RecId, [&](BlobRecord& rd)
{
EditTiledBlobRecord(rd, std::move(subTiles));
return true;
});
}
}
return RecId;
}
return RecordID();
}
RecordID TextureGraphInsightSession::RemapBlobHash(HashType oldHash, HashType newHash)
{
auto old_rid = GetRecord().FindBlobRecord(oldHash);
auto new_rid = GetRecord().FindBlobRecord(newHash);
if (new_rid.IsValid() && old_rid.IsValid())
{
GetRecord().EditBlobRecord(old_rid, [=](BlobRecord& BufferRecord) { BufferRecord.MappedID = new_rid; return true; });
GetRecord().EditBlobRecord(new_rid, [=](BlobRecord& BufferRecord) { BufferRecord.NumMapped++; return true; });
MappedBlobsToNotify.emplace_back(old_rid);
}
return old_rid;
}
BlobRecord TextureGraphInsightSession::MakeBlobRecord(RecordID RecId, BlobPtr BlobObj, RecordID sourceID)
{
BlobRecord record;
record.SourceID = sourceID;
record.Name = BlobObj->Name();
record.HashValue = BlobObj->Hash()->Value();
record.TexWidth = BlobObj->GetWidth();
record.TexHeight = BlobObj->GetHeight();
return record;
}
void TextureGraphInsightSession::EditTiledBlobRecord(BlobRecord& rd, const RecordIDTiles& subTiles)
{
rd.TileIdxs.Resize(subTiles.Grid());
for (int i = 0; i < subTiles.Grid().NumTiles(); ++i) {
auto f = std::find(rd.UniqueBlobs.begin(), rd.UniqueBlobs.end(), subTiles._tiles[i].Blob());
if (f == rd.UniqueBlobs.end())
{
rd.TileIdxs._tiles[i] = (uint8_t)rd.UniqueBlobs.size();
rd.UniqueBlobs.emplace_back(subTiles._tiles[i].Blob());
}
else
{
rd.TileIdxs._tiles[i] = (uint8_t)(f - rd.UniqueBlobs.begin());
}
}
}
void TextureGraphInsightSession::UpdateBlobRecord(RecordID RecId, BlobPtr BlobObj)
{
if (BlobObj && RecId.IsBlob())
{
GetRecord().EditBlobRecord(RecId, [this, BlobObj](BlobRecord& BufferRecord)
{
if (!BufferRecord.IsTiled())
BufferRecord.RawBufferMemSize = BlobObj->GetBufferRef()->MemSize();
// Simply update the replay count, should be the only thing changed
BufferRecord.ReplayCount = BlobObj->GetReplayCount();
// Blob is really tiled, then dispatch updates to sub tiles
if (BlobObj->IsTiled() && BufferRecord.IsTiled())
{
TiledBlobPtr tiledBlob = std::static_pointer_cast<TiledBlob>(BlobObj);
BufferRecord.TileIdxs._grid.ForEach([&](uint32 tx, uint32 ty) {
UpdateBlobRecord(BufferRecord.GetTileBlob(tx, ty), tiledBlob->GetTile(tx, ty).get());
});
}
return true;
});
}
}
void TextureGraphInsightSession::EmitOnNewBlob()
{
auto addedBlobs = std::move(NewBlobsToNotify);
NewBlobsToNotify.clear();
OnBlobAddedEvent.Broadcast(addedBlobs);
}
void TextureGraphInsightSession::EmitOnMappedBlob()
{
auto mappedBlobs = std::move(MappedBlobsToNotify);
MappedBlobsToNotify.clear();
OnBlobMappedEvent.Broadcast(mappedBlobs);
}
bool TextureGraphInsightSession::ReplayBatch(RecordID batchRecordID, bool captureRenderDoc)
{
// Get to the Batch ptr if still alive:
auto batchPtr = GetCache().GetBatch(batchRecordID);
if (batchPtr)
{
// configure the replay and spawn it
batchPtr->ResetForReplay();
batchPtr->SetCaptureRenderDoc(false);
if (captureRenderDoc)
TextureGraphEngine::GetInstance()->GetScheduler()->SetCaptureRenderDocNextBatch(true);
TextureGraphEngine::GetInstance()->GetScheduler()->AddBatch(batchPtr);
return true;
}
return false;
}
bool TextureGraphInsightSession::ReplayJob(RecordID jobRecordID, bool captureRenderDoc)
{
// Get to the Batch ptr if still alive:
auto batchPtr = GetCache().GetBatch(jobRecordID);
if (batchPtr)
{
// configure the replay and spawn it
batchPtr->ResetForReplay(jobRecordID.Job());
batchPtr->SetCaptureRenderDoc(false);
if(captureRenderDoc)
TextureGraphEngine::GetInstance()->GetScheduler()->SetCaptureRenderDocNextBatch(true);
TextureGraphEngine::GetInstance()->GetScheduler()->AddBatch(batchPtr);
return true;
}
return false;
}
RecordID TextureGraphInsightSession::AssociateBatchToMix(RecordID Batch, MixPtr MixObj)
{
auto mixID = FindOrCreateMixRecord(MixObj);
if (mixID.IsValid())
{
if (GetRecord().EditMixRecord(mixID,
[Batch](MixRecord& mr)
{
mr.Batches.emplace_back(Batch);
return true;
}))
{
OnMixUpdatedEvent.Broadcast(mixID);
}
}
return mixID;
}
RecordID TextureGraphInsightSession::FindOrCreateMixRecord(MixPtr MixObj)
{
if (MixObj)
{
//auto hash = MixObj->Hash()->Value();
auto hash = (uint64)MixObj;
auto RecId = GetRecord().FindMixRecord(hash);
if (!RecId.IsValid())
{
UMix* mAsMix = dynamic_cast<UMix*>(MixObj);
// if an Instance, find or allocate the parent MixObj
RecordID parentID;
// Record the MixObj
RecId = GetRecord().NewMixRecord(hash,
[=](RecordID srid)
{
MixRecord record;
record.Name = MixObj->GetName();
record.ParentMixID = parentID;
return record;
});
// Cache the live pointer to the MixObj
GetCache().AddMix(RecId, MixObj);
OnMixAddedEvent.Broadcast(RecId);
// If parent ID is valid, add this knowledge to parent record and notify for update
if (parentID.IsValid())
{
GetRecord().EditMixRecord(parentID,
[=](MixRecord& mr)
{
mr.InstanceMixIDs.emplace_back(RecId);
return true;
});
OnMixUpdatedEvent.Broadcast(parentID);
}
}
// Return the RecId already existing or the brand new one
return RecId;
}
return RecordID();
}