Пример #1
0
/// 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;
}
Пример #2
0
/// 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;
}