mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
110 lines
5.4 KiB
C++
110 lines
5.4 KiB
C++
|
//=============================================================================//
|
||
|
//
|
||
|
// Purpose: pak page allocation and alignment
|
||
|
//
|
||
|
//=============================================================================//
|
||
|
#include "rtech/ipakfile.h"
|
||
|
#include "pakstate.h"
|
||
|
#include "pakalloc.h"
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// aligns the segment headers for each asset type
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void Pak_AlignSegmentHeaders(PakFile_t* const pak, PakSegmentDescriptor_t* const desc)
|
||
|
{
|
||
|
uint64_t headersSize = 0;
|
||
|
uint8_t headerSegmentAlignment = static_cast<int8_t>(desc->segmentAlignmentForType[SF_HEAD]);
|
||
|
|
||
|
for (uint8_t i = 0; i < PAK_MAX_TYPES; ++i)
|
||
|
{
|
||
|
const PakAssetBinding_t& binding = g_pPakGlobals->m_assetBindings[i];
|
||
|
|
||
|
if (desc->assetTypeCount[i])
|
||
|
{
|
||
|
// asset header alignment really shouldn't be above 255
|
||
|
// if this needs raising, headerSegmentAlignment should be made wider
|
||
|
assert(binding.headerAlignment <= UINT8_MAX);
|
||
|
|
||
|
const size_t alignedSize = ALIGN_VALUE(headersSize, static_cast<size_t>(binding.headerAlignment));
|
||
|
|
||
|
pak->memoryData.unkAssetTypeBindingSizes[i] = alignedSize;
|
||
|
headersSize = alignedSize + (desc->assetTypeCount[i] * binding.nativeClassSize);
|
||
|
|
||
|
desc->segmentSizeForType[SF_HEAD] = headersSize;
|
||
|
|
||
|
headerSegmentAlignment = static_cast<uint8_t>(max(headerSegmentAlignment, binding.headerAlignment));
|
||
|
desc->segmentAlignmentForType[SF_HEAD] = headerSegmentAlignment;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// aligns each individual non-header segment
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void Pak_AlignSegments(PakFile_t* const pak, PakSegmentDescriptor_t* const desc)
|
||
|
{
|
||
|
for (uint16_t i = 0; i < pak->GetSegmentCount(); ++i)
|
||
|
{
|
||
|
const PakSegmentHeader_t* const segHeader = pak->GetSegmentHeader(i);
|
||
|
|
||
|
const uint8_t segmentType = segHeader->typeFlags & (SF_TEMP | SF_CPU);
|
||
|
|
||
|
if (segmentType != SF_HEAD) // if not a header segment
|
||
|
{
|
||
|
// should this be a hard error on release?
|
||
|
// segment alignment must not be 0 and must be a power of two
|
||
|
assert(segHeader->dataAlignment > 0 && IsPowerOfTwo(segHeader->dataAlignment));
|
||
|
|
||
|
const size_t alignedSegmentSize = ALIGN_VALUE(desc->segmentSizeForType[segmentType], static_cast<size_t>(segHeader->dataAlignment));
|
||
|
//const size_t sizeAligned = ~(m_align - 1) & (m_align - 1 + segmentSizeForType[segmentType]);
|
||
|
|
||
|
desc->segmentSizes[i] = alignedSegmentSize;
|
||
|
desc->segmentSizeForType[segmentType] = alignedSegmentSize + segHeader->dataSize;
|
||
|
|
||
|
// check if this segment's alignment is higher than the previous highest for this type
|
||
|
// if so, increase the alignment to accommodate this segment
|
||
|
desc->segmentAlignmentForType[segmentType] = max(desc->segmentAlignmentForType[segmentType], segHeader->dataAlignment);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// copy's pages into pre-allocated and aligned segments
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void Pak_CopyPagesToSegments(PakFile_t* const pak, PakLoadedInfo_t* const loadedInfo, PakSegmentDescriptor_t* const desc)
|
||
|
{
|
||
|
for (uint32_t i = 0; i < pak->GetPageCount(); ++i)
|
||
|
{
|
||
|
const PakPageHeader_t* const pageHeader = pak->GetPageHeader(i);
|
||
|
const uint32_t segmentIndex = pageHeader->segmentIdx;
|
||
|
|
||
|
const PakSegmentHeader_t* const segHeader = pak->GetSegmentHeader(segmentIndex);
|
||
|
const int typeFlags = segHeader->typeFlags;
|
||
|
|
||
|
// check if header page
|
||
|
if ((typeFlags & (SF_TEMP | SF_CPU)) != 0)
|
||
|
{
|
||
|
// align the segment's current size to the alignment of the new page to get copied in
|
||
|
// this ensures that the location holding the page is aligned as required
|
||
|
//
|
||
|
// since the segment will always have alignment equal to or greater than the page, and that alignment will always be a power of 2
|
||
|
// the page does not have to be aligned to the same alignment as the segment, as aligning it to its own alignment is sufficient as long as
|
||
|
// every subsequent page does the same thing
|
||
|
const size_t alignedSegmentSize = ALIGN_VALUE(desc->segmentSizes[segmentIndex], static_cast<size_t>(pageHeader->pageAlignment));
|
||
|
|
||
|
// get a pointer to the newly aligned location within the segment for this page
|
||
|
pak->memoryData.memPageBuffers[i] = reinterpret_cast<uint8_t*>(loadedInfo->segmentBuffers[typeFlags & (SF_TEMP | SF_CPU)]) + alignedSegmentSize;
|
||
|
|
||
|
// update the segment size to reflect the new alignment and page size
|
||
|
desc->segmentSizes[segmentIndex] = alignedSegmentSize + pak->memoryData.pageHeaders[i].dataSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// all headers go into one segment and are dealt with separately in Pak_ProcessPakFile
|
||
|
// since headers must be copied individually into a buffer that is big enough for the "native class" version of the header
|
||
|
// instead of just the file version
|
||
|
pak->memoryData.memPageBuffers[i] = reinterpret_cast<uint8_t*>(loadedInfo->segmentBuffers[SF_HEAD]);
|
||
|
}
|
||
|
}
|
||
|
}
|