/// Execute the async loading work. void AsyncLoader::LoadWorker::Run() { BufferedStream* pBufferedStream = new BufferedStream; HELIUM_ASSERT( pBufferedStream ); while( m_stopCounter == 0 ) { AtomicExchangeAcquire( m_processingCounter, 1 ); Request* pRequest; { Locker< DynamicArray< Request* >, SpinLock >::Handle handle ( m_requestQueue ); pRequest = handle->IsEmpty() ? NULL : handle->Pop(); } if( !pRequest ) { // Queue is empty, so sleep until notified. AtomicExchangeRelease( m_processingCounter, 0 ); m_wakeUpCondition.Wait(); continue; } HELIUM_ASSERT( pRequest ); FileStream* pFileStream = FileStream::OpenFileStream( pRequest->fileName, FileStream::MODE_READ ); if( !pFileStream ) { SetInvalid( pRequest->bytesRead ); } else { pRequest->bytesRead = 0; pBufferedStream->Open( pFileStream ); int64_t offset = pBufferedStream->Seek( pRequest->offset, SeekOrigins::Begin ); if( static_cast< uint64_t >( offset ) == pRequest->offset ) { pRequest->bytesRead = pBufferedStream->Read( pRequest->pBuffer, 1, pRequest->size ); } pBufferedStream->Open( NULL ); delete pFileStream; } AtomicExchangeRelease( pRequest->processedCounter, 1 ); Thread::Yield(); } AtomicExchangeRelease( m_processingCounter, 0 ); delete pBufferedStream; }
Connection::Connection(Stream::ptr stream) : m_stream(stream) { MORDOR_ASSERT(stream); MORDOR_ASSERT(stream->supportsRead()); MORDOR_ASSERT(stream->supportsWrite()); if (!stream->supportsUnread() || !stream->supportsFind()) { BufferedStream *buffered = new BufferedStream(stream); buffered->allowPartialReads(true); m_stream.reset(buffered); } }
/// Execute the async loading work. void AsyncLoader::LoadWorker::Run() { BufferedStream* pBufferedStream = new BufferedStream; HELIUM_ASSERT( pBufferedStream ); while( m_stopCounter == 0 ) { AtomicExchangeAcquire( m_processingCounter, 1 ); Request* pRequest; if( !m_requestQueue.try_pop( pRequest ) ) { // Queue is empty, so sleep until notified. AtomicExchangeRelease( m_processingCounter, 0 ); m_wakeUpCondition.Wait(); continue; } HELIUM_ASSERT( pRequest ); FileStream* pFileStream = File::Open( pRequest->fileName, FileStream::MODE_READ ); if( !pFileStream ) { SetInvalid( pRequest->bytesRead ); } else { pRequest->bytesRead = 0; pBufferedStream->Open( pFileStream ); int64_t offset = pBufferedStream->Seek( pRequest->offset, SeekOrigins::SEEK_ORIGIN_BEGIN ); if( static_cast< uint64_t >( offset ) == pRequest->offset ) { pRequest->bytesRead = pBufferedStream->Read( pRequest->pBuffer, 1, pRequest->size ); } pBufferedStream->Open( NULL ); delete pFileStream; } AtomicExchangeRelease( pRequest->processedCounter, 1 ); Thread::Yield(); } AtomicExchangeRelease( m_processingCounter, 0 ); delete pBufferedStream; }
IContent* TextureReader::read(DataStream& stream) { if ( !hasGraphicsDevice() ) { return nullptr; } int width, height, format; stream >> width >> height >> format; BufferedStream datastream; stream.read(datastream); Graphics::TextureDescription desc; desc.width = width; desc.height = height; desc.format = Graphics::eFormat_BC3; desc.pinitData = datastream.getData(); return getGraphicsDevice().createTexture(desc); }
/// Add or update an entry in the cache. /// /// @param[in] path GameObject path. /// @param[in] subDataIndex Sub-data index associated with the cached data. /// @param[in] pData Data to cache. /// @param[in] timestamp Timestamp value to associate with the entry in the cache. /// @param[in] size Number of bytes to cache. /// /// @return True if the cache was updated successfully, false if not. bool Cache::CacheEntry( GameObjectPath path, uint32_t subDataIndex, const void* pData, int64_t timestamp, uint32_t size ) { HELIUM_ASSERT( pData || size == 0 ); Status status; status.Read( m_cacheFileName.GetData() ); int64_t cacheFileSize = status.m_Size; uint64_t entryOffset = ( cacheFileSize == -1 ? 0 : static_cast< uint64_t >( cacheFileSize ) ); HELIUM_ASSERT( m_pEntryPool ); Entry* pEntryUpdate = m_pEntryPool->Allocate(); HELIUM_ASSERT( pEntryUpdate ); pEntryUpdate->offset = entryOffset; pEntryUpdate->timestamp = timestamp; pEntryUpdate->path = path; pEntryUpdate->subDataIndex = subDataIndex; pEntryUpdate->size = size; uint64_t originalOffset = 0; int64_t originalTimestamp = 0; uint32_t originalSize = 0; EntryKey key; key.path = path; key.subDataIndex = subDataIndex; EntryMapType::Accessor entryAccessor; bool bNewEntry = m_entryMap.Insert( entryAccessor, KeyValue< EntryKey, Entry* >( key, pEntryUpdate ) ); if( bNewEntry ) { HELIUM_TRACE( TraceLevels::Info, TXT( "Cache: Adding \"%s\" to cache \"%s\".\n" ), *path.ToString(), *m_cacheFileName ); m_entries.Push( pEntryUpdate ); } else { HELIUM_TRACE( TraceLevels::Info, TXT( "Cache: Updating \"%s\" in cache \"%s\".\n" ), *path.ToString(), *m_cacheFileName ); m_pEntryPool->Release( pEntryUpdate ); pEntryUpdate = entryAccessor->Second(); HELIUM_ASSERT( pEntryUpdate ); originalOffset = pEntryUpdate->offset; originalTimestamp = pEntryUpdate->timestamp; originalSize = pEntryUpdate->size; if( originalSize < size ) { pEntryUpdate->offset = entryOffset; } else { entryOffset = originalOffset; } pEntryUpdate->timestamp = timestamp; pEntryUpdate->size = size; } AsyncLoader& rLoader = AsyncLoader::GetStaticInstance(); rLoader.Lock(); bool bCacheSuccess = true; FileStream* pCacheStream = FileStream::OpenFileStream( m_cacheFileName, FileStream::MODE_WRITE, false ); if( !pCacheStream ) { HELIUM_TRACE( TraceLevels::Error, TXT( "Cache: Failed to open cache \"%s\" for writing.\n" ), *m_cacheFileName ); bCacheSuccess = false; } else { HELIUM_TRACE( TraceLevels::Info, TXT( "Cache: Caching \"%s\" to \"%s\" (%" ) TPRIu32 TXT( " bytes @ offset %" ) TPRIu64 TXT( ").\n" ), *path.ToString(), *m_cacheFileName, size, entryOffset ); uint64_t seekOffset = static_cast< uint64_t >( pCacheStream->Seek( static_cast< int64_t >( entryOffset ), SeekOrigins::SEEK_ORIGIN_BEGIN ) ); if( seekOffset != entryOffset ) { HELIUM_TRACE( TraceLevels::Error, TXT( "Cache: Cache file offset seek failed.\n" ) ); if( bNewEntry ) { m_entries.Pop(); m_entryMap.Remove( entryAccessor ); m_pEntryPool->Release( pEntryUpdate ); } else { pEntryUpdate->offset = originalOffset; pEntryUpdate->timestamp = originalTimestamp; pEntryUpdate->size = originalSize; } bCacheSuccess = false; } else { size_t writeSize = pCacheStream->Write( pData, 1, size ); if( writeSize != size ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "Cache: Failed to write %" ) TPRIu32 TXT( " bytes to cache \"%s\" (%" ) TPRIuSZ TXT( " bytes written).\n" ) ), size, *m_cacheFileName, writeSize ); if( bNewEntry ) { m_entries.Pop(); m_entryMap.Remove( entryAccessor ); m_pEntryPool->Release( pEntryUpdate ); } else { pEntryUpdate->offset = originalOffset; pEntryUpdate->timestamp = originalTimestamp; pEntryUpdate->size = originalSize; } bCacheSuccess = false; } else { HELIUM_TRACE( TraceLevels::Info, TXT( "Cache: Rewriting TOC file \"%s\".\n" ), *m_tocFileName ); FileStream* pTocStream = FileStream::OpenFileStream( m_tocFileName, FileStream::MODE_WRITE, true ); if( !pTocStream ) { HELIUM_TRACE( TraceLevels::Error, TXT( "Cache: Failed to open TOC \"%s\" for writing.\n" ), *m_tocFileName ); } else { BufferedStream* pBufferedStream = new BufferedStream( pTocStream ); HELIUM_ASSERT( pBufferedStream ); pBufferedStream->Write( &TOC_MAGIC, sizeof( TOC_MAGIC ), 1 ); pBufferedStream->Write( &sm_Version, sizeof( sm_Version ), 1 ); uint32_t entryCount = static_cast< uint32_t >( m_entries.GetSize() ); pBufferedStream->Write( &entryCount, sizeof( entryCount ), 1 ); String entryPath; uint_fast32_t entryCountFast = entryCount; for( uint_fast32_t entryIndex = 0; entryIndex < entryCountFast; ++entryIndex ) { Entry* pEntry = m_entries[ entryIndex ]; HELIUM_ASSERT( pEntry ); pEntry->path.ToString( entryPath ); HELIUM_ASSERT( entryPath.GetSize() < UINT16_MAX ); uint16_t pathSize = static_cast< uint16_t >( entryPath.GetSize() ); pBufferedStream->Write( &pathSize, sizeof( pathSize ), 1 ); pBufferedStream->Write( *entryPath, sizeof( tchar_t ), pathSize ); pBufferedStream->Write( &pEntry->subDataIndex, sizeof( pEntry->subDataIndex ), 1 ); pBufferedStream->Write( &pEntry->offset, sizeof( pEntry->offset ), 1 ); pBufferedStream->Write( &pEntry->timestamp, sizeof( pEntry->timestamp ), 1 ); pBufferedStream->Write( &pEntry->size, sizeof( pEntry->size ), 1 ); } delete pBufferedStream; delete pTocStream; } } } delete pCacheStream; } rLoader.Unlock(); return bCacheSuccess; }