void D3D9TimerQuery::finalize() { mFinalized = true; if (!isQueryValid()) { mTimeDelta = 0.0f; return; } BOOL disjoint; mDisjointQuery->GetData(&disjoint, sizeof(BOOL), 0); if(!disjoint) { UINT64 frequency; mFreqQuery->GetData(&frequency, sizeof(UINT64), 0); UINT64 timeStart, timeEnd; mBeginQuery->GetData(&timeStart, sizeof(UINT64), 0); mEndQuery->GetData(&timeEnd, sizeof(UINT64), 0); UINT64 delta = timeEnd - timeStart; mTimeDelta = (delta/(float)frequency) * 1000.0f; } else { LOGWRN_VERBOSE("Unrealiable GPU timer query detected."); } }
HResource Resources::loadAsync(const Path& filePath, bool loadDependencies, bool keepInternalReference) { if (!FileSystem::isFile(filePath)) { LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist."); return HResource(); } String uuid; bool foundUUID = getUUIDFromFilePath(filePath, uuid); if (!foundUUID) uuid = UUIDGenerator::generateRandom(); return loadInternal(uuid, filePath, false, loadDependencies, keepInternalReference); }
void D3D11TimerQuery::finalize() { UINT64 timeStart, timeEnd; mContext->GetData(mBeginQuery, &timeStart, sizeof(timeStart), 0); mContext->GetData(mEndQuery, &timeEnd, sizeof(timeEnd), 0); D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData; mContext->GetData(mDisjointQuery, &disjointData, sizeof(disjointData), 0); float time = 0.0f; if(disjointData.Disjoint == FALSE) { float frequency = static_cast<float>(disjointData.Frequency); UINT64 delta = timeEnd - timeStart; mTimeDelta = (delta / (float)frequency) * 1000.0f; } else { LOGWRN_VERBOSE("Unrealiable GPU timer query detected."); } }
HResource Resources::loadInternal(const String& UUID, const Path& filePath, bool synchronous, bool loadDependencies, bool keepInternalReference) { HResource outputResource; bool alreadyLoading = false; bool loadInProgress = false; { // Check if resource is already being loaded on a worker thread Lock inProgressLock(mInProgressResourcesMutex); auto iterFind2 = mInProgressResources.find(UUID); if (iterFind2 != mInProgressResources.end()) { LoadedResourceData& resData = iterFind2->second->resData; outputResource = resData.resource.lock(); if (keepInternalReference) { resData.numInternalRefs++; outputResource.addInternalRef(); } alreadyLoading = true; loadInProgress = true; } // Previously being loaded as async but now we want it synced, so we wait if (loadInProgress && synchronous) outputResource.blockUntilLoaded(); if (!alreadyLoading) { Lock loadedLock(mLoadedResourceMutex); auto iterFind = mLoadedResources.find(UUID); if (iterFind != mLoadedResources.end()) // Resource is already loaded { LoadedResourceData& resData = iterFind->second; outputResource = resData.resource.lock(); if (keepInternalReference) { resData.numInternalRefs++; outputResource.addInternalRef(); } alreadyLoading = true; } } } // Not loaded and not in progress, start loading of new resource // (or if already loaded or in progress, load any dependencies) if (!alreadyLoading) { // Check if the handle already exists Lock lock(mLoadedResourceMutex); auto iterFind = mHandles.find(UUID); if (iterFind != mHandles.end()) outputResource = iterFind->second.lock(); else { outputResource = HResource(UUID); mHandles[UUID] = outputResource.getWeak(); } } // We have nowhere to load from, warn and complete load if a file path was provided, // otherwise pass through as we might just want to load from memory. if (filePath.isEmpty()) { if (!alreadyLoading) { LOGWRN_VERBOSE("Cannot load resource. Resource with UUID '" + UUID + "' doesn't exist."); // Complete the load as that the depedency counter is properly reduced, in case this // is a dependency of some other resource. loadComplete(outputResource); return outputResource; } } else if (!FileSystem::isFile(filePath)) { LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist."); // Complete the load as that the depedency counter is properly reduced, in case this // is a dependency of some other resource. loadComplete(outputResource); assert(!loadInProgress); // Resource already being loaded but we can't find its path now? return outputResource; } // Load dependency data if a file path is provided SPtr<SavedResourceData> savedResourceData; if (!filePath.isEmpty()) { FileDecoder fs(filePath); savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode()); } // If already loading keep the old load operation active, otherwise create a new one if (!alreadyLoading) { { Lock lock(mInProgressResourcesMutex); ResourceLoadData* loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0); mInProgressResources[UUID] = loadData; loadData->resData = outputResource.getWeak(); if (keepInternalReference) { loadData->resData.numInternalRefs++; outputResource.addInternalRef(); } loadData->remainingDependencies = 1; loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously // Register dependencies and count them so we know when the resource is fully loaded if (loadDependencies && savedResourceData != nullptr) { for (auto& dependency : savedResourceData->getDependencies()) { if (dependency != UUID) { mDependantLoads[dependency].push_back(loadData); loadData->remainingDependencies++; } } } } if (loadDependencies && savedResourceData != nullptr) { const Vector<String>& dependencyUUIDs = savedResourceData->getDependencies(); UINT32 numDependencies = (UINT32)dependencyUUIDs.size(); Vector<HResource> dependencies(numDependencies); for (UINT32 i = 0; i < numDependencies; i++) dependencies[i] = loadFromUUID(dependencyUUIDs[i], !synchronous, true, false); // Keep dependencies alive until the parent is done loading { Lock lock(mInProgressResourcesMutex); // At this point the resource is guaranteed to still be in-progress, so it's safe to update its dependency list mInProgressResources[UUID]->dependencies = dependencies; } } } else if (loadDependencies && savedResourceData != nullptr) // Queue dependencies in case they aren't already loaded { const Vector<String>& dependencies = savedResourceData->getDependencies(); if (!dependencies.empty()) { { Lock lock(mInProgressResourcesMutex); ResourceLoadData* loadData = nullptr; auto iterFind = mInProgressResources.find(UUID); if (iterFind == mInProgressResources.end()) // Fully loaded { loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0); loadData->resData = outputResource.getWeak(); loadData->remainingDependencies = 0; loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously mInProgressResources[UUID] = loadData; } else { loadData = iterFind->second; } // Register dependencies and count them so we know when the resource is fully loaded for (auto& dependency : dependencies) { if (dependency != UUID) { bool registerDependency = true; auto iterFind2 = mDependantLoads.find(dependency); if (iterFind2 != mDependantLoads.end()) { Vector<ResourceLoadData*>& dependantData = iterFind2->second; auto iterFind3 = std::find_if(dependantData.begin(), dependantData.end(), [&](ResourceLoadData* x) { return x->resData.resource.getUUID() == outputResource.getUUID(); }); registerDependency = iterFind3 == dependantData.end(); } if (registerDependency) { mDependantLoads[dependency].push_back(loadData); loadData->remainingDependencies++; loadData->dependencies.push_back(_getResourceHandle(dependency)); } } } } for (auto& dependency : dependencies) loadFromUUID(dependency, !synchronous, true, false); } } // Actually start the file read operation if not already loaded or in progress if (!alreadyLoading && !filePath.isEmpty()) { // Synchronous or the resource doesn't support async, read the file immediately if (synchronous || !savedResourceData->allowAsyncLoading()) { loadCallback(filePath, outputResource); } else // Asynchronous, read the file on a worker thread { String fileName = filePath.getFilename(); String taskName = "Resource load: " + fileName; SPtr<Task> task = Task::create(taskName, std::bind(&Resources::loadCallback, this, filePath, outputResource)); TaskScheduler::instance().addTask(task); } } else // File already loaded or in progress { // Complete the load unless its in progress in which case we wait for its worker thread to complete it. // In case file is already loaded this will only decrement dependency count in case this resource is a dependency. if (!loadInProgress) loadComplete(outputResource); else { // In case loading finished in the meantime we cannot be sure at what point ::loadComplete was triggered, // so trigger it manually so that the dependency count is properly decremented in case this resource // is a dependency. Lock lock(mLoadedResourceMutex); auto iterFind = mLoadedResources.find(UUID); if (iterFind != mLoadedResources.end()) loadComplete(outputResource); } } return outputResource; }