/// Free a block of memory previously allocated for FreeType.
///
/// @param[in] pMemory  Handle to the source memory manager.
/// @param[in] pBlock   Block of memory to free.
///
/// @see FreeTypeAllocate(), FreeTypeReallocate()
static void FreeTypeFree( FT_Memory /*pMemory*/, void* pBlock )
{
    // Our allocators allow for null pointers to be passed to their free functions, so we do not need to validate the
    // block parameter.
    DefaultAllocator allocator;
	allocator.FreeAligned( pBlock );
}
/// Shut down this package loader.
///
/// @see Initialize()
void CachePackageLoader::Shutdown()
{
	DefaultAllocator allocator;

	AsyncLoader* pAsyncLoader = AsyncLoader::GetInstance();
	HELIUM_ASSERT( pAsyncLoader );

	size_t loadRequestCount = m_loadRequests.GetSize();
	for( size_t requestIndex = 0; requestIndex < loadRequestCount; ++requestIndex )
	{
		if( m_loadRequests.IsElementValid( requestIndex ) )
		{
			LoadRequest* pRequest = m_loadRequests[ requestIndex ];
			HELIUM_ASSERT( pRequest );
			if( IsValid( pRequest->asyncLoadId ) )
			{
				pAsyncLoader->SyncRequest( pRequest->asyncLoadId );
			}

			allocator.Free( pRequest->pAsyncLoadBuffer );

			m_loadRequestPool.Release( pRequest );
		}
	}

	m_loadRequests.Clear();

	m_pCache = NULL;
	m_bFinishedCacheTocLoad = false;
}
Example #3
0
TEST( MemoryRouter, differentAllocationMethods )
{
   DefaultAllocator defaultAllocator;

   // at the beginning, no memory is allocated
   CPPUNIT_ASSERT_EQUAL( (ulong)0, defaultAllocator.getMemoryUsed() );
   
   MemoryRouter& router = TSingleton< MemoryRouter >::getInstance();
   void* ptr = router.alloc( 12, AM_ALIGNED_16, &defaultAllocator );

   // memory was indeed allocated - but since we were allocating an aligned block,
   // a larger block was allocated
   CPPUNIT_ASSERT( ptr != NULL );
   CPPUNIT_ASSERT( (ulong)12 < defaultAllocator.getMemoryUsed() );

   // and that the returned address is aligned to a 16 byte boundary
   bool isAligned = MemoryUtils::isAddressAligned( ptr );
   CPPUNIT_ASSERT( isAligned );

   // cleanup
   router.dealloc( ptr, AM_ALIGNED_16 );

   // allocated memory was correctly released - the entire amount
   CPPUNIT_ASSERT_EQUAL( (ulong)0, defaultAllocator.getMemoryUsed() );
}
Example #4
0
TEST( JsonParserTest, ParseEmptyJson )
{
    using namespace StevensDev::sgdd;
    using namespace StevensDev::sgdm;

    DefaultAllocator<JsonEntity> def;
    def.get( 1 );

    // global allocator, object with whitespace
    EXPECT_NO_THROW( StackGuard<JsonEntity> guard2(
        nullptr, JsonParser::fromString( "{ }" ) ) );

    // global allocator, array
    EXPECT_NO_THROW( StackGuard<JsonEntity> guard3(
        nullptr,
        JsonParser::fromString( "[]" ) ) );

    // global allocator, array with whitespace
    EXPECT_NO_THROW( StackGuard<JsonEntity> guard4(
        nullptr,
        JsonParser::fromString( "[ ]" ) ) );

    // custom allocator
    EXPECT_NO_THROW( StackGuard<JsonEntity> guard5(
        &def, JsonParser::fromString( "{}", &def ) ) );

    // custom allocator, with whitespace
    EXPECT_NO_THROW( StackGuard<JsonEntity> guard6(
        &def, JsonParser::fromString( "{ }", &def ) ) );
}
/// Allocate a block of memory for FreeType.
///
/// @param[in] pMemory  Handle to the source memory manager.
/// @param[in] size     Number of bytes to allocate.
///
/// @return  Address of the newly allocated block of memory, or null if allocation failed.
///
/// @see FreeTypeFree(), FreeTypeReallocate()
static void* FreeTypeAllocate( FT_Memory /*pMemory*/, long size )
{
    // FreeType uses setjmp()/longjmp(), and because our SSE settings bleed into dependency projects, jmp_buf needs to
    // be 16-byte aligned for backing up SSE register states.  To avoid misaligned jmp_buf instances, we align all
    // allocations of 16 bytes or greater to 16-byte boundaries.
    DefaultAllocator allocator;
	return allocator.AllocateAligned( HELIUM_SIMD_ALIGNMENT, size );
}
Example #6
0
/// Write out a formatted message to this log using a variable argument list.
///
/// @param[in] level    Logging level.
/// @param[in] pFormat  Format string.
/// @param[in] argList  Initialized variable argument list for the format arguments (va_start() should have already
///                     been called on this as necessary).
void Helium::Trace::OutputVa( ETraceLevel level, const tchar_t* pFormat, va_list argList )
{
    HELIUM_ASSERT( pFormat );

    MutexScopeLock scopeLock( m_mutex );

    if( level < m_level )
    {
        return;
    }

    if( m_bNewLine || level != m_lastMessageLevel )
    {
        OutputImplementation( GetLevelString( level ) );
    }

    m_bNewLine = false;
    m_lastMessageLevel = level;

    tchar_t buffer[ DEFAULT_MESSAGE_BUFFER_SIZE ];

    va_list argListTemp = argList;
    int result = StringFormatVa( buffer, HELIUM_ARRAY_COUNT( buffer ), pFormat, argListTemp );

    if( static_cast< unsigned int >( result ) < HELIUM_ARRAY_COUNT( buffer ) )
    {
        OutputImplementation( buffer );
        m_bNewLine = ( buffer[ result - 1 ] == TXT( '\n' ) );

        return;
    }

    if( result < 0 )
    {
        argListTemp = argList;
        result = StringFormatVa( NULL, 0, pFormat, argListTemp );
        HELIUM_ASSERT( result >= 0 );
    }

    size_t bufferSize = static_cast< size_t >( result ) + 1;

    DefaultAllocator allocator;
    tchar_t* pBuffer = static_cast< tchar_t* >( allocator.Allocate( sizeof( tchar_t ) * bufferSize ) );
    HELIUM_ASSERT( pBuffer );
    if( pBuffer )
    {
        argListTemp = argList;
        result = StringFormatVa( pBuffer, bufferSize, pFormat, argListTemp );

        HELIUM_ASSERT( result == static_cast< int >( bufferSize - 1 ) );
        OutputImplementation( pBuffer );
        m_bNewLine = ( pBuffer[ result - 1 ] == TXT( '\n' ) );

        allocator.Free( pBuffer );
    }
}
Example #7
0
TEST( DefaultAllocator, threadSafety )
{
   Thread thread1;
   Thread thread2;

   DefaultAllocator allocator;
   CPPUNIT_ASSERT_EQUAL( (ulong)0, allocator.getMemoryUsed() );

   MultithreadedAllocFunc allocOperator1( allocator );
   MultithreadedAllocFunc allocOperator2( allocator );

   thread1.start( allocOperator1 );
   thread2.start( allocOperator2 );

   thread1.join();
   thread2.join();

   CPPUNIT_ASSERT_EQUAL( (ulong)0, allocator.getMemoryUsed() );
}
Example #8
0
TEST( MemoryRouter, objectsPlacement )
{
   DefaultAllocator defaultAllocator;
   MemoryRouter& router = TSingleton< MemoryRouter >::getInstance();
   ulong initialAllocatedMemorySize = router.getMemoryUsed();

   TestClass* obj = new ( &defaultAllocator ) TestClass();
   CPPUNIT_ASSERT( obj != NULL );

   // no memory was allocated in the pool internally managed by the router
   CPPUNIT_ASSERT_EQUAL( (ulong)0, router.getMemoryUsed() - initialAllocatedMemorySize );

   // entire memory was allocated in the specified external pool
   ulong expectedSize = MemoryUtils::calcAlignedSize( (ulong)(sizeof( TestClass ) + sizeof(void*)) );
   CPPUNIT_ASSERT_EQUAL( expectedSize, defaultAllocator.getMemoryUsed() );

   delete obj;
   CPPUNIT_ASSERT_EQUAL( (ulong)0, router.getMemoryUsed() - initialAllocatedMemorySize );
   CPPUNIT_ASSERT_EQUAL( (ulong)0, defaultAllocator.getMemoryUsed() );
}
Example #9
0
/// Assignment operator.
///
/// @param[in] rSource  Source object from which to copy.
///
/// @return  Reference to this object.
XmlTemplateSerializer::PropertyData& XmlTemplateSerializer::PropertyData::operator=( const PropertyData& rSource )
{
    if( this != &rSource )
    {
        DefaultAllocator allocator;

        allocator.Free( m_pData );
        m_pData = NULL;

        m_name = rSource.m_name;
        m_size = rSource.m_size;
        if( m_size != 0 )
        {
            HELIUM_ASSERT( rSource.m_pData );

            m_pData = allocator.Allocate( m_size );
            HELIUM_ASSERT( m_pData );
            MemoryCopy( m_pData, rSource.m_pData, m_size );
        }
    }

    return *this;
}
Example #10
0
/// Reallocate a block of memory for FreeType.
///
/// @param[in] pMemory      Handle to the source memory manager.
/// @param[in] currentSize  Current block size, in bytes.
/// @param[in] newSize      New block size, in bytes.
/// @param[in] pBlock       Block to reallocate.
///
/// @return  Pointer to the reallocated block of memory, or null if reallocation failed.
///
/// @see FreeTypeAllocate(), FreeTypeFree()
static void* FreeTypeReallocate( FT_Memory /*pMemory*/, long currentSize, long newSize, void* pBlock )
{
    DefaultAllocator allocator;

    // We cannot call Reallocate() if either the old or new size requires SIMD alignment (see FreeTypeAllocate() for
    // more information about why we need to align some allocations), so call Free()/Allocate()/AllocateAligned()
    // instead as appropriate.
    if( newSize < HELIUM_SIMD_SIZE )
    {
        if( currentSize < HELIUM_SIMD_SIZE )
        {
            // Our allocators allow for null pointers to be passed to their reallocate functions, so we do not need to
            // validate the block parameter.
            pBlock = allocator.Reallocate( pBlock, newSize );
        }
        else
        {
            void* pOldBlock = pBlock;

            // Our allocators treat a realloc() with a size of zero as a free, so simulate that functionality here.
            pBlock = NULL;
            if( newSize )
            {
                pBlock = allocator.Allocate( newSize );
                if( pBlock )
                {
                    HELIUM_ASSERT( newSize < currentSize );
                    MemoryCopy( pBlock, pOldBlock, newSize );
                }
            }

            allocator.Free( pOldBlock );
        }
    }
    else
    {
        void* pOldBlock = pBlock;

        // Note that newSize >= HELIUM_SIMD_SIZE, so we don't need to check for non-zero sizes here.
        pBlock = allocator.AllocateAligned( HELIUM_SIMD_ALIGNMENT, newSize );
        if( pBlock )
        {
            MemoryCopy( pBlock, pOldBlock, Min( currentSize, newSize ) );
        }

        allocator.Free( pOldBlock );
    }

    return pBlock;
}
/// @copydoc ResourceHandler::CacheResource()
bool ShaderResourceHandler::CacheResource(
    ObjectPreprocessor* pObjectPreprocessor,
    Resource* pResource,
    const String& rSourceFilePath )
{
    HELIUM_ASSERT( pObjectPreprocessor );
    HELIUM_ASSERT( pResource );

    const Shader* pShader = Reflect::AssertCast< const Shader >( pResource );
    GameObjectPath shaderPath = pShader->GetPath();

    HELIUM_TRACE( TraceLevels::Info, TXT( "ShaderResourceHandler: Caching \"%s\".\n" ), *shaderPath.ToString() );

    DefaultAllocator allocator;

    FileStream* pSourceFileStream = FileStream::OpenFileStream( rSourceFilePath, FileStream::MODE_READ );
    if( !pSourceFileStream )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "ShaderResourceHandler: Source file for shader resource \"%s\" failed to open properly.\n" ),
            *shaderPath.ToString() );

        return false;
    }

    // Load the entire shader resource into memory.
    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(
            TraceLevels::Error,
            ( TXT( "ShaderResourceHandler: Source file for shader resource \"%s\" is too large to fit into " )
            TXT( "memory for preprocessing.\n" ) ),
            *shaderPath.ToString() );

        delete pSourceFileStream;

        return false;
    }

    size_t size = static_cast< size_t >( size64 );

    void* pShaderData = allocator.Allocate( size );
    HELIUM_ASSERT( pShaderData );
    if( !pShaderData )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            ( TXT( "ShaderResourceHandler: Failed to allocate %" ) TPRIuSZ TXT( " bytes for loading the source " )
            TXT( "data of \"%s\" for preprocessing.\n" ) ),
            size,
            *shaderPath.ToString() );

        delete pSourceFileStream;

        return false;
    }

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

    delete pSourceFileStream;

    // Parse all preprocessor toggle and selection tokens from the shader source.
    Shader::PersistentResourceData resourceData;

    const char* pLineEnd = static_cast< const char* >( pShaderData );
    const char* pShaderEnd = pLineEnd + size;

    do
    {
        const char* pLineStart = pLineEnd;
        while( pLineEnd < pShaderEnd )
        {
            char character = *pLineEnd;
            if( character == '\n' || character == '\r' )
            {
                break;
            }

            ++pLineEnd;
        }

        ParseLine( shaderPath, resourceData, pLineStart, pLineEnd );

        while( pLineEnd < pShaderEnd )
        {
            char character = *pLineEnd;
            if( character != '\n' && character != '\r' )
            {
                break;
            }

            ++pLineEnd;
        }
    } while( pLineEnd < pShaderEnd );

    allocator.Free( pShaderData );

    // Serialize the persistent shader resource data 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;
        }

        Resource::PreprocessedData& rPreprocessedData = pResource->GetPreprocessedData(
            static_cast< Cache::EPlatform >( platformIndex ) );
        SaveObjectToPersistentDataBuffer(&resourceData, rPreprocessedData.persistentDataBuffer);
        rPreprocessedData.subDataBuffers.Resize( 0 );
        rPreprocessedData.bLoaded = true;
    }

    

    return true;
}
Example #12
0
/// Create a new object.
///
/// @param[out] rspObject             Pointer to the newly created object if object creation was successful.  Note that
///                                   any object reference stored in this strong pointer prior to calling this function
///                                   will always be cleared by this function, regardless of whether object creation is
///                                   successful.
/// @param[in]  pType                 Type of object to create.
/// @param[in]  name                  Object name.
/// @param[in]  pOwner                Object owner.
/// @param[in]  pTemplate             Optional override template object.  If null, the default template for the
///                                   specified type will be used.
/// @param[in]  bAssignInstanceIndex  True to assign an instance index to the object, false to leave the index
///                                   invalid.
///
/// @return  True if object creation was successful, false if not.
///
/// @see Create()
bool GameObject::CreateObject(
    GameObjectPtr& rspObject,
    const GameObjectType* pType,
    Name name,
    GameObject* pOwner,
    GameObject* pTemplate,
    bool bAssignInstanceIndex )
{
    HELIUM_ASSERT( pType );

    HELIUM_TRACE(
        TraceLevels::Debug,
        TXT( "GameObject::CreateObject(): Creating object named \"%s\" of type \"%s\" owned by \"%s\".\n"),
        *name,
        *pType->GetName(),
        !pOwner ? TXT("[none]") : *pOwner->GetPath().ToString());

    rspObject.Release();

    // Get the appropriate template object.
    GameObject* pObjectTemplate = pTemplate;
    if( pObjectTemplate )
    {
        if( pType->GetFlags() & GameObjectType::FLAG_NO_TEMPLATE && pType->GetTemplate() != pObjectTemplate )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "GameObject::CreateObject(): Objects of type \"%s\" cannot be used as templates.\n" ),
                *pType->GetName() );

            return false;
        }
    }
    else
    {
        pObjectTemplate = pType->GetTemplate();
        HELIUM_ASSERT( pObjectTemplate );
    }

    // Make sure the object template is of the correct type.
    if( !pObjectTemplate->IsInstanceOf( pType ) )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "GameObject::CreateObject: Template object \"%s\" is not of type \"%s\".\n" ),
            *pTemplate->GetPath().ToString(),
            pType->GetName().Get() );
        HELIUM_ASSERT_FALSE();

        return false;
    }

    // Allocate memory for and create the object.
    DefaultAllocator allocator;

    size_t bufferSize = pObjectTemplate->GetInstanceSize();
    void* pObjectMemory = allocator.AllocateAligned( HELIUM_SIMD_ALIGNMENT, bufferSize );
    HELIUM_ASSERT( pObjectMemory );
    GameObject* pObject = pObjectTemplate->InPlaceConstruct( pObjectMemory, StandardCustomDestroy );
    HELIUM_ASSERT( pObject == pObjectMemory );
    rspObject = pObject;

    pObject->m_spTemplate = pTemplate;

    // Initialize the object based on its default.
    pObjectTemplate->CopyTo(pObject);

    // Attempt to register the object and set its name.
    RenameParameters nameParameters;
    nameParameters.name = name;
    nameParameters.spOwner = pOwner;
    if( bAssignInstanceIndex )
    {
        nameParameters.instanceIndex = INSTANCE_INDEX_AUTO;
    }

    if ( !RegisterObject( pObject ) )
    {            
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "GameObject::CreateObject(): RegisterObject() failed for GameObject \"%s\" owned by \"%s\".\n" ),
            *name,
            !pOwner ? TXT("[none]") : *pOwner->GetPath().ToString());

        HELIUM_ASSERT_FALSE();

        rspObject.Release();

        return false;
    }

    if( !pObject->Rename( nameParameters ) )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "GameObject::CreateObject(): Rename() failed for GameObject \"%s\" owned by \"%s\".\n" ),
            *name,
            !pOwner ? TXT("[none]") : *pOwner->GetPath().ToString());

        HELIUM_ASSERT_FALSE();

        rspObject.Release();

        return false;
    }

    return true;
}
Example #13
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 #14
0
/// Begin asynchronous loading of the cache table of contents.
///
/// This must be called after calling Initialize() in order to begin using an existing cache.
///
/// @return  True if loading was started successfully, false if not.
///
/// @see TryFinishLoadToc(), IsTocLoaded(), Initialize()
bool Cache::BeginLoadToc()
{
    if( IsValid( m_asyncLoadId ) )
    {
        HELIUM_TRACE(
            TraceLevels::Warning,
            TXT( "Cache::BeginLoadToc(): Async load of TOC file \"%s\" already in progress.\n" ),
            *m_tocFileName );

        return true;
    }

    if( m_tocFileName.IsEmpty() )
    {
        HELIUM_TRACE( TraceLevels::Error, TXT( "Cache::BeginLoadToc(): Called without having initialized the cache.\n" ) );

        return false;
    }

    if( IsInvalid( m_tocSize ) )
    {
        HELIUM_TRACE( TraceLevels::Info, TXT( "Cache::BeginLoadToc(): TOC file does not seem to exist.  MOVING ON...\n" ) );

        // Since the TOC doesn't exist, we can consider its loading to be complete.
        m_bTocLoaded = true;

        return false;
    }

    HELIUM_ASSERT( !m_pTocBuffer );
    DefaultAllocator allocator;
    m_pTocBuffer = static_cast< uint8_t* >( allocator.Allocate( m_tocSize ) );
    HELIUM_ASSERT( m_pTocBuffer );
    if( !m_pTocBuffer )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "Cache::BeginLoadToc(): Failed to allocate %" ) TPRIu32 TXT( " bytes for TOC file \"%s\".\n" ),
            m_tocSize,
            *m_tocFileName );

        return false;
    }

    AsyncLoader& rLoader = AsyncLoader::GetStaticInstance();
    m_asyncLoadId = rLoader.QueueRequest( m_pTocBuffer, m_tocFileName, 0, m_tocSize );
    HELIUM_ASSERT( IsValid( m_asyncLoadId ) );
    if( IsInvalid( m_asyncLoadId ) )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "Cache::BeginLoadToc(): Failed to begin asynchronous load of TOC file \"%s\".\n" ),
            *m_tocFileName );

        allocator.Free( m_pTocBuffer );
        m_pTocBuffer = NULL;

        return false;
    }

    m_bTocLoaded = false;

    return true;
}
Example #15
0
/// Open a shader include file.
///
/// @param[in]  includeType  Location of the include file.
/// @param[in]  pFileName    Name of the include file.
/// @param[in]  pParentData  Pointer to the container that includes the include file.
/// @param[out] ppData       Pointer to the returned buffer that contains the include directives.  This pointer
///                          remains valid until Close() is called.
/// @param[out] pBytes       Number of bytes returned in ppData.
///
/// @return  S_OK if the include file was loaded successfully, an error code if not.
///
/// @see Close()
HRESULT D3DIncludeHandler::Open(
                                D3D10_INCLUDE_TYPE /*includeType*/,
                                LPCSTR pFileName,
                                LPCVOID /*pParentData*/,
                                LPCVOID* ppData,
                                UINT* pBytes )
{
    HELIUM_ASSERT( pFileName );
    HELIUM_ASSERT( ppData );
    HELIUM_ASSERT( pBytes );

    // Build the path to the file to include.
    String fileName;
    StringConverter< char, tchar_t >::Convert( fileName, pFileName );

    Path includePath( m_shaderDirectory + fileName.GetData() );

    // Attempt to open and read the contents of the include file.
    FileStream* pIncludeFileStream = File::Open( includePath.c_str(), FileStream::MODE_READ );
    if( !pIncludeFileStream )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            TXT( "D3DIncludeHandler::Open(): Failed to open include file \"%s\" for reading.\n" ),
            *includePath );

        return E_FAIL;
    }

    int64_t fileSizeActual = pIncludeFileStream->GetSize();
    HELIUM_ASSERT( fileSizeActual >= 0 );
    if( fileSizeActual > UINT32_MAX )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            ( TXT( "D3DIncludeHandler::Open(): Include file \"%s\" is larger than 4 GB and cannot be read.\n" ) ),
            *includePath );

        delete pIncludeFileStream;

        return E_FAIL;
    }

    uint32_t fileSize = static_cast< uint32_t >( fileSizeActual );

    DefaultAllocator allocator;
    void* pBuffer = allocator.Allocate( fileSize );
    if( !pBuffer )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            ( TXT( "D3DIncludeHandler::Open(): Failed to allocate %" ) TPRIu32 TXT( " bytes for loading include " )
            TXT( "file \"%s\".\n" ) ),
            fileSize,
            *includePath );

        delete pIncludeFileStream;

        return E_FAIL;
    }

    size_t bytesRead = pIncludeFileStream->Read( pBuffer, 1, fileSize );
    if( bytesRead != fileSize )
    {
        HELIUM_TRACE(
            TRACE_WARNING,
            ( TXT( "D3DIncludeHandler::Open(): Include file \"%s\" claimed to be %" ) TPRIu32 TXT( " bytes, but " )
            TXT( "only %" ) TPRIuSZ TXT( " bytes could be read.\n" ) ),
            *includePath,
            fileSize,
            bytesRead );

        fileSize = static_cast< uint32_t >( bytesRead );
    }

    delete pIncludeFileStream;

    *ppData = pBuffer;
    *pBytes = fileSize;

    return S_OK;
}