void BackgroundLoader::ThreadFunction() { while (shouldRun_) { backgroundLoadMutex_.Acquire(); // Search for a queued resource that has not been loaded yet HashMap<Pair<StringHash, StringHash>, BackgroundLoadItem>::Iterator i = backgroundLoadQueue_.Begin(); while (i != backgroundLoadQueue_.End()) { if (i->second_.resource_->GetAsyncLoadState() == ASYNC_QUEUED) break; else ++i; } if (i == backgroundLoadQueue_.End()) { // No resources to load found backgroundLoadMutex_.Release(); Time::Sleep(5); } else { BackgroundLoadItem& item = i->second_; Resource* resource = item.resource_; // We can be sure that the item is not removed from the queue as long as it is in the // "queued" or "loading" state backgroundLoadMutex_.Release(); bool success = false; SharedPtr<File> file = owner_->GetFile(resource->GetName(), item.sendEventOnFailure_); if (file) { resource->SetAsyncLoadState(ASYNC_LOADING); success = resource->BeginLoad(*file); } // Process dependencies now // Need to lock the queue again when manipulating other entries Pair<StringHash, StringHash> key = MakePair(resource->GetType(), resource->GetNameHash()); backgroundLoadMutex_.Acquire(); if (item.dependents_.Size()) { for (HashSet<Pair<StringHash, StringHash> >::Iterator i = item.dependents_.Begin(); i != item.dependents_.End(); ++i) { HashMap<Pair<StringHash, StringHash>, BackgroundLoadItem>::Iterator j = backgroundLoadQueue_.Find(*i); if (j != backgroundLoadQueue_.End()) j->second_.dependencies_.Erase(key); } item.dependents_.Clear(); } resource->SetAsyncLoadState(success ? ASYNC_SUCCESS : ASYNC_FAIL); backgroundLoadMutex_.Release(); } } }
void BackgroundLoader::FinishBackgroundLoading(BackgroundLoadItem& item) { Resource* resource = item.resource_; bool success = resource->GetAsyncLoadState() == ASYNC_SUCCESS; // If BeginLoad() phase was successful, call EndLoad() and get the final success/failure result if (success) { #ifdef URHO3D_PROFILING String profileBlockName("Finish" + resource->GetTypeName()); Profiler* profiler = owner_->GetSubsystem<Profiler>(); if (profiler) profiler->BeginBlock(profileBlockName.CString()); #endif LOGDEBUG("Finishing background loaded resource " + resource->GetName()); success = resource->EndLoad(); #ifdef URHO3D_PROFILING if (profiler) profiler->EndBlock(); #endif } resource->SetAsyncLoadState(ASYNC_DONE); if (!success && item.sendEventOnFailure_) { using namespace LoadFailed; VariantMap& eventData = owner_->GetEventDataMap(); eventData[P_RESOURCENAME] = resource->GetName(); owner_->SendEvent(E_LOADFAILED, eventData); } // Send event, either success or failure { using namespace ResourceBackgroundLoaded; VariantMap& eventData = owner_->GetEventDataMap(); eventData[P_RESOURCENAME] = resource->GetName(); eventData[P_SUCCESS] = success; eventData[P_RESOURCE] = resource; owner_->SendEvent(E_RESOURCEBACKGROUNDLOADED, eventData); } // Store to the cache; use same mechanism as for manual resources if (success || owner_->GetReturnFailedResources()) owner_->AddManualResource(resource); }
void BackgroundLoader::FinishBackgroundLoading(BackgroundLoadItem& item) { Resource* resource = item.resource_; bool success = resource->GetAsyncLoadState() == ASYNC_SUCCESS; // If BeginLoad() phase was successful, call EndLoad() and get the final success/failure result if (success) { URHO3D_PROFILE(ea::string("Finish" + resource->GetTypeName()).c_str()); URHO3D_LOGDEBUG("Finishing background loaded resource " + resource->GetName()); success = resource->EndLoad(); } resource->SetAsyncLoadState(ASYNC_DONE); if (!success && item.sendEventOnFailure_) { using namespace LoadFailed; VariantMap& eventData = owner_->GetEventDataMap(); eventData[P_RESOURCENAME] = resource->GetName(); owner_->SendEvent(E_LOADFAILED, eventData); } // Store to the cache just before sending the event; use same mechanism as for manual resources if (success || owner_->GetReturnFailedResources()) owner_->AddManualResource(resource); // Send event, either success or failure { using namespace ResourceBackgroundLoaded; VariantMap& eventData = owner_->GetEventDataMap(); eventData[P_RESOURCENAME] = resource->GetName(); eventData[P_SUCCESS] = success; eventData[P_RESOURCE] = resource; owner_->SendEvent(E_RESOURCEBACKGROUNDLOADED, eventData); } }