void FD3D12BuddyAllocator::Allocate(uint32 SizeInBytes, uint32 Alignment, FD3D12ResourceLocation& ResourceLocation) { FScopeLock Lock(&CS); if (Initialized == false) { Initialize(); Initialized = true; } uint32 SizeToAllocate = SizeInBytes; // If the alignment doesn't match the block size if (Alignment != 0 && MinBlockSize % Alignment != 0) { SizeToAllocate = SizeInBytes + Alignment; } // Work out what size block is needed and allocate one const uint32 UnitSize = SizeToUnitSize(SizeToAllocate); const uint32 Order = UnitSizeToOrder(UnitSize); const uint32 Offset = AllocateBlock(Order); // This is the offset in MinBlockSize units const uint32 AllocSize = uint32(OrderToUnitSize(Order) * MinBlockSize); const uint32 AllocationBlockOffset = uint32(Offset * MinBlockSize); uint32 Padding = 0; if (Alignment != 0 && AllocationBlockOffset % Alignment != 0) { uint32 AlignedBlockOffset = AlignArbitrary(AllocationBlockOffset, Alignment); Padding = AlignedBlockOffset - AllocationBlockOffset; check((Padding + SizeInBytes) <= AllocSize) }
bool CreatePakFile(const TCHAR* Filename, TArray<FPakInputPair>& FilesToAdd, const FPakCommandLineParameters& CmdLineParameters) { const double StartTime = FPlatformTime::Seconds(); // Create Pak TAutoPtr<FArchive> PakFileHandle(CreatePakWriter(Filename)); if (!PakFileHandle.IsValid()) { UE_LOG(LogPakFile, Error, TEXT("Unable to create pak file \"%s\"."), Filename); return false; } FPakInfo Info; TArray<FPakEntryPair> Index; FString MountPoint = GetCommonRootPath(FilesToAdd); uint8* ReadBuffer = NULL; int64 BufferSize = 0; ECompressionFlags CompressionMethod = COMPRESS_None; FCompressedFileBuffer CompressedFileBuffer; for (int32 FileIndex = 0; FileIndex < FilesToAdd.Num(); FileIndex++) { // Remember the offset but don't serialize it with the entry header. int64 NewEntryOffset = PakFileHandle->Tell(); FPakEntryPair NewEntry; //check if this file requested to be compression int64 OriginalFileSize = IFileManager::Get().FileSize(*FilesToAdd[FileIndex].Source); int64 RealFileSize = OriginalFileSize + NewEntry.Info.GetSerializedSize(FPakInfo::PakFile_Version_Latest); CompressionMethod = (FilesToAdd[FileIndex].bNeedsCompression && OriginalFileSize > 0) ? COMPRESS_Default : COMPRESS_None; if (CompressionMethod != COMPRESS_None) { if (CompressedFileBuffer.CompressFileToWorkingBuffer(FilesToAdd[FileIndex], ReadBuffer, BufferSize, CompressionMethod, CmdLineParameters.CompressionBlockSize)) { // Check the compression ratio, if it's too low just store uncompressed. Also take into account read size // if we still save 64KB it's probably worthwhile compressing, as that saves a file read operation in the runtime. // TODO: drive this threashold from the command line float PercentLess = ((float)CompressedFileBuffer.TotalCompressedSize/(OriginalFileSize/100.f)); if (PercentLess > 90.f && (OriginalFileSize-CompressedFileBuffer.TotalCompressedSize) < 65536) { CompressionMethod = COMPRESS_None; } else { NewEntry.Info.CompressionMethod = CompressionMethod; NewEntry.Info.CompressionBlocks.AddUninitialized(CompressedFileBuffer.CompressedBlocks.Num()); RealFileSize = CompressedFileBuffer.TotalCompressedSize + NewEntry.Info.GetSerializedSize(FPakInfo::PakFile_Version_Latest); NewEntry.Info.CompressionBlocks.Reset(); } } } // Account for file system block size, which is a boundary we want to avoid crossing. if (CmdLineParameters.FileSystemBlockSize > 0 && OriginalFileSize != INDEX_NONE && RealFileSize <= CmdLineParameters.FileSystemBlockSize) { if ((NewEntryOffset / CmdLineParameters.FileSystemBlockSize) != ((NewEntryOffset+RealFileSize) / CmdLineParameters.FileSystemBlockSize)) { //File crosses a block boundary, so align it to the beginning of the next boundary NewEntryOffset = AlignArbitrary(NewEntryOffset, CmdLineParameters.FileSystemBlockSize); PakFileHandle->Seek(NewEntryOffset); } } bool bCopiedToPak; if (FilesToAdd[FileIndex].bNeedsCompression && CompressionMethod != COMPRESS_None) { bCopiedToPak = CopyCompressedFileToPak(*PakFileHandle, MountPoint, FilesToAdd[FileIndex], CompressedFileBuffer, NewEntry); } else { bCopiedToPak = CopyFileToPak(*PakFileHandle, MountPoint, FilesToAdd[FileIndex], ReadBuffer, BufferSize, NewEntry); } if (bCopiedToPak) { // Update offset now and store it in the index (and only in index) NewEntry.Info.Offset = NewEntryOffset; Index.Add(NewEntry); if (FilesToAdd[FileIndex].bNeedsCompression && CompressionMethod != COMPRESS_None) { float PercentLess = ((float)NewEntry.Info.Size/(NewEntry.Info.UncompressedSize/100.f)); UE_LOG(LogPakFile, Display, TEXT("Added compressed file \"%s\", %.2f%% of original size. Compressed Size %lld bytes, Original Size %lld bytes. "), *NewEntry.Filename, PercentLess, NewEntry.Info.Size, NewEntry.Info.UncompressedSize); } else { UE_LOG(LogPakFile, Display, TEXT("Added file \"%s\", %lld bytes."), *NewEntry.Filename, NewEntry.Info.Size); } } else { UE_LOG(LogPakFile, Warning, TEXT("Missing file \"%s\" will not be added to PAK file."), *FilesToAdd[FileIndex].Source); } } FMemory::Free(ReadBuffer); ReadBuffer = NULL; // Remember IndexOffset Info.IndexOffset = PakFileHandle->Tell(); // Serialize Pak Index at the end of Pak File TArray<uint8> IndexData; FMemoryWriter IndexWriter(IndexData); IndexWriter.SetByteSwapping(PakFileHandle->ForceByteSwapping()); int32 NumEntries = Index.Num(); IndexWriter << MountPoint; IndexWriter << NumEntries; for (int32 EntryIndex = 0; EntryIndex < Index.Num(); EntryIndex++) { FPakEntryPair& Entry = Index[EntryIndex]; IndexWriter << Entry.Filename; Entry.Info.Serialize(IndexWriter, Info.Version); } PakFileHandle->Serialize(IndexData.GetData(), IndexData.Num()); FSHA1::HashBuffer(IndexData.GetData(), IndexData.Num(), Info.IndexHash); Info.IndexSize = IndexData.Num(); // Save trailer (offset, size, hash value) Info.Serialize(*PakFileHandle); UE_LOG(LogPakFile, Display, TEXT("Added %d files, %lld bytes total, time %.2lfs."), Index.Num(), PakFileHandle->TotalSize(), FPlatformTime::Seconds() - StartTime); PakFileHandle->Close(); PakFileHandle.Reset(); return true; }