/// Perform a non-blocking attempt to sync with an asynchronous shader variant load request. /// /// @param[in] loadId Load request ID. /// @param[out] rspVariant Smart pointer set to the variant reference if loading has completed. /// /// @return True if loading has completed, false if not. Note that if this returns true, the load request ID will /// no longer be valid for its current load request and should not be reused. /// /// @see BeginLoadVariant() bool Shader::TryFinishLoadVariant( size_t loadId, ShaderVariantPtr& rspVariant ) { HELIUM_ASSERT( IsValid( loadId ) ); // Use the try-finish-load override if one is registered. if( sm_pTryFinishLoadVariantOverride ) { bool bFinished = sm_pTryFinishLoadVariantOverride( sm_pVariantLoadOverrideData, loadId, rspVariant ); return bFinished; } // Attempt to sync the object load request. GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance(); HELIUM_ASSERT( pObjectLoader ); GameObjectPtr spObject; bool bFinished = pObjectLoader->TryFinishLoad( loadId, spObject ); if( bFinished ) { rspVariant = Reflect::AssertCast< ShaderVariant >( spObject.Get() ); } return bFinished; }
/// Tick the object deserialization process for the given object load request. /// /// @param[in] pRequest Load request. /// /// @return True if the deserialization process has completed, false if it still needs time to process. bool CachePackageLoader::TickDeserialize( LoadRequest* pRequest ) { HELIUM_ASSERT( pRequest ); HELIUM_ASSERT( !( pRequest->flags & LOAD_FLAG_PRELOADED ) ); GameObject* pObject = pRequest->spObject; const Cache::Entry* pCacheEntry = pRequest->pEntry; HELIUM_ASSERT( pCacheEntry ); // Wait for the template and owner objects to load. GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance(); HELIUM_ASSERT( pObjectLoader ); if( IsValid( pRequest->templateLinkIndex ) ) { HELIUM_ASSERT( pRequest->templateLinkIndex < pRequest->objectLinkTable.GetSize() ); size_t templateLoadId = pRequest->objectLinkTable[ pRequest->templateLinkIndex ]; if( IsValid( templateLoadId ) && !pObjectLoader->TryFinishLoad( templateLoadId, pRequest->spTemplate ) ) { return false; } SetInvalid( pRequest->templateLinkIndex ); if( !pRequest->spTemplate ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Failed to load template object for \"%s\".\n" ), *pCacheEntry->path.ToString() ); if( pObject ) { pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); } DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } } GameObject* pTemplate = pRequest->spTemplate; if( IsValid( pRequest->ownerLinkIndex ) ) { HELIUM_ASSERT( pRequest->ownerLinkIndex < pRequest->objectLinkTable.GetSize() ); size_t ownerLoadId = pRequest->objectLinkTable[ pRequest->ownerLinkIndex ]; if( IsValid( ownerLoadId ) && !pObjectLoader->TryFinishLoad( ownerLoadId, pRequest->spOwner ) ) { return false; } SetInvalid( pRequest->ownerLinkIndex ); if( !pRequest->spOwner ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Failed to load owner object for \"%s\".\n" ), *pCacheEntry->path.ToString() ); if( pObject ) { pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); } DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } } GameObject* pOwner = pRequest->spOwner; HELIUM_ASSERT( !pOwner || pOwner->IsFullyLoaded() ); HELIUM_ASSERT( !pTemplate || pTemplate->IsFullyLoaded() ); GameObjectType* pType = pRequest->spType; HELIUM_ASSERT( pType ); // If we already had an existing object, make sure the type and template match. if( pObject ) { const GameObjectType* pExistingType = pObject->GetGameObjectType(); HELIUM_ASSERT( pExistingType ); if( pExistingType != pType ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "CachePackageLoader: Cannot load \"%s\" using the existing object as the types do not " ) TXT( "match (existing type: \"%s\"; serialized type: \"%s\".\n" ) ), *pCacheEntry->path.ToString(), *pExistingType->GetName(), *pType->GetName() ); pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } } else { // Create the object. if( !GameObject::CreateObject( pRequest->spObject, pType, pCacheEntry->path.GetName(), pOwner, pTemplate ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Failed to create \"%s\" during loading.\n" ), *pCacheEntry->path.ToString() ); DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } pObject = pRequest->spObject; HELIUM_ASSERT( pObject ); } Reflect::ObjectPtr cached_object = Cache::ReadCacheObjectFromBuffer(pRequest->pSerializedData, 0, pRequest->pPropertyStreamEnd - pRequest->pSerializedData); if (!cached_object.ReferencesObject()) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Failed to deserialize object \"%s\".\n" ), *pCacheEntry->path.ToString() ); // Clear out object references (object can now be considered fully loaded as well). // pmd - Not sure that we need to do this.. but if we do, just use this visitor //ClearLinkIndicesFromObject clifo_visitor; //pObject->Accept(clifo_visitor); pObject->SetFlags( GameObject::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); pRequest->flags |= LOAD_FLAG_ERROR; } else { cached_object->CopyTo(pObject); if( !pObject->IsDefaultTemplate() ) { // Load persistent resource data. Resource* pResource = Reflect::SafeCast< Resource >( pObject ); if( pResource ) { Reflect::ObjectPtr cached_prd = Cache::ReadCacheObjectFromBuffer( pRequest->pPropertyStreamEnd, 0, (pRequest->pPersistentResourceStreamEnd - pRequest->pPropertyStreamEnd)); if (!cached_prd.ReferencesObject()) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "CachePackageLoader: Failed to deserialize persistent resource " ) TXT( "data for \"%s\".\n" ) ), *pCacheEntry->path.ToString() ); } else { pResource->LoadPersistentResourceObject(cached_prd); } } } } DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pObject->SetFlags( GameObject::FLAG_PRELOADED ); pRequest->flags |= LOAD_FLAG_PRELOADED; // GameObject is now preloaded. return true; }
/// @copydoc PackageLoader::TryFinishLoadObject() bool CachePackageLoader::TryFinishLoadObject( size_t requestId, GameObjectPtr& rspObject, DynamicArray< GameObjectLoader::LinkEntry >& rLinkTable ) { HELIUM_ASSERT( requestId < m_loadRequests.GetSize() ); HELIUM_ASSERT( m_loadRequests.IsElementValid( requestId ) ); LoadRequest* pRequest = m_loadRequests[ requestId ]; HELIUM_ASSERT( pRequest ); if( !( pRequest->flags & LOAD_FLAG_PRELOADED ) ) { return false; } // Sync on template and owner dependencies. GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance(); HELIUM_ASSERT( pObjectLoader ); DynamicArray< size_t >& rInternalLinkTable = pRequest->objectLinkTable; if( IsValid( pRequest->templateLinkIndex ) ) { size_t linkLoadId = rInternalLinkTable[ pRequest->templateLinkIndex ]; if( IsValid( linkLoadId ) && !pObjectLoader->TryFinishLoad( linkLoadId, pRequest->spTemplate ) ) { return false; } SetInvalid( pRequest->templateLinkIndex ); } if( IsValid( pRequest->ownerLinkIndex ) ) { size_t linkLoadId = rInternalLinkTable[ pRequest->ownerLinkIndex ]; if( IsValid( linkLoadId ) && !pObjectLoader->TryFinishLoad( linkLoadId, pRequest->spOwner ) ) { return false; } SetInvalid( pRequest->ownerLinkIndex ); } rspObject = pRequest->spObject; GameObject* pObject = rspObject; if( pObject && ( pRequest->flags & LOAD_FLAG_ERROR ) ) { pObject->SetFlags( GameObject::FLAG_BROKEN ); } pRequest->spObject.Release(); size_t linkTableSize = rInternalLinkTable.GetSize(); rLinkTable.Resize( 0 ); rLinkTable.Reserve( linkTableSize ); for( size_t linkIndex = 0; linkIndex < linkTableSize; ++linkIndex ) { GameObjectLoader::LinkEntry* pEntry = rLinkTable.New(); HELIUM_ASSERT( pEntry ); pEntry->loadId = rInternalLinkTable[ linkIndex ]; pEntry->spObject.Release(); } rInternalLinkTable.Resize( 0 ); HELIUM_ASSERT( IsInvalid( pRequest->asyncLoadId ) ); HELIUM_ASSERT( !pRequest->pAsyncLoadBuffer ); pRequest->spType.Release(); pRequest->spTemplate.Release(); pRequest->spOwner.Release(); pRequest->typeLinkTable.Resize( 0 ); HELIUM_ASSERT( pObject || pRequest->pEntry ); HELIUM_TRACE( TraceLevels::Debug, ( TXT( "CachePackageLoader::TryFinishLoadObject(): Load request for \"%s\" (ID: %" ) TPRIuSZ TXT( ") " ) TXT( "synced.\n" ) ), *( pObject ? pObject->GetPath() : pRequest->pEntry->path ).ToString(), requestId ); m_loadRequests.Remove( requestId ); m_loadRequestPool.Release( pRequest ); return true; }