r5sdk/r5dev/rtech/pak/pakalloc.cpp

110 lines
5.4 KiB
C++
Raw Normal View History

//=============================================================================//
//
// 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]);
}
}
}