/// 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 ); } }
/// 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; }
/// 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 ) { DefaultAllocator allocator; // 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. void* pBlock; if( size < HELIUM_SIMD_SIZE ) { pBlock = allocator.Allocate( size ); } else { pBlock = allocator.AllocateAligned( HELIUM_SIMD_ALIGNMENT, size ); } return pBlock; }
/// 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; }
/// @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; }
/// @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; }
/// 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; }
/// 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; }