Example #1
0
void Helium::Material::PreSerialize( const Reflect::Field* field )
{
    m_userOptions.Resize(0);

    Shader* pShader = m_spShader;
    if( pShader )
    {
        const Shader::Options& rUserOptions = pShader->GetUserOptions();

        DynamicArray< Name > enabledToggles;
        rUserOptions.GetOptionSetFromIndex(
            RShader::TYPE_FIRST,
            m_persistentResourceData.m_shaderVariantIndices[ 0 ],
            enabledToggles,
            m_userOptions );

        size_t enabledToggleCount = enabledToggles.GetSize();

        Shader::SelectPair optionPair;

        Name enabledChoice( TXT( "1" ) );
        Name disabledChoice( TXT( "0" ) );

        const DynamicArray< Shader::Toggle >& rUserToggles = rUserOptions.GetToggles();
        size_t userToggleCount = rUserToggles.GetSize();
        for( size_t userToggleIndex = 0; userToggleIndex < userToggleCount; ++userToggleIndex )
        {
            optionPair.name = rUserToggles[ userToggleIndex ].name;

            size_t enabledToggleIndex;
            for( enabledToggleIndex = 0; enabledToggleIndex < enabledToggleCount; ++enabledToggleIndex )
            {
                if( enabledToggles[ enabledToggleIndex ] == optionPair.name )
                {
                    break;
                }
            }

            optionPair.choice =
                ( enabledToggleIndex < enabledToggleCount ? enabledChoice : disabledChoice );

            m_userOptions.Push( optionPair );
        }
    }
}
/// @copydoc ResourceHandler::CacheResource()
bool MaterialResourceHandler::CacheResource(
    AssetPreprocessor* pAssetPreprocessor,
    Resource* pResource,
    const String& /*rSourceFilePath*/ )
{
    HELIUM_ASSERT( pAssetPreprocessor );
    HELIUM_ASSERT( pResource );

    Material* pMaterial = Reflect::AssertCast< Material >( pResource );
    Shader* pShader = pMaterial->GetShader();
    bool failedToWriteASubdata = false;
    
    StrongPtr< Material::PersistentResourceData > resource_data( new Material::PersistentResourceData() );

    // Compute the shader variant indices from the user options selected in the material, as the array of indices in
    // the material is not yet initialized.
    //uint32_t shaderVariantIndices[ RShader::TYPE_MAX ];
    if( pShader )
    {
        const Shader::Options& rShaderUserOptions = pShader->GetUserOptions();
        const DynamicArray< Shader::SelectPair >& rMaterialUserOptions = pMaterial->GetUserOptions();

        for( size_t shaderTypeIndex = 0; shaderTypeIndex < RShader::TYPE_MAX; ++shaderTypeIndex )
        {
            size_t optionSetIndex = rShaderUserOptions.GetOptionSetIndex(
                static_cast< RShader::EType >( shaderTypeIndex ),
                rMaterialUserOptions.GetData(),
                rMaterialUserOptions.GetSize() );
            resource_data->m_shaderVariantIndices[ shaderTypeIndex ] = static_cast< uint32_t >( optionSetIndex );
        }
    }
    else
    {
        MemoryZero( resource_data->m_shaderVariantIndices, sizeof( resource_data->m_shaderVariantIndices ) );
    }

    size_t float1ParameterCount = pMaterial->GetFloat1ParameterCount();
    size_t float2ParameterCount = pMaterial->GetFloat2ParameterCount();
    size_t float3ParameterCount = pMaterial->GetFloat3ParameterCount();
    size_t float4ParameterCount = pMaterial->GetFloat4ParameterCount();

    Name parameterConstantBufferName = Material::GetParameterConstantBufferName();
    
    for( size_t platformIndex = 0; platformIndex < static_cast< size_t >( Cache::PLATFORM_MAX ); ++platformIndex )
    {
        PlatformPreprocessor* pPreprocessor = pAssetPreprocessor->GetPlatformPreprocessor(
            static_cast< Cache::EPlatform >( platformIndex ) );

        if( !pPreprocessor )
        {
            continue;
        }

        Resource::PreprocessedData& rPreprocessedData = pResource->GetPreprocessedData(
            static_cast< Cache::EPlatform >( platformIndex ) );
        SaveObjectToPersistentDataBuffer(resource_data.Get(), rPreprocessedData.persistentDataBuffer);
        rPreprocessedData.bLoaded = true;

        // Write out the parameter constant buffer data as the resource sub-data.
        size_t shaderProfileCount = pPreprocessor->GetShaderProfileCount();

        DynamicArray< DynamicArray< uint8_t > >& rSubDataBuffers = rPreprocessedData.subDataBuffers;
        rSubDataBuffers.Clear();
        rSubDataBuffers.Reserve( shaderProfileCount * RShader::TYPE_MAX );
        rSubDataBuffers.Resize( shaderProfileCount * RShader::TYPE_MAX );

        if( pShader )
        {
    //        deserializer.SetByteSwapping( bSwapBytes );

            for( size_t shaderTypeIndex = 0; shaderTypeIndex < RShader::TYPE_MAX; ++shaderTypeIndex )
            {
                RShader::EType shaderType = static_cast< RShader::EType >( shaderTypeIndex );
                size_t variantLoadId = pShader->BeginLoadVariant(
                    shaderType,
                    resource_data->m_shaderVariantIndices[ shaderTypeIndex ] );
                if( IsInvalid( variantLoadId ) )
                {
                    continue;
                }

                ShaderVariantPtr spVariant;
                while( !pShader->TryFinishLoadVariant( variantLoadId, spVariant ) )
                {
                }

                ShaderVariant* pVariant = spVariant;
                if( !pVariant )
                {
                    continue;
                }

                const Resource::PreprocessedData& rVariantData = pVariant->GetPreprocessedData(
                    static_cast< Cache::EPlatform >( platformIndex ) );
                HELIUM_ASSERT( rVariantData.bLoaded );

                const DynamicArray< DynamicArray< uint8_t > >& rVariantSubDataBuffers = rVariantData.subDataBuffers;
                size_t variantSubDataCount = rVariantSubDataBuffers.GetSize();
                HELIUM_ASSERT( variantSubDataCount != 0 );
                HELIUM_ASSERT( variantSubDataCount % shaderProfileCount == 0 );
                size_t systemOptionSetCount = variantSubDataCount / shaderProfileCount;

                for( size_t profileIndex = 0; profileIndex < shaderProfileCount; ++profileIndex )
                {
                    // Get the first option set of each profile
                    const DynamicArray< uint8_t >& rVariantSubData =
                        rVariantSubDataBuffers[ profileIndex * systemOptionSetCount ];

                    Reflect::ObjectPtr variantSubDataObjectPtr = 
                        Cache::ReadCacheObjectFromBuffer(rVariantSubData);

                    if (!variantSubDataObjectPtr.ReferencesObject())
                    {
                        HELIUM_TRACE(
                            TraceLevels::Error,
                            "MaterialResourceHandler: A shader variant subdata could not be read. (Option Set: %d Profile: %d)",
                            0,
                            profileIndex );

                        failedToWriteASubdata = true;
                    }
                    else if (!variantSubDataObjectPtr->IsA(Reflect::GetMetaClass<CompiledShaderData>()))
                    {
                        HELIUM_TRACE(
                            TraceLevels::Error,
                            "MaterialResourceHandler: A shader variant subdata was of an unexpected type. (Option Set: %d Profile: %d)\n",
                            0,
                            profileIndex );

                        failedToWriteASubdata = true;

                    }
                    else
                    {
                        CompiledShaderData &csd = *Reflect::AssertCast<CompiledShaderData>(variantSubDataObjectPtr.Get());
                        

                        size_t bufferCount = csd.constantBuffers.GetSize();
                        for( size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex )
                        {
                            const ShaderConstantBufferInfo& rBufferInfo = csd.constantBuffers[ bufferIndex ];
                            if( rBufferInfo.name != parameterConstantBufferName )
                            {
                                continue;
                            }

                            size_t bufferSize = rBufferInfo.size;

                            DynamicArray< uint8_t >& rMaterialSubData =
                                rSubDataBuffers[ profileIndex * RShader::TYPE_MAX + shaderTypeIndex ];
                            rMaterialSubData.Clear();
                            rMaterialSubData.Reserve( bufferSize );
                            rMaterialSubData.Add( 0, bufferSize );

                            DynamicMemoryStream memoryStream( &rMaterialSubData );
                            ByteSwappingStream byteSwapStream( &memoryStream );
                            Stream& rOutputStream = memoryStream;
                            //Stream& rOutputStream =
                            //    ( bSwapBytes
                            //    ? static_cast< Stream& >( byteSwapStream )
                            //    : static_cast< Stream& >( memoryStream ) );

                            const DynamicArray< ShaderConstantInfo >& rConstants = rBufferInfo.constants;
                            size_t constantCount = rConstants.GetSize();
                            for( size_t constantIndex = 0; constantIndex < constantCount; ++constantIndex )
                            {
                                const ShaderConstantInfo& rConstantInfo = rConstants[ constantIndex ];
                                Name constantName = rConstantInfo.name;

                                size_t parameterIndex;
                                for( parameterIndex = 0; parameterIndex < float1ParameterCount; ++parameterIndex )
                                {
                                    const Material::Float1Parameter& rParameter = pMaterial->GetFloat1Parameter(
                                        parameterIndex );
                                    if( rParameter.name == constantName )
                                    {
                                        rOutputStream.Seek( rConstantInfo.offset, SeekOrigins::Begin );
                                        rOutputStream.Write(
                                            &rParameter.value,
                                            sizeof( float32_t ),
                                            Min< size_t >( 1, rConstantInfo.size / sizeof( float32_t ) ) );

                                        break;
                                    }
                                }

                                if( parameterIndex >= float1ParameterCount )
                                {
                                    for( parameterIndex = 0; parameterIndex < float2ParameterCount; ++parameterIndex )
                                    {
                                        const Material::Float2Parameter& rParameter = pMaterial->GetFloat2Parameter(
                                            parameterIndex );
                                        if( rParameter.name == constantName )
                                        {
                                            rOutputStream.Seek( rConstantInfo.offset, SeekOrigins::Begin );
                                            rOutputStream.Write(
                                                &rParameter.value,
                                                sizeof( float32_t ),
                                                Min< size_t >( 2, rConstantInfo.size / sizeof( float32_t ) ) );

                                            break;
                                        }
                                    }

                                    if( parameterIndex >= float2ParameterCount )
                                    {
                                        for( parameterIndex = 0;
                                            parameterIndex < float3ParameterCount;
                                            ++parameterIndex )
                                        {
                                            const Material::Float3Parameter& rParameter = pMaterial->GetFloat3Parameter(
                                                parameterIndex );
                                            if( rParameter.name == constantName )
                                            {
                                                rOutputStream.Seek( rConstantInfo.offset, SeekOrigins::Begin );
                                                rOutputStream.Write(
                                                    &rParameter.value,
                                                    sizeof( float32_t ),
                                                    Min< size_t >( 3, rConstantInfo.size / sizeof( float32_t ) ) );

                                                break;
                                            }
                                        }

                                        if( parameterIndex >= float3ParameterCount )
                                        {
                                            for( parameterIndex = 0;
                                                parameterIndex < float4ParameterCount;
                                                ++parameterIndex )
                                            {
                                                const Material::Float4Parameter& rParameter =
                                                    pMaterial->GetFloat4Parameter( parameterIndex );
                                                if( rParameter.name == constantName )
                                                {
                                                    rOutputStream.Seek(
                                                        rConstantInfo.offset,
                                                        SeekOrigins::Begin );
                                                    rOutputStream.Write(
                                                        &rParameter.value,
                                                        sizeof( float32_t ),
                                                        Min< size_t >( 4, rConstantInfo.size / sizeof( float32_t ) ) );

                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            break;
                        }
                    }
                }
            }
        }
    }


    return !failedToWriteASubdata;
}
Example #3
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;
}
Example #4
0
/// @copydoc GameObject::BeginPrecacheResourceData()
bool Material::BeginPrecacheResourceData()
{
#if HELIUM_TOOLS
    // Convert shader options to variant indices if we just loaded a set of options.
    if( m_bLoadedOptions )
    {
        MemoryZero( m_persistentResourceData.m_shaderVariantIndices, sizeof( m_persistentResourceData.m_shaderVariantIndices ) );

        Shader* pShader = m_spShader;
        if( pShader )
        {
            const Shader::Options& rUserOptions = pShader->GetUserOptions();

            for( size_t shaderTypeIndex = 0;
                shaderTypeIndex < HELIUM_ARRAY_COUNT( m_persistentResourceData.m_shaderVariantIndices );
                ++shaderTypeIndex )
            {
                m_persistentResourceData.m_shaderVariantIndices[ shaderTypeIndex ] = static_cast< uint32_t >( rUserOptions.GetOptionSetIndex(
                    static_cast< RShader::EType >( shaderTypeIndex ),
                    m_userOptions.GetData(),
                    m_userOptions.GetSize() ) );
            }
        }

        m_userOptions.Clear();

        m_bLoadedOptions = false;
    }
#endif

    // Preload shader variant resources.
    Shader* pShader = m_spShader;
    if( !pShader )
    {
        for( size_t shaderTypeIndex = 0; shaderTypeIndex < HELIUM_ARRAY_COUNT( m_shaderVariants ); ++shaderTypeIndex )
        {
            HELIUM_ASSERT( IsInvalid( m_shaderVariantLoadIds[ shaderTypeIndex ] ) );
            m_shaderVariants[ shaderTypeIndex ].Release();
        }
    }
    else
    {
        for( size_t shaderTypeIndex = 0; shaderTypeIndex < HELIUM_ARRAY_COUNT( m_shaderVariants ); ++shaderTypeIndex )
        {
            HELIUM_ASSERT( IsInvalid( m_shaderVariantLoadIds[ shaderTypeIndex ] ) );
            m_shaderVariantLoadIds[ shaderTypeIndex ] = pShader->BeginLoadVariant(
                static_cast< RShader::EType >( shaderTypeIndex ),
                m_persistentResourceData.m_shaderVariantIndices[ shaderTypeIndex ] );
        }
    }

    // Preload the constant buffers for shader parameters.
    Renderer* pRenderer = Renderer::GetStaticInstance();
    if( pRenderer )
    {
        for( size_t shaderTypeIndex = 0; shaderTypeIndex < HELIUM_ARRAY_COUNT( m_constantBuffers ); ++shaderTypeIndex )
        {
            HELIUM_ASSERT( !m_constantBuffers[ shaderTypeIndex ] );
            HELIUM_ASSERT( IsInvalid( m_constantBufferLoadIds[ shaderTypeIndex ] ) );

            size_t bufferSize = GetSubDataSize( static_cast< uint32_t >( shaderTypeIndex ) );
            if( bufferSize == 0 )
            {
                continue;
            }

            RConstantBufferPtr spBuffer = pRenderer->CreateConstantBuffer(
                bufferSize,
                RENDERER_BUFFER_USAGE_STATIC );
            if( !spBuffer )
            {
                HELIUM_TRACE(
                    TraceLevels::Error,
                    ( TXT( "Material::BeginPrecacheResourceData(): Failed to allocate constant buffer of %" )
                    TPRIuSZ TXT( " bytes for parameter usage for material \"%s\".\n" ) ),
                    bufferSize,
                    *GetPath().ToString() );

                continue;
            }

            void* pBufferData = spBuffer->Map();
            if( !pBufferData )
            {
                HELIUM_TRACE(
                    TraceLevels::Error,
                    ( TXT( "Material::BeginPrecacheResourceData(): Failed to map constant buffer data for " )
                    TXT( "material \"%s\".\n" ) ),
                    *GetPath().ToString() );

                continue;
            }

            size_t loadId = BeginLoadSubData( pBufferData, static_cast< uint32_t >( shaderTypeIndex ) );
            if( IsInvalid( loadId ) )
            {
                HELIUM_TRACE(
                    TraceLevels::Error,
                    ( TXT( "Material::BeginPrecacheResourceData(): Failed to begin loading resource sub-data %" )
                    TPRIuSZ TXT( " for material \"%s\".\n" ) ),
                    shaderTypeIndex,
                    *GetPath().ToString() );

                spBuffer->Unmap();

                continue;
            }

            m_constantBuffers[ shaderTypeIndex ] = spBuffer;
            m_constantBufferLoadIds[ shaderTypeIndex ] = loadId;
        }
    }

    return true;
}
Example #5
0
/// @copydoc GameObject::Serialize()
void Material::Serialize( Serializer& s )
{
    L_SERIALIZE_BASE( s );

    s << L_TAGGED( m_spShader );

#if L_EDITOR
    if( s.CanResolveTags() )
    {
        m_userOptions.Resize( 0 );

        Serializer::EMode serializerMode = s.GetMode();
        bool bSaving = ( serializerMode == Serializer::MODE_SAVE );
        bool bLoading = ( serializerMode == Serializer::MODE_LOAD );

        if( bSaving )
        {
            // Aggregate all user options from the resource information into the single "m_userOptions" array.
            Shader* pShader = m_spShader;
            if( pShader )
            {
                const Shader::Options& rUserOptions = pShader->GetUserOptions();

                DynArray< Name > enabledToggles;
                rUserOptions.GetOptionSetFromIndex(
                    RShader::TYPE_FIRST,
                    m_shaderVariantIndices[ 0 ],
                    enabledToggles,
                    m_userOptions );

                size_t enabledToggleCount = enabledToggles.GetSize();

                Shader::SelectPair optionPair;

                Name enabledChoice( TXT( "1" ) );
                Name disabledChoice( TXT( "0" ) );

                const DynArray< Shader::Toggle >& rUserToggles = rUserOptions.GetToggles();
                size_t userToggleCount = rUserToggles.GetSize();
                for( size_t userToggleIndex = 0; userToggleIndex < userToggleCount; ++userToggleIndex )
                {
                    optionPair.name = rUserToggles[ userToggleIndex ].name;

                    size_t enabledToggleIndex;
                    for( enabledToggleIndex = 0; enabledToggleIndex < enabledToggleCount; ++enabledToggleIndex )
                    {
                        if( enabledToggles[ enabledToggleIndex ] == optionPair.name )
                        {
                            break;
                        }
                    }

                    optionPair.choice =
                        ( enabledToggleIndex < enabledToggleCount ? enabledChoice : disabledChoice );

                    m_userOptions.Push( optionPair );
                }
            }
        }
        else if( bLoading )
        {
            DynArray< String > propertyTagNames;
            s.GetPropertyTagNames( propertyTagNames );

            Shader::SelectPair optionPair;
            optionPair.choice.Clear();

            size_t propertyTagCount = propertyTagNames.GetSize();
            for( size_t tagIndex = 0; tagIndex < propertyTagCount; ++tagIndex )
            {
                const String& rTagName = propertyTagNames[ tagIndex ];
                if( !rTagName.Contains( TXT( '.' ) ) )
                {
                    optionPair.name.Set( rTagName );
                    m_userOptions.Push( optionPair );
                }
            }
        }

        s.PushPropertyFlags( Serializer::FLAG_EDITOR_ONLY );

        size_t userOptionCount = m_userOptions.GetSize();
        for( size_t optionIndex = 0; optionIndex < userOptionCount; ++optionIndex )
        {
            Shader::SelectPair& rOptionPair = m_userOptions[ optionIndex ];
            s << Serializer::Tag( *rOptionPair.name ) << rOptionPair.choice;
        }

        // XXX TMC TODO: Replace with flexible name resolution support (a la m_userOptions above).
        s << L_TAGGED_STRUCT_DYNARRAY( m_float1Parameters );
        s << L_TAGGED_STRUCT_DYNARRAY( m_float2Parameters );
        s << L_TAGGED_STRUCT_DYNARRAY( m_float3Parameters );
        s << L_TAGGED_STRUCT_DYNARRAY( m_float4Parameters );

        s.PopPropertyFlags();

        if( bSaving )
        {
            m_userOptions.Clear();
        }
        else if( bLoading )
        {
            m_bLoadedOptions = true;
        }
    }
#endif

    // XXX TMC TODO: Replace with flexible name resolution support (a la m_userOptions above).
    s << L_TAGGED_STRUCT_DYNARRAY( m_textureParameters );
}