Пример #1
0
/// Resolve a set of shader preprocessor options from the associated index.
///
/// @param[in]  shaderType    Type of shader.
/// @param[in]  index         Option set index.
/// @param[out] rToggleNames  List of enabled shader toggles.
/// @param[out] rSelectPairs  List shader selection pair values.
void Shader::Options::GetOptionSetFromIndex(
    RShader::EType shaderType,
    size_t index,
    DynArray< Name >& rToggleNames,
    DynArray< SelectPair >& rSelectPairs ) const
{
    HELIUM_ASSERT( static_cast< size_t >( shaderType ) < static_cast< size_t >( RShader::TYPE_MAX ) );

    rToggleNames.Resize( 0 );
    rSelectPairs.Resize( 0 );

    uint32_t shaderTypeMask = ( 1 << shaderType );

    size_t shaderToggleCount = m_toggles.GetSize();
    for( size_t shaderToggleIndex = 0; shaderToggleIndex < shaderToggleCount; ++shaderToggleIndex )
    {
        const Toggle& rShaderToggle = m_toggles[ shaderToggleIndex ];
        if( !( rShaderToggle.shaderTypeFlags & shaderTypeMask ) )
        {
            continue;
        }

        if( index & 0x1 )
        {
            HELIUM_VERIFY( rToggleNames.New( rShaderToggle.name ) );
        }

        index >>= 1;
    }

    size_t shaderSelectCount = m_selects.GetSize();
    for( size_t shaderSelectIndex = 0; shaderSelectIndex < shaderSelectCount; ++shaderSelectIndex )
    {
        const Select& rShaderSelect = m_selects[ shaderSelectIndex ];
        if( !( rShaderSelect.shaderTypeFlags & shaderTypeMask ) )
        {
            continue;
        }

        const DynArray< Name >& rShaderSelectChoices = rShaderSelect.choices;
        size_t shaderSelectChoiceCount = rShaderSelectChoices.GetSize();

        size_t selectIndexMultiplier = shaderSelectChoiceCount + rShaderSelect.bOptional;

        size_t selectIndex = index % selectIndexMultiplier;
        index /= selectIndexMultiplier;

        if( !rShaderSelect.bOptional || selectIndex != shaderSelectChoiceCount )
        {
            SelectPair* pSelectPair = rSelectPairs.New();
            HELIUM_ASSERT( pSelectPair );
            pSelectPair->name = rShaderSelect.name;
            pSelectPair->choice = rShaderSelectChoices[ selectIndex ];
        }
    }
}
Пример #2
0
void Helium::ResourceHandler::SaveObjectToPersistentDataBuffer( Reflect::Object *_object, DynArray< uint8_t > &_buffer )
{
    _buffer.Resize(0);
    if (!_object)
    {
        return;
    }

    Cache::WriteCacheObjectToBuffer(*_object, _buffer);
}
Пример #3
0
void Helium::Cache::WriteCacheObjectToBuffer( Reflect::Object &_object, DynArray< uint8_t > &_buffer )
{
#if USE_XML_FOR_CACHE_DATA
    {
        tstringstream xml_out_ss;

        Reflect::ArchiveXML xml_out(new Reflect::TCharStream(&xml_out_ss, false), true);
        xml_out.WriteFileHeader();
        xml_out.WriteSingleObject(_object);
        xml_out.WriteFileFooter();
        xml_out.Close();
            
        tstring xml_str;
        xml_str = xml_out_ss.str();

        if (xml_str.size() > 0)
        {
            _buffer.Resize(xml_str.size() * sizeof(tchar_t));
            memcpy(&_buffer[0], xml_str.data(), xml_str.size() * sizeof(tchar_t));
        }
    }
#else
    {
        std::stringstream ss_out;
        Reflect::ArchiveBinary binary_out(new Reflect::CharStream(&ss_out, false, Helium::ByteOrders::LittleEndian, Helium::Reflect::CharacterEncodings::UTF_16), true);
        binary_out.SerializeInstance( &_object );

        // This is not an efficient way to do this
        std::string str_out;
        str_out = ss_out.str();

        if (!str_out.empty())
        {
            _buffer.Resize(str_out.size());
            memcpy(&_buffer[0], str_out.data(), str_out.size());
        }
    }
#endif
}
Пример #4
0
void StructureDynArrayData::Serialize( ArchiveT& archive )
{
    const Structure *structure = GetInternalStructure();

    DynArray< ObjectPtr > components;
    components.Resize( structure->m_DynArrayAdapter->GetSize(GetInternalPtr(structure)) );

    for (size_t i = 0; i < components.GetSize(); ++i)
    {
        components[i] = structure->m_DynArrayAdapter->GetItem(GetInternalPtr(structure), i, m_Instance, m_Field);
    }

    archive.SerializeArray( components );
}
Пример #5
0
/// Gather all existing resource handlers.
///
/// This will iterate through all sub-types of ResourceHandler and add their template objects to a dynamic array.
///
/// @param[out] rResourceHandlers  List of existing resource handlers.
void ResourceHandler::GetAllResourceHandlers( DynArray< ResourceHandler* >& rResourceHandlers )
{
    rResourceHandlers.Resize( 0 );

    const GameObjectType* pResourceHandlerType = GetStaticType();
    HELIUM_ASSERT( pResourceHandlerType );

    GameObjectType::ConstIterator typeEnd = GameObjectType::GetTypeEnd();
    for( GameObjectType::ConstIterator typeIterator = GameObjectType::GetTypeBegin(); typeIterator != typeEnd; ++typeIterator )
    {
        const GameObjectType& rType = *typeIterator;
        if( &rType != pResourceHandlerType && rType.GetClass()->IsType( pResourceHandlerType->GetClass() ) )
        {
            ResourceHandler* pHandler = Reflect::AssertCast< ResourceHandler >( rType.GetTemplate() );
            HELIUM_ASSERT( pHandler );
            rResourceHandlers.Push( pHandler );
        }
    }
}
Пример #6
0
/// Helper function for compiling a shader for a specific profile.
///
/// @param[in]  pVariant             Shader variant for which we are compiling.
/// @param[in]  pPreprocessor        Platform preprocessor to use for compiling.
/// @param[in]  platformIndex        Platform index.
/// @param[in]  shaderProfileIndex   Index of the target shader profile.
/// @param[in]  shaderType           Type of shader to compile.
/// @param[in]  pShaderSourceData    Buffer in which the shader source code is stored.
/// @param[in]  shaderSourceSize     Size of the shader source buffer, in bytes.
/// @param[in]  rTokens              Array specifying preprocessor tokens to pass to the shader compiler.
/// @param[out] rCompiledCodeBuffer  Buffer in which the compiled code will be stored.
///
/// @return  True if compiling was successful, false if not.
bool ShaderVariantResourceHandler::CompileShader(
    ShaderVariant* pVariant,
    PlatformPreprocessor* pPreprocessor,
    size_t platformIndex,
    size_t shaderProfileIndex,
    RShader::EType shaderType,
    const void* pShaderSourceData,
    size_t shaderSourceSize,
    const DynArray< PlatformPreprocessor::ShaderToken >& rTokens,
    DynArray< uint8_t >& rCompiledCodeBuffer )
{
    HELIUM_ASSERT( pVariant );
    HELIUM_ASSERT( pPreprocessor );
    HELIUM_ASSERT( static_cast< size_t >( shaderType ) < static_cast< size_t >( RShader::TYPE_MAX ) );
    HELIUM_ASSERT( pShaderSourceData || shaderSourceSize == 0 );

    HELIUM_UNREF( platformIndex );  // Variable is used for logging only.

    rCompiledCodeBuffer.Resize( 0 );

#if HELIUM_ENABLE_TRACE
    DynArray< String > errorMessages;
#endif

    Path shaderFilePath;
    if ( !File::GetDataDirectory( shaderFilePath ) )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            TXT( "ShaderVariantResourceHandler: Failed to obtain data directory." ) );

        return false;
    }

    shaderFilePath += pVariant->GetPath().GetParent().ToFilePathString().GetData();

    bool bCompileResult = pPreprocessor->CompileShader(
                              shaderFilePath,
                              shaderProfileIndex,
                              shaderType,
                              pShaderSourceData,
                              shaderSourceSize,
                              rTokens.GetData(),
                              rTokens.GetSize(),
                              rCompiledCodeBuffer
#if HELIUM_ENABLE_TRACE
                              , &errorMessages
#else
                              , NULL
#endif
                          );
    if( !bCompileResult )
    {
        rCompiledCodeBuffer.Resize( 0 );

#if HELIUM_ENABLE_TRACE
        String tokenList;
#if HELIUM_UNICODE
        String convertedToken;
#endif
        size_t tokenCount = rTokens.GetSize();
        for( size_t tokenIndex = 0; tokenIndex < tokenCount; ++tokenIndex )
        {
            tokenList += TXT( ' ' );
#if HELIUM_UNICODE
            StringConverter< char, tchar_t >::Convert( convertedToken, rTokens[ tokenIndex ].name );
            tokenList += convertedToken;
#else
            tokenList += rTokens[ tokenIndex ].name;
#endif
        }

        size_t errorCount = errorMessages.GetSize();

        HELIUM_TRACE(
            TRACE_ERROR,
            ( TXT( "ShaderVariantResourceHandler: Failed to compile \"%s\" for platform %" ) TPRIuSZ
              TXT( ", profile %" ) TPRIuSZ TXT( "; %" ) TPRIuSZ TXT( " errors (tokens:%s):\n" ) ),
            *pVariant->GetPath().ToString(),
            platformIndex,
            shaderProfileIndex,
            errorCount,
            *tokenList );

        for( size_t errorIndex = 0; errorIndex < errorCount; ++errorIndex )
        {
            HELIUM_TRACE( TRACE_ERROR, TXT( "- %s\n" ), *errorMessages[ errorIndex ] );
        }
#endif  // HELIUM_ENABLE_TRACE
    }

    return bCompileResult;
}
Пример #7
0
/// @copydoc ResourceHandler::CacheResource()
bool ShaderVariantResourceHandler::CacheResource(
    ObjectPreprocessor* pObjectPreprocessor,
    Resource* pResource,
    const String& rSourceFilePath )
{
    HELIUM_ASSERT( pObjectPreprocessor );
    HELIUM_ASSERT( pResource );

    ShaderVariant* pVariant = Reflect::AssertCast< ShaderVariant >( pResource );

    // Parse the shader type and user option index from the variant name.
    Name variantName = pVariant->GetName();
    const tchar_t* pVariantNameString = *variantName;
    HELIUM_ASSERT( pVariantNameString );

    tchar_t shaderTypeCharacter = pVariantNameString[ 0 ];
    HELIUM_ASSERT( shaderTypeCharacter != TXT( '\0' ) );

    RShader::EType shaderType;
    switch( shaderTypeCharacter )
    {
    case TXT( 'v' ):
    {
        shaderType = RShader::TYPE_VERTEX;
        break;
    }

    case TXT( 'p' ):
    {
        shaderType = RShader::TYPE_PIXEL;
        break;
    }

    default:
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            ( TXT( "ShaderVariantResourceHandler: Failed to determine shader type from the name of object " )
              TXT( "\"%s\".\n" ) ),
            *pVariant->GetPath().ToString() );

        return false;
    }
    }

    uint32_t userOptionIndex = 0;
    ++pVariantNameString;
    int parseResult;
#if HELIUM_UNICODE
#if HELIUM_CC_CL
    parseResult = swscanf_s( pVariantNameString, TXT( "%" ) TSCNu32, &userOptionIndex );
#else
    parseResult = swscanf( pVariantNameString, TXT( "%" ) TSCNu32, &userOptionIndex );
#endif
#else
#if HELIUM_CC_CL
    parseResult = sscanf_s( pVariantNameString, TXT( "%" ) TSCNu32, &userOptionIndex );
#else
    parseResult = sscanf( pVariantNameString, TXT( "%" ) TSCNu32, &userOptionIndex );
#endif
#endif
    if( parseResult != 1 )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            ( TXT( "ShaderVariantResourceHandler: Failed to parse user shader option set index from the name of " )
              TXT( "option \"%s\".\n" ) ),
            *pVariant->GetPath().ToString() );

        return false;
    }

    // Get the parent shader.
    Shader* pShader = Reflect::AssertCast< Shader >( pVariant->GetOwner() );
    HELIUM_ASSERT( pShader );
    HELIUM_ASSERT( pShader->GetAnyFlagSet( GameObject::FLAG_PRECACHED ) );

    // Acquire the user preprocessor option set associated with the target shader type and user option set index.
    const Shader::Options& rUserOptions = pShader->GetUserOptions();

    DynArray< Name > toggleNames;
    DynArray< Shader::SelectPair > selectPairs;
    rUserOptions.GetOptionSetFromIndex( shaderType, userOptionIndex, toggleNames, selectPairs );

    DynArray< PlatformPreprocessor::ShaderToken > shaderTokens;

    size_t userToggleNameCount = toggleNames.GetSize();
    for( size_t toggleNameIndex = 0; toggleNameIndex < userToggleNameCount; ++toggleNameIndex )
    {
        PlatformPreprocessor::ShaderToken* pToken = shaderTokens.New();
        HELIUM_ASSERT( pToken );
        StringConverter< tchar_t, char >::Convert( pToken->name, *toggleNames[ toggleNameIndex ] );
        pToken->definition = "1";
    }

    size_t userSelectPairCount = selectPairs.GetSize();
    for( size_t selectPairIndex = 0; selectPairIndex < userSelectPairCount; ++selectPairIndex )
    {
        const Shader::SelectPair& rPair = selectPairs[ selectPairIndex ];

        PlatformPreprocessor::ShaderToken* pToken = shaderTokens.New();
        HELIUM_ASSERT( pToken );
        StringConverter< tchar_t, char >::Convert( pToken->name, *rPair.name );
        pToken->definition = "1";

        pToken = shaderTokens.New();
        HELIUM_ASSERT( pToken );
        StringConverter< tchar_t, char >::Convert( pToken->name, *rPair.choice );
        pToken->definition = "1";
    }

    size_t userShaderTokenCount = shaderTokens.GetSize();

    // Load the entire shader resource into memory.
    FileStream* pSourceFileStream = File::Open( rSourceFilePath, FileStream::MODE_READ );
    if( !pSourceFileStream )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            ( TXT( "ShaderVariantResourceHandler: Source file for shader variant resource \"%s\" failed to open " )
              TXT( "properly.\n" ) ),
            *pVariant->GetPath().ToString() );

        return false;
    }

    int64_t size64 = pSourceFileStream->GetSize();
    HELIUM_ASSERT( size64 != -1 );

    HELIUM_ASSERT( static_cast< uint64_t >( size64 ) <= static_cast< size_t >( -1 ) );
    if( size64 > static_cast< uint64_t >( static_cast< size_t >( -1 ) ) )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            ( TXT( "ShaderVariantResourceHandler: Source file for shader resource \"%s\" is too large to fit " )
              TXT( "into memory for preprocessing.\n" ) ),
            *pShader->GetPath().ToString() );

        delete pSourceFileStream;

        return false;
    }

    size_t size = static_cast< size_t >( size64 );

    DefaultAllocator allocator;
    void* pShaderSource = allocator.Allocate( size );
    HELIUM_ASSERT( pShaderSource );
    if( !pShaderSource )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            ( TXT( "ShaderVariantResourceHandler: Failed to allocate %" ) TPRIuSZ TXT( " bytes for loading the " )
              TXT( "source data of \"%s\" for preprocessing.\n" ) ),
            size,
            *pShader->GetPath().ToString() );

        delete pSourceFileStream;

        return false;
    }

    BufferedStream( pSourceFileStream ).Read( pShaderSource, 1, size );

    delete pSourceFileStream;

    // Compile each variant of system options for each shader profile in each supported target platform.
    const Shader::Options& rSystemOptions = pShader->GetSystemOptions();
    size_t systemOptionSetCount = rSystemOptions.ComputeOptionSetCount( shaderType );
    if( systemOptionSetCount > UINT32_MAX )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            ( TXT( "ShaderVariantResourceHandler: System option set count (%" ) TPRIuSZ TXT( ") in shader \"%s\" " )
              TXT( "exceeds the maximum supported (%" ) TPRIuSZ TXT( ").\n" ) ),
            systemOptionSetCount,
            *pShader->GetPath().ToString(),
            static_cast< size_t >( UINT32_MAX ) );

        allocator.Free( pShaderSource );

        return false;
    }

    uint32_t systemOptionSetCount32 = static_cast< uint32_t >( systemOptionSetCount );

    for( size_t platformIndex = 0; platformIndex < static_cast< size_t >( Cache::PLATFORM_MAX ); ++platformIndex )
    {
        PlatformPreprocessor* pPreprocessor = pObjectPreprocessor->GetPlatformPreprocessor(
                static_cast< Cache::EPlatform >( platformIndex ) );
        if( !pPreprocessor )
        {
            continue;
        }

        Resource::PreprocessedData& rPreprocessedData = pVariant->GetPreprocessedData(
                    static_cast< Cache::EPlatform >( platformIndex ) );

        ShaderVariant::PersistentResourceData persistentResourceData;
        persistentResourceData.m_resourceCount = systemOptionSetCount32;
        SaveObjectToPersistentDataBuffer(&persistentResourceData, rPreprocessedData.persistentDataBuffer);

        size_t shaderProfileCount = pPreprocessor->GetShaderProfileCount();
        size_t shaderCount = shaderProfileCount * systemOptionSetCount;

        DynArray< DynArray< uint8_t > >& rSubDataBuffers = rPreprocessedData.subDataBuffers;
        rSubDataBuffers.Reserve( shaderCount );
        rSubDataBuffers.Resize( 0 );
        rSubDataBuffers.Resize( shaderCount );
        rSubDataBuffers.Trim();

        rPreprocessedData.bLoaded = true;
    }

//     DynArray< uint8_t > compiledCodeBuffer;
//     DynArray< ShaderConstantBufferInfo > constantBuffers, pcSm4ConstantBuffers;
//     DynArray< ShaderSamplerInfo > samplerInputs;
//     DynArray< ShaderTextureInfo > textureInputs;

    CompiledShaderData csd_pc_sm4;

    for( size_t systemOptionSetIndex = 0; systemOptionSetIndex < systemOptionSetCount; ++systemOptionSetIndex )
    {
        rSystemOptions.GetOptionSetFromIndex( shaderType, systemOptionSetIndex, toggleNames, selectPairs );

        size_t systemToggleNameCount = toggleNames.GetSize();
        for( size_t toggleNameIndex = 0; toggleNameIndex < systemToggleNameCount; ++toggleNameIndex )
        {
            PlatformPreprocessor::ShaderToken* pToken = shaderTokens.New();
            HELIUM_ASSERT( pToken );
            StringConverter< tchar_t, char >::Convert( pToken->name, *toggleNames[ toggleNameIndex ] );
            pToken->definition = "1";
        }

        size_t systemSelectPairCount = selectPairs.GetSize();
        for( size_t selectPairIndex = 0; selectPairIndex < systemSelectPairCount; ++selectPairIndex )
        {
            const Shader::SelectPair& rPair = selectPairs[ selectPairIndex ];

            PlatformPreprocessor::ShaderToken* pToken = shaderTokens.New();
            HELIUM_ASSERT( pToken );
            StringConverter< tchar_t, char >::Convert( pToken->name, *rPair.name );
            pToken->definition = "1";

            pToken = shaderTokens.New();
            HELIUM_ASSERT( pToken );
            StringConverter< tchar_t, char >::Convert( pToken->name, *rPair.choice );
            pToken->definition = "1";
        }

        // Compile for PC shader model 4 first so that we can get the constant buffer information.
        PlatformPreprocessor* pPreprocessor = pObjectPreprocessor->GetPlatformPreprocessor( Cache::PLATFORM_PC );
        HELIUM_ASSERT( pPreprocessor );

        csd_pc_sm4.compiledCodeBuffer.Resize( 0 );
        bool bCompiled = CompileShader(
                             pVariant,
                             pPreprocessor,
                             Cache::PLATFORM_PC,
                             ShaderProfile::PC_SM4,
                             shaderType,
                             pShaderSource,
                             size,
                             shaderTokens,
                             csd_pc_sm4.compiledCodeBuffer );
        if( !bCompiled )
        {
            HELIUM_TRACE(
                TRACE_ERROR,
                ( TXT( "ShaderVariantResourceHandler: Failed to compile shader for PC shader model 4, which is " )
                  TXT( "needed for reflection purposes.  Additional shader targets will not be built.\n" ) ) );
        }
        else
        {
            csd_pc_sm4.constantBuffers.Resize( 0 );
            csd_pc_sm4.samplerInputs.Resize( 0 );
            csd_pc_sm4.textureInputs.Resize( 0 );
            bool bReadConstantBuffers = pPreprocessor->FillShaderReflectionData(
                                            ShaderProfile::PC_SM4,
                                            csd_pc_sm4.compiledCodeBuffer.GetData(),
                                            csd_pc_sm4.compiledCodeBuffer.GetSize(),
                                            csd_pc_sm4.constantBuffers,
                                            csd_pc_sm4.samplerInputs,
                                            csd_pc_sm4.textureInputs );
            if( !bReadConstantBuffers )
            {
                HELIUM_TRACE(
                    TRACE_ERROR,
                    ( TXT( "ShaderVariantResourceHandler: Failed to read reflection information for PC shader " )
                      TXT( "model 4.  Additional shader targets will not be built.\n" ) ) );
            }
            else
            {
                Resource::PreprocessedData& rPcPreprocessedData = pVariant->GetPreprocessedData(
                            Cache::PLATFORM_PC );
                DynArray< DynArray< uint8_t > >& rPcSubDataBuffers = rPcPreprocessedData.subDataBuffers;
                DynArray< uint8_t >& rPcSm4SubDataBuffer =
                    rPcSubDataBuffers[ ShaderProfile::PC_SM4 * systemOptionSetCount + systemOptionSetIndex ];

                Cache::WriteCacheObjectToBuffer(csd_pc_sm4, rPcSm4SubDataBuffer);

                // FOR EACH PLATFORM
                for( size_t platformIndex = 0;
                        platformIndex < static_cast< size_t >( Cache::PLATFORM_MAX );
                        ++platformIndex )
                {
                    PlatformPreprocessor* pPreprocessor = pObjectPreprocessor->GetPlatformPreprocessor(
                            static_cast< Cache::EPlatform >( platformIndex ) );
                    if( !pPreprocessor )
                    {
                        continue;
                    }

                    // GET PLATFORM'S SUBDATA BUFFER
                    Resource::PreprocessedData& rPreprocessedData = pVariant->GetPreprocessedData(
                                static_cast< Cache::EPlatform >( platformIndex ) );
                    DynArray< DynArray< uint8_t > >& rSubDataBuffers = rPreprocessedData.subDataBuffers;

                    size_t shaderProfileCount = pPreprocessor->GetShaderProfileCount();
                    for( size_t shaderProfileIndex = 0;
                            shaderProfileIndex < shaderProfileCount;
                            ++shaderProfileIndex )
                    {
                        CompiledShaderData csd;

                        // Already cached PC shader model 4...
                        if( shaderProfileIndex == ShaderProfile::PC_SM4 && platformIndex == Cache::PLATFORM_PC )
                        {
                            continue;
                        }

                        bCompiled = CompileShader(
                                        pVariant,
                                        pPreprocessor,
                                        platformIndex,
                                        shaderProfileIndex,
                                        shaderType,
                                        pShaderSource,
                                        size,
                                        shaderTokens,
                                        csd.compiledCodeBuffer );
                        if( !bCompiled )
                        {
                            continue;
                        }

                        csd.constantBuffers = csd_pc_sm4.constantBuffers;
                        csd.samplerInputs.Resize( 0 );
                        csd.textureInputs.Resize( 0 );
                        bReadConstantBuffers = pPreprocessor->FillShaderReflectionData(
                                                   shaderProfileIndex,
                                                   csd.compiledCodeBuffer.GetData(),
                                                   csd.compiledCodeBuffer.GetSize(),
                                                   csd.constantBuffers,
                                                   csd.samplerInputs,
                                                   csd.textureInputs );
                        if( !bReadConstantBuffers )
                        {
                            continue;
                        }

                        DynArray< uint8_t >& rTargetSubDataBuffer =
                            rSubDataBuffers[ shaderProfileIndex * systemOptionSetCount + systemOptionSetIndex ];
                        Cache::WriteCacheObjectToBuffer(csd, rTargetSubDataBuffer);
                    }
                }
            }
        }

        // Trim the system tokens off the shader token list for the next pass.
        shaderTokens.Resize( userShaderTokenCount );
    }

    allocator.Free( pShaderSource );

    return true;
}