Files
tech5/source/shared/idlib/sys/xenon/xen_mem.cpp
T
2026-08-08 13:54:26 -07:00

204 lines
7.3 KiB
C++

#include "idlib/sys/sys_alloc.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <psapi.h>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <limits>
namespace {
unsigned int ClampToUInt64(const unsigned long long value) {
return value > (std::numeric_limits<unsigned int>::max)()
? (std::numeric_limits<unsigned int>::max)()
: static_cast<unsigned int>(value);
}
int AlignUp(const int value, const int alignment) {
const int safeAlignment = alignment <= 0 ? 16 : alignment;
return (value + safeAlignment - 1) & ~(safeAlignment - 1);
}
} // namespace
void MapVirtualAddressSpace() {
// Win32 already supplies a flat virtual address space. Logical map/system
// heap selection remains handled by idMem.
}
unsigned int Sys_GetStreamFileCacheUsage() {
// The PC filesystem owns its cache allocations through idMem rather than
// a carved physical-memory range.
return 0;
}
unsigned int Sys_GetMemoryUsage() {
PROCESS_MEMORY_COUNTERS_EX counters = {};
counters.cb = sizeof(counters);
if (!GetProcessMemoryInfo(GetCurrentProcess(),
reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&counters),
sizeof(counters))) {
return static_cast<unsigned int>(mem.BytesCurrentlyAllocated());
}
return ClampToUInt64(counters.PrivateUsage);
}
unsigned int Sys_GetFreeMemory() {
MEMORYSTATUSEX status = {};
status.dwLength = sizeof(status);
return GlobalMemoryStatusEx(&status) ? ClampToUInt64(status.ullAvailPhys) : 0;
}
void Sys_WriteMemoryReport(const char* mapName, const char* version) {
char fileName[192] = {};
std::snprintf(fileName, sizeof(fileName), "memory_%s_%s.txt",
mapName == nullptr || mapName[0] == '\0' ? "nomap" : mapName,
version == nullptr || version[0] == '\0' ? "unknown" : version);
for (char* cursor = fileName; *cursor != '\0'; ++cursor) {
if (*cursor == '\\' || *cursor == '/' || *cursor == ':'
|| *cursor == '*' || *cursor == '?' || *cursor == '"'
|| *cursor == '<' || *cursor == '>' || *cursor == '|') {
*cursor = '_';
}
}
mem.WriteMemoryReport(".", fileName);
}
void Sys_DumpMemory() {
mem.WriteMemoryReport(".", "memory_dump.txt");
}
void AddTagStats(int, int, int, int) {
// idMem records tags per allocation, so a second accounting table would
// double count on PC.
}
void SubtractTagStats(int, int, int, int) {
}
void* XMemAlloc(const unsigned int size, const int) {
return mem.AllocWithLocation("XMemAlloc PC replacement", size, TAG_IDLIB,
false, ALIGN_16, HEAP_DEFAULTHEAP);
}
void XMemFree(unsigned char* pointer, const unsigned int) {
mem.Free(pointer);
}
void* Sys_Alloc(const unsigned int size, const memTag_t tag,
const align_t alignment, const heapType_t heap) {
return mem.AllocWithLocation("Sys_Alloc PC replacement", size, tag,
false, alignment, heap);
}
void Sys_Free(void* pointer) {
mem.Free(pointer);
}
idPhysicalMemoryBlock::idPhysicalMemoryBlock()
: reservedPhysicalMemoryBlock(nullptr), totalBlockSize(0), commonBytes(0),
overlayBytes(0), cacheBytes(0), insideResourceBlockLoad(false),
physicalBytesAllocated(0), imageBytesAllocated(0), bufferBytesAllocated(0),
otherBytesAllocated(0), alignmentWaste(0), bytesForcedOutsideBlock(0) {
}
void idPhysicalMemoryBlock::Init(const int bytesToAllocate) {
if (reservedPhysicalMemoryBlock != nullptr || bytesToAllocate <= 0) return;
totalBlockSize = AlignUp(bytesToAllocate, 65536);
reservedPhysicalMemoryBlock = static_cast<unsigned char*>(
mem.AllocWithLocation("idPhysicalMemoryBlock PC reserve",
totalBlockSize, TAG_PHYSICAL_BLOCK, true, ALIGN_16,
HEAP_SYSTEMHEAP));
if (reservedPhysicalMemoryBlock == nullptr) totalBlockSize = 0;
}
void idPhysicalMemoryBlock::RevertToDiscreteAllocations() {
if (physicalBytesAllocated != 0) return;
mem.Free(reservedPhysicalMemoryBlock);
reservedPhysicalMemoryBlock = nullptr;
totalBlockSize = 0;
commonBytes = overlayBytes = cacheBytes = 0;
}
void idPhysicalMemoryBlock::BeginResourceLoads() {
insideResourceBlockLoad = true;
}
void idPhysicalMemoryBlock::EndResourceLoads(const bool neverFreeAllocatedData) {
insideResourceBlockLoad = false;
physicalBytesAllocated = std::min(AlignUp(physicalBytesAllocated, 65536),
totalBlockSize);
if (neverFreeAllocatedData) commonBytes = physicalBytesAllocated;
cacheBytes = std::max(0, totalBlockSize - physicalBytesAllocated);
overlayBytes = 0;
}
void* idPhysicalMemoryBlock::PhysicalAlloc(const unsigned int bytes,
const int alignment, const memTag_t tag) {
const int alignedOffset = AlignUp(physicalBytesAllocated, alignment);
alignmentWaste += alignedOffset - physicalBytesAllocated;
if (reservedPhysicalMemoryBlock != nullptr
&& alignedOffset >= 0
&& bytes <= static_cast<unsigned int>(totalBlockSize - alignedOffset)) {
physicalBytesAllocated = alignedOffset + static_cast<int>(bytes);
if (tag == TAG_DXIMAGE) imageBytesAllocated += bytes;
else if (tag == TAG_DXBUFFER) bufferBytesAllocated += bytes;
else otherBytesAllocated += bytes;
return reservedPhysicalMemoryBlock + alignedOffset;
}
bytesForcedOutsideBlock += bytes;
return mem.AllocWithLocation("physical allocation fallback", bytes, tag,
false, alignment >= ALIGN_128 ? ALIGN_128 : ALIGN_16,
HEAP_SYSTEMHEAP);
}
void* idPhysicalMemoryBlock::OverlayAlloc(const unsigned int bytes,
const char*) {
// PC resources are individually reclaimable; keeping overlays discrete
// avoids the Xenon-only 64 KiB overlay fragmentation rules.
return mem.AllocWithLocation("overlay allocation PC replacement", bytes,
TAG_PHYSICAL_BLOCK, false, ALIGN_16, HEAP_SYSTEMHEAP);
}
void idPhysicalMemoryBlock::OverlayFree(void* pointer) {
if (!AddressIsInReservedPhysicalMemoryBlock(pointer)) mem.Free(pointer);
}
bool idPhysicalMemoryBlock::AddressIsInReservedPhysicalMemoryBlock(
const void* pointer) const {
const unsigned char* const address = static_cast<const unsigned char*>(pointer);
return reservedPhysicalMemoryBlock != nullptr
&& address >= reservedPhysicalMemoryBlock
&& address < reservedPhysicalMemoryBlock + totalBlockSize;
}
bool idPhysicalMemoryBlock::AddressIsInOverlayPhysicalMemoryBlock(
const void* pointer) const {
if (!AddressIsInReservedPhysicalMemoryBlock(pointer) || overlayBytes <= 0) {
return false;
}
const unsigned char* const overlayStart =
reservedPhysicalMemoryBlock + totalBlockSize - overlayBytes;
return static_cast<const unsigned char*>(pointer) >= overlayStart;
}
void idPhysicalMemoryBlock::ReportPhysicalMemoryBlock() const {
std::printf("physical block: %d/%d bytes, images=%d buffers=%d other=%d "
"alignment=%d fallback=%d\n", physicalBytesAllocated, totalBlockSize,
imageBytesAllocated, bufferBytesAllocated, otherBytesAllocated,
alignmentWaste, bytesForcedOutsideBlock);
}
void idPhysicalMemoryBlock::ReportUntouchedPhysicalMemory() const {
std::printf("physical block untouched/available: %d bytes\n",
std::max(0, totalBlockSize - physicalBytesAllocated));
}