mirror of
https://github.com/leozide/leocad.git
synced 2026-10-27 06:20:55 +00:00
Clarify asset loader request and completion APIs
Use consistent names for piece loading, synth generation, worker completions, and outstanding work. Remove the unused library drain wrapper and call the loader directly during settings updates. Check for the final consumer release in the library before cancelling queued piece work, and document how running builds retain their load hold until completion. Update callers and asset-loading documentation.
This commit is contained in:
1 parent
d493eee066
commit
f4fe4f8e87
11 files changed
+134
-141
No files matched your search
+73
-76
@@ -26,27 +26,27 @@ lcAssetLoader::~lcAssetLoader()
|
||||
CancelAndDrain();
|
||||
}
|
||||
|
||||
bool lcAssetLoader::LoadPieceInfo(PieceInfo* Info, lcPieceLoadPriority LoadPriority)
|
||||
bool lcAssetLoader::RequestPieceLoad(PieceInfo* Info, lcPieceLoadPriority LoadPriority)
|
||||
{
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
if (Info->IsProject() || (Info->IsModel() && !Info->GetModel()->HasDirectGeometry()))
|
||||
Info->mState = lcPieceInfoState::Loaded;
|
||||
else if (Info->mState == lcPieceInfoState::Unloaded)
|
||||
EnqueuePiece(Info, LoadPriority);
|
||||
QueuePiece(Info, LoadPriority);
|
||||
else if (LoadPriority != lcPieceLoadPriority::Low)
|
||||
{
|
||||
mQueueMutex.lock();
|
||||
const auto It = mPieceRequests.find(Info);
|
||||
if (It != mPieceRequests.end())
|
||||
PromoteRequestPriorityLocked(It->second, LoadPriority);
|
||||
PromotePiecePriorityLocked(It->second, LoadPriority);
|
||||
mQueueMutex.unlock();
|
||||
}
|
||||
|
||||
return LoadPriority != lcPieceLoadPriority::Blocking || WaitForRequest(Info);
|
||||
return LoadPriority != lcPieceLoadPriority::Blocking || WaitForPieceRequest(Info);
|
||||
}
|
||||
|
||||
void lcAssetLoader::EnqueuePiece(PieceInfo* Info, lcPieceLoadPriority LoadPriority)
|
||||
void lcAssetLoader::QueuePiece(PieceInfo* Info, lcPieceLoadPriority LoadPriority)
|
||||
{
|
||||
QMutexLocker QueueLock(&mQueueMutex);
|
||||
|
||||
@@ -57,7 +57,7 @@ void lcAssetLoader::EnqueuePiece(PieceInfo* Info, lcPieceLoadPriority LoadPriori
|
||||
|
||||
if (Existing != mPieceRequests.end())
|
||||
{
|
||||
PromoteRequestPriorityLocked(Existing->second, LoadPriority);
|
||||
PromotePiecePriorityLocked(Existing->second, LoadPriority);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -95,7 +95,7 @@ void lcAssetLoader::EnqueuePiece(PieceInfo* Info, lcPieceLoadPriority LoadPriori
|
||||
emit mLibrary->AssetRequestsChanged();
|
||||
}
|
||||
|
||||
void lcAssetLoader::PromoteRequestPriorityLocked(const std::shared_ptr<PieceRequest>& RequestedPiece, lcPieceLoadPriority LoadPriority)
|
||||
void lcAssetLoader::PromotePiecePriorityLocked(const std::shared_ptr<PieceRequest>& RequestedPiece, lcPieceLoadPriority LoadPriority)
|
||||
{
|
||||
RequestedPiece->LoadPriority = std::max(RequestedPiece->LoadPriority, LoadPriority);
|
||||
|
||||
@@ -114,7 +114,7 @@ void lcAssetLoader::PromoteRequestPriorityLocked(const std::shared_ptr<PieceRequ
|
||||
}
|
||||
}
|
||||
|
||||
void lcAssetLoader::QueueSynthMesh(lcPiece* Piece)
|
||||
void lcAssetLoader::RequestSynthMesh(lcPiece* Piece)
|
||||
{
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
@@ -231,28 +231,28 @@ void lcAssetLoader::RunWorker()
|
||||
return Score(Left) < Score(Right) || (Score(Left) == Score(Right) && Left->EnqueuedAt > Right->EnqueuedAt);
|
||||
};
|
||||
|
||||
auto PartBest = std::max_element(mPieceQueue.begin(), mPieceQueue.end(), Less);
|
||||
auto PieceBest = std::max_element(mPieceQueue.begin(), mPieceQueue.end(), Less);
|
||||
auto TextureBest = std::max_element(mTextureQueue.begin(), mTextureQueue.end(), Less);
|
||||
auto SynthBest = std::max_element(mSynthQueue.begin(), mSynthQueue.end(), Less);
|
||||
|
||||
if (TextureBest != mTextureQueue.end() && (PartBest == mPieceQueue.end() || !Less(*TextureBest, *PartBest)) &&
|
||||
if (TextureBest != mTextureQueue.end() && (PieceBest == mPieceQueue.end() || !Less(*TextureBest, *PieceBest)) &&
|
||||
(SynthBest == mSynthQueue.end() || !Less(*TextureBest, *SynthBest)))
|
||||
{
|
||||
RequestedTexture = *TextureBest;
|
||||
mTextureQueue.erase(TextureBest);
|
||||
RequestedTexture->Running = true;
|
||||
RequestedTexture->AwaitingCompletion = true;
|
||||
}
|
||||
else if (SynthBest != mSynthQueue.end() && (PartBest == mPieceQueue.end() || !Less(*SynthBest, *PartBest)))
|
||||
else if (SynthBest != mSynthQueue.end() && (PieceBest == mPieceQueue.end() || !Less(*SynthBest, *PieceBest)))
|
||||
{
|
||||
RequestedSynth = *SynthBest;
|
||||
mSynthQueue.erase(SynthBest);
|
||||
RequestedSynth->Running = true;
|
||||
RequestedSynth->AwaitingCompletion = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
RequestedPiece = *PartBest;
|
||||
mPieceQueue.erase(PartBest);
|
||||
RequestedPiece->Running = true;
|
||||
RequestedPiece = *PieceBest;
|
||||
mPieceQueue.erase(PieceBest);
|
||||
RequestedPiece->AwaitingCompletion = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,14 +267,14 @@ void lcAssetLoader::RunWorker()
|
||||
|
||||
if (RequestedPiece->MeshData)
|
||||
{
|
||||
Completed.Result.Mesh.reset(RequestedPiece->MeshData->CreateMeshResolved(RequestedPiece->ColorTranslucency, RequestedPiece->DefaultColorIndex, nullptr));
|
||||
Completed.PieceResult.Mesh.reset(RequestedPiece->MeshData->CreateMeshResolved(RequestedPiece->ColorTranslucency, RequestedPiece->DefaultColorIndex, nullptr));
|
||||
RequestedPiece->MeshData.reset();
|
||||
|
||||
if (!Completed.Result.Mesh)
|
||||
Completed.Result.Error = tr("Could not prepare piece %1 for rendering.").arg(RequestedPiece->Source.FileName);
|
||||
if (!Completed.PieceResult.Mesh)
|
||||
Completed.PieceResult.Error = tr("Could not prepare piece %1 for rendering.").arg(RequestedPiece->Source.FileName);
|
||||
}
|
||||
else
|
||||
Completed.Result = mLibrary->BuildPieceData(RequestedPiece->Source);
|
||||
Completed.PieceResult = mLibrary->BuildPieceData(RequestedPiece->Source);
|
||||
}
|
||||
else if (RequestedTexture)
|
||||
{
|
||||
@@ -323,7 +323,7 @@ bool lcAssetLoader::ProcessCompletions()
|
||||
{
|
||||
const std::shared_ptr<PieceRequest>& RequestedPiece = Entry.second;
|
||||
|
||||
if (RequestedPiece->Running && RequestedPiece->Info->mState == lcPieceInfoState::Queued)
|
||||
if (RequestedPiece->AwaitingCompletion && RequestedPiece->Info->mState == lcPieceInfoState::Queued)
|
||||
RequestedPiece->Info->mState = lcPieceInfoState::Loading;
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ bool lcAssetLoader::ProcessCompletions()
|
||||
{
|
||||
const std::shared_ptr<TextureRequest>& RequestedTexture = Entry.second;
|
||||
|
||||
if (RequestedTexture->Running && RequestedTexture->Texture->mState == lcTextureState::Queued)
|
||||
if (RequestedTexture->AwaitingCompletion && RequestedTexture->Texture->mState == lcTextureState::Queued)
|
||||
RequestedTexture->Texture->mState = lcTextureState::Decoding;
|
||||
}
|
||||
}
|
||||
@@ -397,11 +397,11 @@ bool lcAssetLoader::ProcessCompletions()
|
||||
}
|
||||
|
||||
if (Completed.RequestedTexture)
|
||||
CompleteTexture(Completed);
|
||||
ProcessTextureCompletion(Completed);
|
||||
else if (Completed.RequestedSynth)
|
||||
CompleteSynth(Completed);
|
||||
ProcessSynthCompletion(Completed);
|
||||
else
|
||||
CompletePiece(Completed);
|
||||
ProcessPieceCompletion(Completed);
|
||||
}
|
||||
|
||||
mQueueMutex.lock();
|
||||
@@ -417,7 +417,7 @@ bool lcAssetLoader::ProcessCompletions()
|
||||
return Progress;
|
||||
}
|
||||
|
||||
void lcAssetLoader::CompletePiece(Completion& Completed)
|
||||
void lcAssetLoader::ProcessPieceCompletion(Completion& Completed)
|
||||
{
|
||||
const std::shared_ptr<PieceRequest>& RequestedPiece = Completed.RequestedPiece;
|
||||
PieceInfo* Info = RequestedPiece->Info;
|
||||
@@ -430,7 +430,7 @@ void lcAssetLoader::CompletePiece(Completion& Completed)
|
||||
mPieceRequests.erase(It);
|
||||
mQueueMutex.unlock();
|
||||
|
||||
RequestedPiece->Running = false;
|
||||
RequestedPiece->AwaitingCompletion = false;
|
||||
|
||||
const bool HasConsumer = mLibrary->HasPieceConsumers(Info);
|
||||
|
||||
@@ -456,12 +456,12 @@ void lcAssetLoader::CompletePiece(Completion& Completed)
|
||||
return;
|
||||
}
|
||||
|
||||
RequestedPiece->Error = Completed.Result.Error;
|
||||
RequestedPiece->EmptyGeometry = Completed.Result.EmptyGeometry;
|
||||
RequestedPiece->Error = Completed.PieceResult.Error;
|
||||
RequestedPiece->EmptyGeometry = Completed.PieceResult.EmptyGeometry;
|
||||
|
||||
if (RequestedPiece->Error.isEmpty())
|
||||
{
|
||||
if (Completed.Result.FromCache && !Completed.Result.Mesh)
|
||||
if (Completed.PieceResult.FromCache && !Completed.PieceResult.Mesh)
|
||||
{
|
||||
// Rebuild a corrupt cache privately on a worker, then use the normal commit path.
|
||||
RequestedPiece->Source.SkipCache = true;
|
||||
@@ -474,11 +474,11 @@ void lcAssetLoader::CompletePiece(Completion& Completed)
|
||||
|
||||
return;
|
||||
}
|
||||
else if (Completed.Result.MeshData)
|
||||
else if (Completed.PieceResult.MeshData)
|
||||
{
|
||||
// Register color indices on the UI thread, then queue the expensive mesh conversion.
|
||||
ResolveMeshColors(*Completed.Result.MeshData, RequestedPiece->ColorTranslucency, RequestedPiece->DefaultColorIndex);
|
||||
RequestedPiece->MeshData = std::move(Completed.Result.MeshData);
|
||||
ResolveMeshColors(*Completed.PieceResult.MeshData, RequestedPiece->ColorTranslucency, RequestedPiece->DefaultColorIndex);
|
||||
RequestedPiece->MeshData = std::move(Completed.PieceResult.MeshData);
|
||||
Info->mState = lcPieceInfoState::Queued;
|
||||
|
||||
QMutexLocker QueueLock(&mQueueMutex);
|
||||
@@ -488,10 +488,10 @@ void lcAssetLoader::CompletePiece(Completion& Completed)
|
||||
|
||||
return;
|
||||
}
|
||||
else if (Completed.Result.Mesh)
|
||||
else if (Completed.PieceResult.Mesh)
|
||||
{
|
||||
RequestedPiece->ColorTranslucency.clear();
|
||||
RequestedPiece->StagedMesh = std::move(Completed.Result.Mesh);
|
||||
RequestedPiece->StagedMesh = std::move(Completed.PieceResult.Mesh);
|
||||
size_t ColorIndex = 0;
|
||||
|
||||
for (lcMeshLod& Lod : RequestedPiece->StagedMesh->mLods)
|
||||
@@ -500,12 +500,12 @@ void lcAssetLoader::CompletePiece(Completion& Completed)
|
||||
{
|
||||
lcMeshSection& Section = Lod.Sections[SectionIdx];
|
||||
|
||||
if (Completed.Result.FromCache)
|
||||
Section.ColorIndex = lcGetColorIndex(Completed.Result.ColorCodes[ColorIndex++]);
|
||||
if (Completed.PieceResult.FromCache)
|
||||
Section.ColorIndex = lcGetColorIndex(Completed.PieceResult.ColorCodes[ColorIndex++]);
|
||||
}
|
||||
}
|
||||
|
||||
RequestedPiece->SaveCache = !Completed.Result.FromCache;
|
||||
RequestedPiece->SaveCache = !Completed.PieceResult.FromCache;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,7 +526,7 @@ void lcAssetLoader::CompletePiece(Completion& Completed)
|
||||
FinishPiece(RequestedPiece);
|
||||
}
|
||||
|
||||
void lcAssetLoader::CompleteSynth(Completion& Completed)
|
||||
void lcAssetLoader::ProcessSynthCompletion(Completion& Completed)
|
||||
{
|
||||
const std::shared_ptr<SynthRequest>& RequestedSynth = Completed.RequestedSynth;
|
||||
bool Stale;
|
||||
@@ -537,7 +537,7 @@ void lcAssetLoader::CompleteSynth(Completion& Completed)
|
||||
It == mSynthRequests.end() || It->second != RequestedSynth;
|
||||
if (Stale && It != mSynthRequests.end() && It->second == RequestedSynth)
|
||||
mSynthRequests.erase(It);
|
||||
RequestedSynth->Running = false;
|
||||
RequestedSynth->AwaitingCompletion = false;
|
||||
mResultReady.wakeAll();
|
||||
mQueueMutex.unlock();
|
||||
|
||||
@@ -578,7 +578,7 @@ void lcAssetLoader::CompleteSynth(Completion& Completed)
|
||||
FinishSynth(RequestedSynth);
|
||||
}
|
||||
|
||||
void lcAssetLoader::CompleteTexture(Completion& Completed)
|
||||
void lcAssetLoader::ProcessTextureCompletion(Completion& Completed)
|
||||
{
|
||||
const std::shared_ptr<TextureRequest>& RequestedTexture = Completed.RequestedTexture;
|
||||
lcTexture* Texture = RequestedTexture->Texture;
|
||||
@@ -589,7 +589,7 @@ void lcAssetLoader::CompleteTexture(Completion& Completed)
|
||||
Stale = mStopping || It == mTextureRequests.end() || It->second != RequestedTexture;
|
||||
if (Stale && It != mTextureRequests.end() && It->second == RequestedTexture)
|
||||
mTextureRequests.erase(It);
|
||||
RequestedTexture->Running = false;
|
||||
RequestedTexture->AwaitingCompletion = false;
|
||||
mResultReady.wakeAll();
|
||||
mQueueMutex.unlock();
|
||||
|
||||
@@ -601,13 +601,13 @@ void lcAssetLoader::CompleteTexture(Completion& Completed)
|
||||
if (Texture->NeedsUpload())
|
||||
UploadTextureRequest(RequestedTexture);
|
||||
else
|
||||
FinishTextureRequest(RequestedTexture);
|
||||
FinishTexture(RequestedTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
Texture->SetFailed(Completed.TextureResult.Error, std::move(Completed.TextureResult.ErrorDetails));
|
||||
|
||||
FinishTextureRequest(RequestedTexture);
|
||||
FinishTexture(RequestedTexture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -758,10 +758,10 @@ void lcAssetLoader::UploadTextureRequest(const std::shared_ptr<TextureRequest>&
|
||||
Texture->DiscardDecodedImage();
|
||||
}
|
||||
|
||||
FinishTextureRequest(RequestedTexture);
|
||||
FinishTexture(RequestedTexture);
|
||||
}
|
||||
|
||||
void lcAssetLoader::FinishTextureRequest(const std::shared_ptr<TextureRequest>& RequestedTexture)
|
||||
void lcAssetLoader::FinishTexture(const std::shared_ptr<TextureRequest>& RequestedTexture)
|
||||
{
|
||||
mQueueMutex.lock();
|
||||
const auto It = mTextureRequests.find(RequestedTexture->Texture);
|
||||
@@ -874,9 +874,9 @@ void lcAssetLoader::FinishSynth(const std::shared_ptr<SynthRequest>& RequestedSy
|
||||
Piece->SetGeneratedMesh(Loaded ? RequestedSynth->StagedMesh.release() : nullptr);
|
||||
|
||||
if (Loaded)
|
||||
mFailedSynthErrors.erase(Piece);
|
||||
mSynthErrors.erase(Piece);
|
||||
else
|
||||
mFailedSynthErrors.insert_or_assign(Piece, RequestedSynth->Error);
|
||||
mSynthErrors.insert_or_assign(Piece, RequestedSynth->Error);
|
||||
|
||||
if (!Loaded)
|
||||
{
|
||||
@@ -1006,7 +1006,7 @@ void lcAssetLoader::WaitForResultsLocked()
|
||||
}
|
||||
}
|
||||
|
||||
bool lcAssetLoader::WaitForRequest(PieceInfo* Info)
|
||||
bool lcAssetLoader::WaitForPieceRequest(PieceInfo* Info)
|
||||
{
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
@@ -1021,7 +1021,7 @@ bool lcAssetLoader::WaitForRequest(PieceInfo* Info)
|
||||
{
|
||||
RequestedPiece = It->second;
|
||||
|
||||
PromoteRequestPriorityLocked(RequestedPiece, lcPieceLoadPriority::Blocking);
|
||||
PromotePiecePriorityLocked(RequestedPiece, lcPieceLoadPriority::Blocking);
|
||||
}
|
||||
StartWorkersLocked();
|
||||
}
|
||||
@@ -1070,7 +1070,7 @@ bool lcAssetLoader::WaitForPieces(const std::vector<PieceInfo*>& Pieces)
|
||||
if (Info->IsProject() || (Info->IsModel() && !Info->GetModel()->HasDirectGeometry()))
|
||||
Info->mState = lcPieceInfoState::Loaded;
|
||||
else
|
||||
EnqueuePiece(Info, lcPieceLoadPriority::Blocking);
|
||||
QueuePiece(Info, lcPieceLoadPriority::Blocking);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1083,7 +1083,7 @@ bool lcAssetLoader::WaitForPieces(const std::vector<PieceInfo*>& Pieces)
|
||||
if (It == mPieceRequests.end())
|
||||
continue;
|
||||
|
||||
PromoteRequestPriorityLocked(It->second, lcPieceLoadPriority::Blocking);
|
||||
PromotePiecePriorityLocked(It->second, lcPieceLoadPriority::Blocking);
|
||||
}
|
||||
|
||||
StartWorkersLocked();
|
||||
@@ -1092,7 +1092,7 @@ bool lcAssetLoader::WaitForPieces(const std::vector<PieceInfo*>& Pieces)
|
||||
bool Ready = true;
|
||||
|
||||
for (PieceInfo* Info : Required)
|
||||
Ready = WaitForRequest(Info) && Ready;
|
||||
Ready = WaitForPieceRequest(Info) && Ready;
|
||||
|
||||
return Ready;
|
||||
}
|
||||
@@ -1189,7 +1189,7 @@ bool lcAssetLoader::WaitForTexture(lcTexture* Texture)
|
||||
return Texture->IsReady();
|
||||
}
|
||||
|
||||
void lcAssetLoader::WaitForLoadQueue()
|
||||
void lcAssetLoader::WaitForAllWork()
|
||||
{
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
@@ -1222,9 +1222,9 @@ bool lcAssetLoader::HasPendingWork()
|
||||
|
||||
QString lcAssetLoader::GetSynthMeshError(const lcPiece* Piece) const
|
||||
{
|
||||
const std::unordered_map<const lcPiece*, QString>::const_iterator It = mFailedSynthErrors.find(Piece);
|
||||
const std::unordered_map<const lcPiece*, QString>::const_iterator It = mSynthErrors.find(Piece);
|
||||
|
||||
return It != mFailedSynthErrors.end() ? It->second : QString();
|
||||
return It != mSynthErrors.end() ? It->second : QString();
|
||||
}
|
||||
|
||||
void lcAssetLoader::RebuildModelPiece(PieceInfo* Info)
|
||||
@@ -1233,7 +1233,7 @@ void lcAssetLoader::RebuildModelPiece(PieceInfo* Info)
|
||||
Q_ASSERT(Info->IsModel());
|
||||
|
||||
if (Info->IsLoading())
|
||||
WaitForRequest(Info);
|
||||
WaitForPieceRequest(Info);
|
||||
|
||||
Info->ReleaseMesh();
|
||||
mLibrary->ClearPieceLoadError(Info);
|
||||
@@ -1247,7 +1247,7 @@ void lcAssetLoader::RebuildModelPiece(PieceInfo* Info)
|
||||
|
||||
Info->mState = lcPieceInfoState::Unloaded;
|
||||
|
||||
EnqueuePiece(Info, lcPieceLoadPriority::Normal);
|
||||
QueuePiece(Info, lcPieceLoadPriority::Normal);
|
||||
}
|
||||
|
||||
void lcAssetLoader::InvalidatePiece(PieceInfo* Info)
|
||||
@@ -1268,7 +1268,7 @@ void lcAssetLoader::InvalidatePiece(PieceInfo* Info)
|
||||
Removed->Obsolete = true;
|
||||
Removed->Terminal = true;
|
||||
Removed->Succeeded = false;
|
||||
ReleaseHold = !Removed->Running;
|
||||
ReleaseHold = !Removed->AwaitingCompletion;
|
||||
mPieceRequests.erase(It);
|
||||
|
||||
mPieceQueue.erase(std::remove(mPieceQueue.begin(), mPieceQueue.end(), Removed), mPieceQueue.end());
|
||||
@@ -1281,13 +1281,13 @@ void lcAssetLoader::InvalidatePiece(PieceInfo* Info)
|
||||
mResultReady.wakeAll();
|
||||
}
|
||||
|
||||
if (Removed && !Removed->Running)
|
||||
if (Removed && !Removed->AwaitingCompletion)
|
||||
Removed->StagedMesh.reset();
|
||||
|
||||
Info->mState = lcPieceInfoState::Unloaded;
|
||||
mLibrary->ClearPieceLoadError(Info);
|
||||
|
||||
// Running work retains its load hold until its stale completion arrives.
|
||||
// Work awaiting completion retains its load hold until its stale completion arrives.
|
||||
if (ReleaseHold)
|
||||
mLibrary->ReleasePieceLoadHold(Info);
|
||||
|
||||
@@ -1297,14 +1297,11 @@ void lcAssetLoader::InvalidatePiece(PieceInfo* Info)
|
||||
emit mLibrary->AssetRequestsChanged();
|
||||
}
|
||||
|
||||
void lcAssetLoader::OnConsumerReleased(PieceInfo* Info)
|
||||
void lcAssetLoader::CancelPieceLoad(PieceInfo* Info)
|
||||
{
|
||||
// Ordinary running builds finish privately; discard them if their last consumer is gone.
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
if (mLibrary->HasPieceConsumers(Info))
|
||||
return;
|
||||
|
||||
std::shared_ptr<PieceRequest> Removed;
|
||||
{
|
||||
QMutexLocker QueueLock(&mQueueMutex);
|
||||
@@ -1316,7 +1313,7 @@ void lcAssetLoader::OnConsumerReleased(PieceInfo* Info)
|
||||
|
||||
const std::shared_ptr<PieceRequest>& RequestedPiece = It->second;
|
||||
|
||||
if (RequestedPiece->Running)
|
||||
if (RequestedPiece->AwaitingCompletion)
|
||||
return;
|
||||
|
||||
RequestedPiece->Obsolete = true;
|
||||
@@ -1347,7 +1344,7 @@ void lcAssetLoader::CancelSynthMesh(lcPiece* Piece)
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
mSynthPieces.erase(Piece);
|
||||
mFailedSynthErrors.erase(Piece);
|
||||
mSynthErrors.erase(Piece);
|
||||
|
||||
for (SynthNotification& Pending : mSynthNotifications)
|
||||
if (Pending.RequestedSynth->Piece == Piece)
|
||||
@@ -1371,7 +1368,7 @@ void lcAssetLoader::CancelSynthMesh(lcPiece* Piece)
|
||||
mResultReady.wakeAll();
|
||||
}
|
||||
|
||||
if (!Removed->Running)
|
||||
if (!Removed->AwaitingCompletion)
|
||||
{
|
||||
Removed->StagedMesh.reset();
|
||||
CancelUnusedTextureRequests();
|
||||
@@ -1390,7 +1387,7 @@ void lcAssetLoader::CancelUnusedTextureRequests()
|
||||
const std::shared_ptr<TextureRequest>& RequestedTexture = It->second;
|
||||
|
||||
// A queued request owns one reference; all others belong to consumers.
|
||||
if (RequestedTexture->Running || RequestedTexture->Texture->GetRefCount() > 1)
|
||||
if (RequestedTexture->AwaitingCompletion || RequestedTexture->Texture->GetRefCount() > 1)
|
||||
{
|
||||
++It;
|
||||
continue;
|
||||
@@ -1420,7 +1417,7 @@ void lcAssetLoader::CancelUnusedTextureRequests()
|
||||
}
|
||||
}
|
||||
|
||||
void lcAssetLoader::ReloadSynthMeshes()
|
||||
void lcAssetLoader::RebuildSynthMeshes()
|
||||
{
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
@@ -1469,7 +1466,7 @@ void lcAssetLoader::PauseQueuedWork()
|
||||
|
||||
RequestedPiece->StagedMesh.reset();
|
||||
RequestedPiece->Info->mState = lcPieceInfoState::Queued;
|
||||
RequestedPiece->Running = false;
|
||||
RequestedPiece->AwaitingCompletion = false;
|
||||
mPieceQueue.push_back(RequestedPiece);
|
||||
}
|
||||
|
||||
@@ -1527,11 +1524,11 @@ void lcAssetLoader::CancelAndDrain()
|
||||
mTextureQueue.clear();
|
||||
mSynthQueue.clear();
|
||||
mSynthPieces.clear();
|
||||
mFailedSynthErrors.clear();
|
||||
mSynthErrors.clear();
|
||||
|
||||
for (auto It = mPieceRequests.begin(); It != mPieceRequests.end();)
|
||||
{
|
||||
if (It->second->Running)
|
||||
if (It->second->AwaitingCompletion)
|
||||
{
|
||||
It->second->Obsolete = true;
|
||||
++It;
|
||||
@@ -1550,7 +1547,7 @@ void lcAssetLoader::CancelAndDrain()
|
||||
|
||||
for (auto It = mTextureRequests.begin(); It != mTextureRequests.end();)
|
||||
{
|
||||
if (It->second->Running)
|
||||
if (It->second->AwaitingCompletion)
|
||||
++It;
|
||||
else
|
||||
{
|
||||
@@ -1562,7 +1559,7 @@ void lcAssetLoader::CancelAndDrain()
|
||||
|
||||
for (SynthRequestMap::iterator It = mSynthRequests.begin(); It != mSynthRequests.end();)
|
||||
{
|
||||
if (It->second->Running)
|
||||
if (It->second->AwaitingCompletion)
|
||||
{
|
||||
It->second->Cancelled.store(true, std::memory_order_relaxed);
|
||||
++It;
|
||||
@@ -1583,7 +1580,7 @@ void lcAssetLoader::CancelAndDrain()
|
||||
for (const std::shared_ptr<TextureRequest>& RequestedTexture : CancelledTextures)
|
||||
mLibrary->ReleaseTexture(RequestedTexture->Texture);
|
||||
|
||||
WaitForLoadQueue();
|
||||
WaitForAllWork();
|
||||
|
||||
while (!mPieceNotifications.empty())
|
||||
{
|
||||
|
||||
+25
-22
@@ -60,25 +60,29 @@ public:
|
||||
// Load a piece the library has already acquired for the caller. Adds no consumer reference.
|
||||
// Low and Normal return immediately; true does not mean the piece is ready yet.
|
||||
// Blocking promotes urgent work, waits until loading settles, and returns whether it succeeded.
|
||||
bool LoadPieceInfo(PieceInfo* Info, lcPieceLoadPriority LoadPriority);
|
||||
|
||||
// Build this instance's generated mesh from its current control points in the background.
|
||||
// Cancel any older request and keep the previous mesh visible while the replacement is built.
|
||||
void QueueSynthMesh(lcPiece* Piece);
|
||||
bool RequestPieceLoad(PieceInfo* Info, lcPieceLoadPriority LoadPriority);
|
||||
|
||||
// Start or promote loading, then wait and returns true if all pieces are ready. Adds no consumer references.
|
||||
// Waits for these identities only, without traversing container children or generated meshes.
|
||||
bool WaitForPieces(const std::vector<PieceInfo*>& Pieces);
|
||||
|
||||
// Called when the last consumer releases the piece. Cancels queued work;
|
||||
// running work finishes privately and is discarded if the piece is still unused.
|
||||
void CancelPieceLoad(PieceInfo* Info);
|
||||
|
||||
// Build this instance's generated mesh from its current control points in the background.
|
||||
// Cancel any older request and keep the previous mesh visible while the replacement is built.
|
||||
void RequestSynthMesh(lcPiece* Piece);
|
||||
|
||||
// Promote and wait for queued generations. Returns true if every required generated mesh is current.
|
||||
// Call QueueSynthMesh() to start a generation; the caller keeps the instances alive through the wait.
|
||||
// Call RequestSynthMesh() to start a generation; the caller keeps the instances alive through the wait.
|
||||
bool WaitForSynthMeshes(const std::vector<lcPiece*>& Pieces);
|
||||
|
||||
// Start or promote decoding as needed, then wait through upload and retries. The caller retains the texture.
|
||||
bool WaitForTexture(lcTexture* Texture);
|
||||
|
||||
// Drain all pending work, including unrelated assets. Completion does not imply success.
|
||||
void WaitForLoadQueue();
|
||||
void WaitForAllWork();
|
||||
|
||||
// True while piece, texture, or generated-mesh requests or worker completions remain unsettled.
|
||||
// Includes paused work and upload retries; deferred notifications alone do not count.
|
||||
@@ -90,9 +94,8 @@ public:
|
||||
|
||||
void RebuildModelPiece(PieceInfo* Info);
|
||||
void InvalidatePiece(PieceInfo* Info);
|
||||
void OnConsumerReleased(PieceInfo* Info);
|
||||
void CancelSynthMesh(lcPiece* Piece);
|
||||
void ReloadSynthMeshes();
|
||||
void RebuildSynthMeshes();
|
||||
void PauseQueuedWork();
|
||||
void ResumeQueuedWork();
|
||||
|
||||
@@ -105,7 +108,7 @@ private:
|
||||
lcPieceSourceSnapshot Source;
|
||||
lcPieceLoadPriority LoadPriority;
|
||||
qint64 EnqueuedAt;
|
||||
bool Running = false; // A worker phase is outstanding, including its completion.
|
||||
bool AwaitingCompletion = false; // A worker phase is outstanding, including its completion.
|
||||
bool Obsolete = false; // Its result must not publish, even if the build succeeds.
|
||||
bool Terminal = false; // The wait has settled; this does not imply success.
|
||||
bool Succeeded = false; // Published successfully, including valid empty geometry.
|
||||
@@ -125,7 +128,7 @@ private:
|
||||
lcFileSource Source;
|
||||
lcPieceLoadPriority LoadPriority;
|
||||
qint64 EnqueuedAt;
|
||||
bool Running = false;
|
||||
bool AwaitingCompletion = false;
|
||||
int UploadAttempts = 0;
|
||||
qint64 RetryAt = 0;
|
||||
};
|
||||
@@ -139,7 +142,7 @@ private:
|
||||
std::vector<lcPieceControlPoint> ControlPoints;
|
||||
lcPieceLoadPriority LoadPriority;
|
||||
qint64 EnqueuedAt;
|
||||
bool Running = false;
|
||||
bool AwaitingCompletion = false;
|
||||
std::atomic_bool Cancelled = false;
|
||||
bool Terminal = false;
|
||||
std::unique_ptr<lcLibraryMeshData> MeshData; // Present when the next worker phase is mesh conversion.
|
||||
@@ -157,7 +160,7 @@ private:
|
||||
struct Completion
|
||||
{
|
||||
std::shared_ptr<PieceRequest> RequestedPiece;
|
||||
lcPieceBuildResult Result;
|
||||
lcPieceBuildResult PieceResult;
|
||||
std::shared_ptr<TextureRequest> RequestedTexture;
|
||||
lcTextureBuildResult TextureResult;
|
||||
std::shared_ptr<SynthRequest> RequestedSynth;
|
||||
@@ -179,11 +182,11 @@ private:
|
||||
PieceInfo* Info;
|
||||
};
|
||||
|
||||
// Enqueue and promote requests. Workers read copied sources and private build data.
|
||||
// Queue and promote requests. Workers read copied sources and private build data.
|
||||
// Acquires mQueueMutex internally; callers must not already hold it.
|
||||
void EnqueuePiece(PieceInfo* Info, lcPieceLoadPriority LoadPriority);
|
||||
void QueuePiece(PieceInfo* Info, lcPieceLoadPriority LoadPriority);
|
||||
// Caller holds mQueueMutex.
|
||||
void PromoteRequestPriorityLocked(const std::shared_ptr<PieceRequest>& RequestedPiece, lcPieceLoadPriority LoadPriority);
|
||||
void PromotePiecePriorityLocked(const std::shared_ptr<PieceRequest>& RequestedPiece, lcPieceLoadPriority LoadPriority);
|
||||
void QueueTexture(lcTexture* Texture, lcPieceLoadPriority LoadPriority);
|
||||
// Caller holds mQueueMutex.
|
||||
void StartWorkersLocked();
|
||||
@@ -191,16 +194,16 @@ private:
|
||||
|
||||
// UI-thread completion handling: colors, conversion, texture dependencies, publication.
|
||||
bool ProcessCompletions();
|
||||
void CompletePiece(Completion& Completed);
|
||||
void CompleteSynth(Completion& Completed);
|
||||
void CompleteTexture(Completion& Completed);
|
||||
void ProcessPieceCompletion(Completion& Completed);
|
||||
void ProcessSynthCompletion(Completion& Completed);
|
||||
void ProcessTextureCompletion(Completion& Completed);
|
||||
static void ResolveMeshColors(lcLibraryMeshData& MeshData, std::vector<bool>& ColorTranslucency, int& DefaultColorIndex);
|
||||
bool ResolveAndQueueMeshTextures(lcMesh& Mesh, const std::vector<QString>& SearchDirectories,
|
||||
const std::map<QString, std::shared_ptr<const lcEmbeddedData>>& EmbeddedData, lcPieceLoadPriority LoadPriority, QString& Error);
|
||||
static bool MeshTexturesSettled(const lcMesh& Mesh, QString& Error);
|
||||
static QString TextureFailureMessage(const lcTexture* Texture);
|
||||
void UploadTextureRequest(const std::shared_ptr<TextureRequest>& RequestedTexture);
|
||||
void FinishTextureRequest(const std::shared_ptr<TextureRequest>& RequestedTexture);
|
||||
void FinishTexture(const std::shared_ptr<TextureRequest>& RequestedTexture);
|
||||
void FinishPiecesWithSettledTextures();
|
||||
void FinishSynthsWithSettledTextures();
|
||||
void FinishPiece(const std::shared_ptr<PieceRequest>& RequestedPiece);
|
||||
@@ -211,7 +214,7 @@ private:
|
||||
bool event(QEvent* Event) override;
|
||||
// Caller holds mQueueMutex; the condition wait releases it and reacquires it on return.
|
||||
void WaitForResultsLocked();
|
||||
bool WaitForRequest(PieceInfo* Info);
|
||||
bool WaitForPieceRequest(PieceInfo* Info);
|
||||
|
||||
void CancelUnusedTextureRequests();
|
||||
void CancelAndDrain();
|
||||
@@ -225,7 +228,7 @@ private:
|
||||
TextureRequestMap mTextureRequests;
|
||||
SynthRequestMap mSynthRequests;
|
||||
// UI-thread diagnostics and instance tracking; these do not own the pieces.
|
||||
std::unordered_map<const lcPiece*, QString> mFailedSynthErrors;
|
||||
std::unordered_map<const lcPiece*, QString> mSynthErrors;
|
||||
std::unordered_set<lcPiece*> mSynthPieces;
|
||||
// Pending worker phases remain here while paused; mPaused prevents dispatch.
|
||||
std::deque<std::shared_ptr<PieceRequest>> mPieceQueue;
|
||||
|
||||
+10
-15
@@ -1644,13 +1644,13 @@ bool lcPiecesLibrary::SaveArchiveCacheIndex(const QString& FileName)
|
||||
return WriteArchiveCacheFile(FileName, IndexFile);
|
||||
}
|
||||
|
||||
bool lcPiecesLibrary::LoadPieceInfo(PieceInfo* Info, lcPieceLoadPriority LoadPriority)
|
||||
bool lcPiecesLibrary::RequestPieceLoad(PieceInfo* Info, lcPieceLoadPriority LoadPriority)
|
||||
{
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
AddPieceReference(Info);
|
||||
|
||||
return mAssetLoader->LoadPieceInfo(Info, LoadPriority);
|
||||
return mAssetLoader->RequestPieceLoad(Info, LoadPriority);
|
||||
}
|
||||
|
||||
void lcPiecesLibrary::NotifyConsumersChanged()
|
||||
@@ -1681,9 +1681,9 @@ bool lcPiecesLibrary::WaitForPieces(const std::vector<PieceInfo*>& Pieces)
|
||||
return mAssetLoader->WaitForPieces(Pieces);
|
||||
}
|
||||
|
||||
void lcPiecesLibrary::QueueSynthMesh(lcPiece* Piece)
|
||||
void lcPiecesLibrary::RequestSynthMesh(lcPiece* Piece)
|
||||
{
|
||||
mAssetLoader->QueueSynthMesh(Piece);
|
||||
mAssetLoader->RequestSynthMesh(Piece);
|
||||
}
|
||||
|
||||
void lcPiecesLibrary::CancelSynthMesh(lcPiece* Piece)
|
||||
@@ -1734,8 +1734,8 @@ void lcPiecesLibrary::ReleasePieceInfo(PieceInfo* Info)
|
||||
UnloadPieceInfo(Info);
|
||||
}
|
||||
|
||||
if (Remaining != 0 && mAssetLoader)
|
||||
mAssetLoader->OnConsumerReleased(Info);
|
||||
if (Remaining == 1 && mAssetLoader)
|
||||
mAssetLoader->CancelPieceLoad(Info);
|
||||
}
|
||||
|
||||
void lcPiecesLibrary::AddPieceReference(PieceInfo* Info)
|
||||
@@ -1786,11 +1786,6 @@ void lcPiecesLibrary::ClearPieceLoadError(const PieceInfo* Info)
|
||||
mFailedPartErrors.erase(Info);
|
||||
}
|
||||
|
||||
void lcPiecesLibrary::WaitForLoadQueue()
|
||||
{
|
||||
mAssetLoader->WaitForLoadQueue();
|
||||
}
|
||||
|
||||
lcPieceSourceSnapshot lcPiecesLibrary::SnapshotPieceSource(const PieceInfo* Info) const
|
||||
{
|
||||
lcPieceSourceSnapshot Source;
|
||||
@@ -2309,12 +2304,12 @@ void lcPiecesLibrary::UpdateStudStyleAndColors(lcStudStyle StudStyle, bool StudC
|
||||
Info->ReleaseMesh();
|
||||
Info->mState = lcPieceInfoState::Unloaded;
|
||||
|
||||
mAssetLoader->LoadPieceInfo(Info, lcPieceLoadPriority::Low);
|
||||
mAssetLoader->RequestPieceLoad(Info, lcPieceLoadPriority::Low);
|
||||
}
|
||||
else if (!Info->IsProject())
|
||||
{
|
||||
Info->Unload();
|
||||
mAssetLoader->LoadPieceInfo(Info, lcPieceLoadPriority::Low);
|
||||
mAssetLoader->RequestPieceLoad(Info, lcPieceLoadPriority::Low);
|
||||
}
|
||||
|
||||
mBuffersDirty = true;
|
||||
@@ -2328,11 +2323,11 @@ void lcPiecesLibrary::UpdateStudStyleAndColors(lcStudStyle StudStyle, bool StudC
|
||||
|
||||
mLoadMutex.unlock();
|
||||
|
||||
mAssetLoader->ReloadSynthMeshes();
|
||||
mAssetLoader->RebuildSynthMeshes();
|
||||
|
||||
mAssetLoader->ResumeQueuedWork();
|
||||
|
||||
WaitForLoadQueue();
|
||||
mAssetLoader->WaitForAllWork();
|
||||
}
|
||||
|
||||
bool lcPiecesLibrary::IsPrimitive(const char* Name) const
|
||||
|
||||
+4
-6
@@ -75,7 +75,7 @@ enum class lcPrimitiveState
|
||||
Loaded
|
||||
};
|
||||
|
||||
// Scheduling urgency. LoadPieceInfo() also waits when Blocking is requested.
|
||||
// Scheduling urgency. RequestPieceLoad() also waits when Blocking is requested.
|
||||
// Queued requests only promote and keep their priority until completion or cancellation.
|
||||
enum class lcPieceLoadPriority
|
||||
{
|
||||
@@ -191,7 +191,7 @@ public:
|
||||
// Asset scheduling, waits, invalidation, and consumer releases below run on the UI thread.
|
||||
// Acquires one reference even on failure; always pair with ReleasePieceInfo().
|
||||
// Blocking waits and reports success; Low and Normal return immediately. See docs/asset-loading.md.
|
||||
bool LoadPieceInfo(PieceInfo* Info, lcPieceLoadPriority LoadPriority);
|
||||
bool RequestPieceLoad(PieceInfo* Info, lcPieceLoadPriority LoadPriority);
|
||||
void NotifyConsumersChanged();
|
||||
// Start or promote loading, then wait. Adds no consumer references.
|
||||
// Returns false for failed or cancelled pieces.
|
||||
@@ -200,10 +200,10 @@ public:
|
||||
// Also settles container children/synths and updates bounds; caller retains the identity.
|
||||
bool EnsurePieceAssetsReady(PieceInfo* Info);
|
||||
// Replaces any pending generation for this instance; snapshots control points for workers.
|
||||
void QueueSynthMesh(lcPiece* Piece);
|
||||
void RequestSynthMesh(lcPiece* Piece);
|
||||
void CancelSynthMesh(lcPiece* Piece);
|
||||
// Promote and wait for queued generations; false means missing or outdated generated geometry.
|
||||
// Call QueueSynthMesh() to start a generation; keep the instances alive through the wait.
|
||||
// Call RequestSynthMesh() to start a generation; keep the instances alive through the wait.
|
||||
bool WaitForSynthMeshes(const std::vector<lcPiece*>& Pieces);
|
||||
QString GetSynthMeshError(const lcPiece* Piece) const;
|
||||
void RebuildModelPiece(PieceInfo* Info);
|
||||
@@ -225,8 +225,6 @@ public:
|
||||
// Worker build service: returns private CPU data/errors without publishing asset state.
|
||||
lcPieceBuildResult BuildPieceData(const lcPieceSourceSnapshot& Source);
|
||||
void SaveBuiltPieceCache(const lcPieceSourceSnapshot& Source, lcMesh& Mesh);
|
||||
// UI-thread drain of all work, including unrelated assets; not a success check.
|
||||
void WaitForLoadQueue();
|
||||
|
||||
// UI-thread lookup and upload wait; returns a ready reference or nullptr on failure.
|
||||
// Release a returned reference with ReleaseTexture().
|
||||
|
||||
@@ -2024,7 +2024,7 @@ void lcMainWindow::SetCurrentPieceInfo(PieceInfo* Info)
|
||||
mCurrentPieceInfo = Info;
|
||||
|
||||
if (mCurrentPieceInfo)
|
||||
Library->LoadPieceInfo(mCurrentPieceInfo, lcPieceLoadPriority::Normal);
|
||||
Library->RequestPieceLoad(mCurrentPieceInfo, lcPieceLoadPriority::Normal);
|
||||
}
|
||||
|
||||
lcVector3 lcMainWindow::GetTransformAmount()
|
||||
|
||||
+2
-2
@@ -393,7 +393,7 @@ void lcModel::CreatePieceInfo(Project* Project)
|
||||
// until its source lines have been parsed and QueueMeshBuild() runs.
|
||||
if (!Project->DefersModelMeshRequests())
|
||||
{
|
||||
Library->LoadPieceInfo(mPieceInfo, mIsPreview ? lcPieceLoadPriority::Normal : lcPieceLoadPriority::Blocking);
|
||||
Library->RequestPieceLoad(mPieceInfo, mIsPreview ? lcPieceLoadPriority::Normal : lcPieceLoadPriority::Blocking);
|
||||
Library->ReleasePieceInfo(mPieceInfo);
|
||||
}
|
||||
|
||||
@@ -3418,7 +3418,7 @@ void lcModel::SetPreviewInsertPieceInfo(std::vector<lcInsertPieceInfo>&& Preview
|
||||
|
||||
for (lcInsertPieceInfo& InfoTransform : PreviewInsertPieceInfo)
|
||||
{
|
||||
Library->LoadPieceInfo(InfoTransform.Info, lcPieceLoadPriority::Normal);
|
||||
Library->RequestPieceLoad(InfoTransform.Info, lcPieceLoadPriority::Normal);
|
||||
Required.push_back(InfoTransform.Info);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ void lcPreviewDockWidget::RefreshModel(const lcModel* Model)
|
||||
if (Info->mState != lcPieceInfoState::Unloaded)
|
||||
continue;
|
||||
|
||||
Library->LoadPieceInfo(Info, lcPieceLoadPriority::Normal);
|
||||
Library->RequestPieceLoad(Info, lcPieceLoadPriority::Normal);
|
||||
Library->ReleasePieceInfo(Info);
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ bool lcPreview::SetCurrentPiece(PieceInfo* Info, int ColorCode)
|
||||
}
|
||||
|
||||
lcPiecesLibrary* Library = lcGetPiecesLibrary();
|
||||
bool Ready = Library->LoadPieceInfo(Info, lcPieceLoadPriority::Blocking);
|
||||
bool Ready = Library->RequestPieceLoad(Info, lcPieceLoadPriority::Blocking);
|
||||
|
||||
if (Ready && Info->IsModel())
|
||||
Ready = static_cast<bool>(Info->GetModel()->EnsureAssetsReady());
|
||||
|
||||
@@ -136,7 +136,7 @@ void lcThumbnailManager::RefreshRequiredPieces(lcPartThumbnail& Thumbnail)
|
||||
for (PieceInfo* Info : Required)
|
||||
{
|
||||
if (Previous.erase(Info) == 0)
|
||||
mLibrary->LoadPieceInfo(Info, lcPieceLoadPriority::Low);
|
||||
mLibrary->RequestPieceLoad(Info, lcPieceLoadPriority::Low);
|
||||
}
|
||||
|
||||
for (PieceInfo* Info : Previous)
|
||||
|
||||
+2
-2
@@ -215,7 +215,7 @@ void MinifigWizard::LoadTemplate(const QString& TemplateName)
|
||||
mMinifig.Parts[PartIndex] = Info;
|
||||
|
||||
if (Info)
|
||||
Library->LoadPieceInfo(Info, lcPieceLoadPriority::Normal);
|
||||
Library->RequestPieceLoad(Info, lcPieceLoadPriority::Normal);
|
||||
}
|
||||
|
||||
std::vector<PieceInfo*> Required;
|
||||
@@ -513,7 +513,7 @@ void MinifigWizard::SetPieceInfo(int Type, PieceInfo* Info)
|
||||
mMinifig.Parts[Type] = Info;
|
||||
|
||||
if (mMinifig.Parts[Type])
|
||||
Library->LoadPieceInfo(mMinifig.Parts[Type], lcPieceLoadPriority::Blocking);
|
||||
Library->RequestPieceLoad(mMinifig.Parts[Type], lcPieceLoadPriority::Blocking);
|
||||
|
||||
Calculate();
|
||||
}
|
||||
|
||||
+2
-2
@@ -86,7 +86,7 @@ void lcPiece::SetPieceInfo(PieceInfo* Info, const QString& ID, bool Wait, bool U
|
||||
|
||||
mPieceInfo = Info;
|
||||
if (mPieceInfo)
|
||||
Library->LoadPieceInfo(mPieceInfo, Wait ? lcPieceLoadPriority::Blocking : lcPieceLoadPriority::Normal);
|
||||
Library->RequestPieceLoad(mPieceInfo, Wait ? lcPieceLoadPriority::Blocking : lcPieceLoadPriority::Normal);
|
||||
|
||||
if (!ID.isEmpty())
|
||||
mID = ID;
|
||||
@@ -1564,7 +1564,7 @@ void lcPiece::UpdateMesh()
|
||||
mSynthPending = mPieceInfo && mPieceInfo->GetSynthInfo();
|
||||
|
||||
if (mSynthPending)
|
||||
lcGetPiecesLibrary()->QueueSynthMesh(this);
|
||||
lcGetPiecesLibrary()->RequestSynthMesh(this);
|
||||
else
|
||||
{
|
||||
delete mMesh;
|
||||
|
||||
+12
-12
@@ -234,7 +234,7 @@ worker phases, so a part can return to `Queued` between phases. Invalidation or
|
||||
unloading resets readiness; cancellation and stale-result disposal also have
|
||||
request-level terminal flags, independent of the published asset state.
|
||||
Queued piece and synth requests use the presence of `MeshData` to select
|
||||
conversion; an empty pointer selects parsing or generation. `Running` tracks
|
||||
conversion; an empty pointer selects parsing or generation. `AwaitingCompletion` tracks
|
||||
outstanding worker phases through completion processing.
|
||||
|
||||
A part becomes `Loaded` after its private mesh is committed and all declared
|
||||
@@ -280,7 +280,7 @@ caller omits unavailable geometry, while the loading indicator exposes errors.
|
||||
|
||||
The loader implementation follows this lifecycle: request acquisition and queueing,
|
||||
worker scheduling and `RunWorker()`, UI-thread `ProcessCompletions()` dispatch to
|
||||
`CompletePiece()`, `CompleteSynth()`, or `CompleteTexture()`, dependency settlement
|
||||
`ProcessPieceCompletion()`, `ProcessSynthCompletion()`, or `ProcessTextureCompletion()`, dependency settlement
|
||||
and publication, then deferred notifications. Readiness waits follow these paths;
|
||||
invalidation, pause/resume, and shutdown are grouped at the end of the file.
|
||||
Piece and synth handlers share color preparation and texture dependency checks,
|
||||
@@ -292,7 +292,7 @@ sequenceDiagram
|
||||
participant Library as Library
|
||||
participant Loader as Loader / UI thread
|
||||
participant Worker as Qt worker
|
||||
Caller->>Library: LoadPieceInfo(Info, LoadPriority)
|
||||
Caller->>Library: RequestPieceLoad(Info, LoadPriority)
|
||||
Library->>Library: Acquire consumer reference
|
||||
Library->>Loader: Queue/promote
|
||||
Loader->>Worker: Immutable source snapshot
|
||||
@@ -340,7 +340,7 @@ buffer upload is not part of asset readiness.
|
||||
|
||||
## References, cancellation, and generated geometry
|
||||
|
||||
`LoadPieceInfo()` acquires one reference even if loading fails. Always pair it
|
||||
`RequestPieceLoad()` acquires one reference even if loading fails. Always pair it
|
||||
with `ReleasePieceInfo()`. Its asynchronous return value means the call did not
|
||||
wait, not that the asset loaded. `AddPieceReference()` retains an identity without
|
||||
starting work. `WaitForPieces()` deduplicates its input without acquiring consumer
|
||||
@@ -369,7 +369,7 @@ retained; drawing does not retry them. Explicit invalidation or unloading can
|
||||
permit a later request.
|
||||
|
||||
Synth meshes are **per `lcPiece` instance**, separate from the shared library
|
||||
mesh. `QueueSynthMesh()` copies control points and retains the shared synth
|
||||
mesh. `RequestSynthMesh()` copies control points and retains the shared synth
|
||||
definition. Replacing or deleting the piece cancels its old request; workers
|
||||
check an atomic cancellation flag and stale results cannot replace newer meshes.
|
||||
Initial generation displays a cube. Control-point edits retain the previous
|
||||
@@ -393,7 +393,7 @@ Priorities only promote: `Low < Normal < Blocking`. Ordinary thumbnail
|
||||
requests start Low; asynchronous model pieces and generated meshes start
|
||||
Normal, regardless of step. Synchronous waits promote their required requests
|
||||
and pending texture dependencies to Blocking. The same `lcPieceLoadPriority` enum
|
||||
is used at the loading entry point and throughout the scheduler. `LoadPieceInfo()`
|
||||
is used at the loading entry point and throughout the scheduler. `RequestPieceLoad()`
|
||||
waits only for Blocking; Low and Normal return immediately. Internal queueing
|
||||
uses priority solely to rank work and does not wait. Shared textures retain the highest
|
||||
promotion received from any parent or direct wait. There is no consumer identity
|
||||
@@ -412,11 +412,11 @@ requirements and does not expand model containers itself. Callers retain every
|
||||
required identity through the wait; it does not acquire consumer references.
|
||||
`WaitForSynthMeshes()`
|
||||
promotes and waits for queued generations of the specified instances; callers
|
||||
start generations with `QueueSynthMesh()`. The loader's `WaitForTexture()` starts
|
||||
start generations with `RequestSynthMesh()`. The loader's `WaitForTexture()` starts
|
||||
or promotes decoding as needed and waits through upload and retries.
|
||||
`lcModel::WaitForAssets()` combines recursive part and synth waits and updates
|
||||
bounds, but deliberately ignores their failure results. `EnsureAssetsReady()`
|
||||
adds strict failure reporting. `WaitForLoadQueue()` drains all pending work and
|
||||
adds strict failure reporting. The loader's `WaitForAllWork()` drains all pending work and
|
||||
workers, including unrelated assets; it is not a scoped success check.
|
||||
|
||||
### Choosing an API
|
||||
@@ -424,15 +424,15 @@ workers, including unrelated assets; it is not a scoped success check.
|
||||
| Need | API and lifetime contract |
|
||||
| --- | --- |
|
||||
| Resolve a name | `FindPiece()` with the intended project and explicit `CreateMissing` / `SearchProjectFolder` arguments. The returned pointer is borrowed; retain it before keeping it beyond its owner's lifetime. |
|
||||
| Retain and start ordinary asynchronous work | `LoadPieceInfo()` with `lcPieceLoadPriority::Low` for background work or `Normal` for model/view work. Pair every acquisition with `ReleasePieceInfo()`, including failures. |
|
||||
| Retain and synchronously load one identity | `LoadPieceInfo()` with `lcPieceLoadPriority::Blocking`; check its return value and pair the acquisition with `ReleasePieceInfo()`, including failures. |
|
||||
| Retain and start ordinary asynchronous work | `RequestPieceLoad()` with `lcPieceLoadPriority::Low` for background work or `Normal` for model/view work. Pair every acquisition with `ReleasePieceInfo()`, including failures. |
|
||||
| Retain and synchronously load one identity | `RequestPieceLoad()` with `lcPieceLoadPriority::Blocking`; check its return value and pair the acquisition with `ReleasePieceInfo()`, including failures. |
|
||||
| Retain without starting work | `AddPieceReference()`, paired with `ReleasePieceInfo()`. This does not make geometry ready. |
|
||||
| Wait for an explicit part set | `WaitForPieces()` (use `{ Info }` for one identity), check the boolean for strict consumers. Retain every identity and its owner throughout the wait; this call acquires no consumer references. |
|
||||
| Wait for one identity and its container geometry | `EnsurePieceAssetsReady()` settles the identity, then delegates recursive children, synths, and bounds to the model/project API. Retain the identity and its owner throughout. |
|
||||
| Wait for a model, including nested synths | `WaitForAssets()` for permissive output; `EnsureAssetsReady()` for strict preview-style failure reporting. Keep the model and its pieces alive throughout. |
|
||||
| Replace/wait for generated geometry | `QueueSynthMesh()` / `WaitForSynthMeshes()`. Supply live `lcPiece` instances; a shared part mesh or a retained previous generated mesh is not readiness for the replacement. |
|
||||
| Replace/wait for generated geometry | `RequestSynthMesh()` / `WaitForSynthMeshes()`. Supply live `lcPiece` instances; a shared part mesh or a retained previous generated mesh is not readiness for the replacement. |
|
||||
| Acquire a texture directly | `FindTexture()` waits for readiness and returns an acquired texture or null. `FindTextureDeferred()` acquires without waiting. The loader handles GPU upload readiness internally. Retain the texture during a direct wait and pair acquisition with `ReleaseTexture()`. |
|
||||
| Synchronize an entire library operation | `WaitForLoadQueue()`; reserve this for operations that truly need all work drained, such as settings changes. Ordinary previews must use scoped waits. |
|
||||
| Synchronize an entire library operation | The library calls the loader's `WaitForAllWork()` internally for settings changes. Ordinary previews must use scoped waits. |
|
||||
|
||||
Scoped waits may process unrelated completions while pumping publication, but
|
||||
their completion condition depends only on the requested assets. They cannot
|
||||
|
||||
Reference in new issue
Block a user