/// Begin asynchronous loading of a shader variant. /// /// @param[in] shaderType Shader type. /// @param[in] userOptionIndex Index associated with the user option combination for the shader variant. /// /// @return ID associated with the load procedure, or an invalid index if the load could not be started. /// /// @see TryFinishLoadVariant() size_t Shader::BeginLoadVariant( RShader::EType shaderType, uint32_t userOptionIndex ) { HELIUM_ASSERT( static_cast< size_t >( shaderType ) < static_cast< size_t >( RShader::TYPE_MAX ) ); // Make sure the user option index is valid. if( userOptionIndex >= m_variantCounts[ shaderType ] ) { HELIUM_TRACE( TRACE_ERROR, ( TXT( "Shader::BeginLoadVariant(): Invalid user option index %" ) TPRIuSZ TXT( " specified for " ) TXT( "variant of shader \"%s\" (only %" ) TPRIuSZ TXT ( " variants are available for shader type %" ) TPRId32 TXT( ").\n" ) ), userOptionIndex, *GetPath().ToString(), m_variantCounts[ shaderType ], static_cast< int32_t >( shaderType ) ); return Invalid< size_t >(); } // Use the begin-load override if one is registered. if( sm_pBeginLoadVariantOverride ) { size_t loadId = sm_pBeginLoadVariantOverride( sm_pVariantLoadOverrideData, this, shaderType, userOptionIndex ); return loadId; } // Build the object path name. tchar_t shaderTypeCharacter; if( shaderType == RShader::TYPE_VERTEX ) { shaderTypeCharacter = TXT( 'v' ); } else { HELIUM_ASSERT( shaderType == RShader::TYPE_PIXEL ); shaderTypeCharacter = TXT( 'p' ); } String variantNameString; variantNameString.Format( TXT( "%c%" ) TPRIu32, shaderTypeCharacter, userOptionIndex ); GameObjectPath variantPath; HELIUM_VERIFY( variantPath.Set( Name( variantNameString ), false, GetPath() ) ); // Begin the load process. GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance(); HELIUM_ASSERT( pObjectLoader ); size_t loadId = pObjectLoader->BeginLoadObject( variantPath ); return loadId; }
/// Deserialize the link tables for an object load. /// /// @param[in] pRequest Load request data. bool CachePackageLoader::DeserializeLinkTables( LoadRequest* pRequest ) { HELIUM_ASSERT( pRequest ); uint8_t* pBufferCurrent = pRequest->pAsyncLoadBuffer; uint8_t* pPropertyStreamEnd = pRequest->pPropertyStreamEnd; HELIUM_ASSERT( pBufferCurrent ); HELIUM_ASSERT( pPropertyStreamEnd ); HELIUM_ASSERT( pBufferCurrent <= pPropertyStreamEnd ); uint32_t propertyStreamSize = 0; if( pBufferCurrent + sizeof( propertyStreamSize ) > pPropertyStreamEnd ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } MemoryCopy( &propertyStreamSize, pBufferCurrent, sizeof( propertyStreamSize ) ); pBufferCurrent += sizeof( propertyStreamSize ); if( propertyStreamSize > static_cast< size_t >( pPropertyStreamEnd - pBufferCurrent ) ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "CachePackageLoader: Property stream size (%" ) TPRIu32 TXT( " bytes) for \"%s\" exceeds the " ) TXT( "amount of data cached. Value will be clamped.\n" ) ), propertyStreamSize, *pRequest->pEntry->path.ToString() ); propertyStreamSize = static_cast< uint32_t >( pPropertyStreamEnd - pBufferCurrent ); } pPropertyStreamEnd = pBufferCurrent + propertyStreamSize; pRequest->pPropertyStreamEnd = pPropertyStreamEnd; // Adjust the end of the persistent resource data stream to account for the resource sub-data count padded on // the end (note that non-resources will not have this padding). if( pRequest->pPersistentResourceStreamEnd - pPropertyStreamEnd >= sizeof( uint32_t ) ) { pRequest->pPersistentResourceStreamEnd -= sizeof( uint32_t ); } else { pRequest->pPersistentResourceStreamEnd = pPropertyStreamEnd; } StackMemoryHeap<>& rStackHeap = ThreadLocalStackAllocator::GetMemoryHeap(); // Load the type link table. uint32_t typeLinkTableSize = 0; if( pBufferCurrent + sizeof( typeLinkTableSize ) > pPropertyStreamEnd ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } MemoryCopy( &typeLinkTableSize, pBufferCurrent, sizeof( typeLinkTableSize ) ); pBufferCurrent += sizeof( typeLinkTableSize ); pRequest->typeLinkTable.Resize( 0 ); pRequest->typeLinkTable.Reserve( typeLinkTableSize ); uint_fast32_t typeLinkTableSizeFast = typeLinkTableSize; for( uint_fast32_t linkTableIndex = 0; linkTableIndex < typeLinkTableSizeFast; ++linkTableIndex ) { uint32_t typeNameSize; if( pBufferCurrent + sizeof( typeNameSize ) > pPropertyStreamEnd ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } MemoryCopy( &typeNameSize, pBufferCurrent, sizeof( typeNameSize ) ); pBufferCurrent += sizeof( typeNameSize ); if( pBufferCurrent + sizeof( tchar_t ) * typeNameSize > pPropertyStreamEnd ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } StackMemoryHeap<>::Marker stackMarker( rStackHeap ); tchar_t* pTypeNameString = static_cast< tchar_t* >( rStackHeap.Allocate( sizeof( tchar_t ) * ( typeNameSize + 1 ) ) ); HELIUM_ASSERT( pTypeNameString ); MemoryCopy( pTypeNameString, pBufferCurrent, sizeof( tchar_t ) * typeNameSize ); pBufferCurrent += sizeof( tchar_t ) * typeNameSize; pTypeNameString[ typeNameSize ] = TXT( '\0' ); Name typeName( pTypeNameString ); GameObjectType* pType = GameObjectType::Find( typeName ); if( !pType ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Failed to locate type \"%s\" when attempting to deserialize \"%s\".\n" ), pTypeNameString, *pRequest->pEntry->path.ToString() ); } pRequest->typeLinkTable.Push( pType ); } // Load the object link table. uint32_t objectLinkTableSize = 0; if( pBufferCurrent + sizeof( objectLinkTableSize ) > pPropertyStreamEnd ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } MemoryCopy( &objectLinkTableSize, pBufferCurrent, sizeof( objectLinkTableSize ) ); pBufferCurrent += sizeof( objectLinkTableSize ); pRequest->objectLinkTable.Resize( 0 ); pRequest->objectLinkTable.Reserve( objectLinkTableSize ); StackMemoryHeap<>::Marker stackMarker( rStackHeap ); // Track the link table object paths so that we can use them for issuing additional load requests for the object // template and owner dependencies (this way, we can sync on those load requests during the preload process // while still providing load requests for the caller to resolve if necessary). GameObjectPath* pObjectLinkTablePaths = static_cast< GameObjectPath* >( rStackHeap.Allocate( sizeof( GameObjectPath ) * objectLinkTableSize ) ); HELIUM_ASSERT( pObjectLinkTablePaths ); ArrayUninitializedFill( pObjectLinkTablePaths, GameObjectPath( NULL_NAME ), objectLinkTableSize ); GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance(); HELIUM_ASSERT( pObjectLoader ); uint_fast32_t objectLinkTableSizeFast = objectLinkTableSize; for( uint_fast32_t linkTableIndex = 0; linkTableIndex < objectLinkTableSizeFast; ++linkTableIndex ) { uint32_t pathStringSize; if( pBufferCurrent + sizeof( pathStringSize ) > pPropertyStreamEnd ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } MemoryCopy( &pathStringSize, pBufferCurrent, sizeof( pathStringSize ) ); pBufferCurrent += sizeof( pathStringSize ); if( pBufferCurrent + sizeof( tchar_t ) * pathStringSize > pPropertyStreamEnd ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } StackMemoryHeap<>::Marker stackMarker( rStackHeap ); tchar_t* pPathString = static_cast< tchar_t* >( rStackHeap.Allocate( sizeof( tchar_t ) * ( pathStringSize + 1 ) ) ); HELIUM_ASSERT( pPathString ); MemoryCopy( pPathString, pBufferCurrent, sizeof( tchar_t ) * pathStringSize ); pBufferCurrent += sizeof( tchar_t ) * pathStringSize; pPathString[ pathStringSize ] = TXT( '\0' ); size_t linkLoadId; SetInvalid( linkLoadId ); GameObjectPath path; if( !path.Set( pPathString ) ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "CachePackageLoader: Invalid object path \"%s\" found in linker table when deserializing " ) TXT( "\"%s\". Setting to null.\n" ) ), pPathString, *pRequest->pEntry->path.ToString() ); pRequest->flags |= LOAD_FLAG_ERROR; } else { pObjectLinkTablePaths[ linkTableIndex ] = path; // Begin loading the link table entry. linkLoadId = pObjectLoader->BeginLoadObject( path ); if( IsInvalid( linkLoadId ) ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "CachePackageLoader: Failed to begin loading \"%s\" as a link dependency for \"%s\". " ) TXT( "Setting to null.\n" ) ), pPathString, *pRequest->pEntry->path.ToString() ); pRequest->flags |= LOAD_FLAG_ERROR; } } pRequest->objectLinkTable.Push( linkLoadId ); } // Read the type link information. uint32_t typeLinkIndex; if( pBufferCurrent + sizeof( typeLinkIndex ) > pPropertyStreamEnd ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } MemoryCopy( &typeLinkIndex, pBufferCurrent, sizeof( typeLinkIndex ) ); pBufferCurrent += sizeof( typeLinkIndex ); if( typeLinkIndex >= typeLinkTableSizeFast ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Invalid link table index for the type of \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } GameObjectType* pType = pRequest->typeLinkTable[ typeLinkIndex ]; if( !pType ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Type not found for object \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } pRequest->spType = pType; // Read the template link information. if( pBufferCurrent + sizeof( pRequest->templateLinkIndex ) > pPropertyStreamEnd ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } MemoryCopy( &pRequest->templateLinkIndex, pBufferCurrent, sizeof( pRequest->templateLinkIndex ) ); pBufferCurrent += sizeof( pRequest->templateLinkIndex ); if( IsValid( pRequest->templateLinkIndex ) ) { if( pRequest->templateLinkIndex >= objectLinkTableSizeFast ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Invalid link table index for the template of \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); SetInvalid( pRequest->templateLinkIndex ); return false; } size_t templateLoadId = pObjectLoader->BeginLoadObject( pObjectLinkTablePaths[ pRequest->templateLinkIndex ] ); HELIUM_ASSERT( templateLoadId == pRequest->objectLinkTable[ pRequest->templateLinkIndex ] ); HELIUM_UNREF( templateLoadId ); } // Read the owner link information. if( pBufferCurrent + sizeof( pRequest->ownerLinkIndex ) > pPropertyStreamEnd ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); return false; } MemoryCopy( &pRequest->ownerLinkIndex, pBufferCurrent, sizeof( pRequest->ownerLinkIndex ) ); pBufferCurrent += sizeof( pRequest->ownerLinkIndex ); if( IsValid( pRequest->ownerLinkIndex ) ) { if( pRequest->ownerLinkIndex >= objectLinkTableSizeFast ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Invalid link table index for the owner of \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); SetInvalid( pRequest->ownerLinkIndex ); return false; } size_t ownerLoadId = pObjectLoader->BeginLoadObject( pObjectLinkTablePaths[ pRequest->ownerLinkIndex ] ); HELIUM_ASSERT( ownerLoadId == pRequest->objectLinkTable[ pRequest->ownerLinkIndex ] ); HELIUM_UNREF( ownerLoadId ); } pRequest->pSerializedData = pBufferCurrent; return true; }