//--------------------------------------------------------------------- WorkQueue::Response* Page::handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ) { // Background thread (maybe) PageRequest preq = any_cast<PageRequest>(req->getData()); // only deal with own requests; we shouldn't ever get here though if (preq.srcPage != this) return 0; PageResponse res; res.pageData = OGRE_NEW PageData(); WorkQueue::Response* response = 0; try { prepareImpl(res.pageData); response = OGRE_NEW WorkQueue::Response(req, true, Any(res)); } catch (Exception& e) { // oops response = OGRE_NEW WorkQueue::Response(req, false, Any(res), e.getFullDescription()); } return response; }
//--------------------------------------------------------------------- bool Page::prepareImpl(PageData* dataToPopulate) { // Procedural preparation if (mParent->_prepareProceduralPage(this)) return true; else { // Background loading String filename = generateFilename(); DataStreamPtr stream = Root::getSingleton().openFileStream(filename, getManager()->getPageResourceGroup()); StreamSerialiser ser(stream); return prepareImpl(ser, dataToPopulate); } }
//----------------------------------------------------------------------- void Resource::prepare() { // quick check that avoids any synchronisation LoadingState old = mLoadingState.get(); if (old != LOADSTATE_UNLOADED && old != LOADSTATE_PREPARING) return; // atomically do slower check to make absolutely sure, // and set the load state to PREPARING if (!mLoadingState.cas(LOADSTATE_UNLOADED,LOADSTATE_PREPARING)) { while( mLoadingState.get() == LOADSTATE_PREPARING ) { OGRE_LOCK_AUTO_MUTEX } LoadingState state = mLoadingState.get(); if( state != LOADSTATE_PREPARED && state != LOADSTATE_LOADING && state != LOADSTATE_LOADED ) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Another thread failed in resource operation", "Resource::prepare"); } return; } // Scope lock for actual loading try { OGRE_LOCK_AUTO_MUTEX if (mIsManual) { if (mLoader) { mLoader->prepareResource(this); } else { // Warn that this resource is not reloadable LogManager::getSingleton().stream(LML_TRIVIAL) << "WARNING: " << mCreator->getResourceType() << " instance '" << mName << "' was defined as manually " << "loaded, but no manual loader was provided. This Resource " << "will be lost if it has to be reloaded."; } } else { if (mGroup == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME) { // Derive resource group changeGroupOwnership( ResourceGroupManager::getSingleton() .findGroupContainingResource(mName)); } prepareImpl(); } } catch (...) { mLoadingState.set(LOADSTATE_UNLOADED); throw; } mLoadingState.set(LOADSTATE_PREPARED); // Since we don't distinguish between GPU and CPU RAM, this // seems pointless //if(mCreator) // mCreator->_notifyResourcePrepared(this); // Fire (deferred) events if (mIsBackgroundLoaded) queueFireBackgroundPreparingComplete(); }
//--------------------------------------------------------------------- void Resource::load(bool background) { // Early-out without lock (mitigate perf cost of ensuring loaded) // Don't load if: // 1. We're already loaded // 2. Another thread is loading right now // 3. We're marked for background loading and this is not the background // loading thread we're being called by if (mIsBackgroundLoaded && !background) return; // This next section is to deal with cases where 2 threads are fighting over // who gets to prepare / load - this will only usually happen if loading is escalated bool keepChecking = true; LoadingState old; while (keepChecking) { // quick check that avoids any synchronisation old = mLoadingState.get(); if ( old == LOADSTATE_PREPARING ) { while( mLoadingState.get() == LOADSTATE_PREPARING ) { OGRE_LOCK_AUTO_MUTEX } old = mLoadingState.get(); } if (old!=LOADSTATE_UNLOADED && old!=LOADSTATE_PREPARED && old!=LOADSTATE_LOADING) return; // atomically do slower check to make absolutely sure, // and set the load state to LOADING if (old==LOADSTATE_LOADING || !mLoadingState.cas(old,LOADSTATE_LOADING)) { while( mLoadingState.get() == LOADSTATE_LOADING ) { OGRE_LOCK_AUTO_MUTEX } LoadingState state = mLoadingState.get(); if( state == LOADSTATE_PREPARED || state == LOADSTATE_PREPARING ) { // another thread is preparing, loop around continue; } else if( state != LOADSTATE_LOADED ) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Another thread failed in resource operation", "Resource::load"); } return; } keepChecking = false; } // Scope lock for actual loading try { OGRE_LOCK_AUTO_MUTEX if (mIsManual) { preLoadImpl(); // Load from manual loader if (mLoader) { mLoader->loadResource(this); } else { // Warn that this resource is not reloadable LogManager::getSingleton().stream(LML_TRIVIAL) << "WARNING: " << mCreator->getResourceType() << " instance '" << mName << "' was defined as manually " << "loaded, but no manual loader was provided. This Resource " << "will be lost if it has to be reloaded."; } postLoadImpl(); } else { if (old==LOADSTATE_UNLOADED) prepareImpl(); preLoadImpl(); old = LOADSTATE_PREPARED; if (mGroup == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME) { // Derive resource group changeGroupOwnership( ResourceGroupManager::getSingleton() .findGroupContainingResource(mName)); } loadImpl(); postLoadImpl(); } // Calculate resource size mSize = calculateSize(); } catch (...) { // Reset loading in-progress flag, in case failed for some reason. // We reset it to UNLOADED because the only other case is when // old == PREPARED in which case the loadImpl should wipe out // any prepared data since it might be invalid. mLoadingState.set(LOADSTATE_UNLOADED); // Re-throw throw; } mLoadingState.set(LOADSTATE_LOADED); _dirtyState(); // Notify manager if(mCreator) mCreator->_notifyResourceLoaded(this); // Fire (deferred) events if (mIsBackgroundLoaded) queueFireBackgroundLoadingComplete(); }