From 4cdd80977c48ea9ac3fdbd3d19068da6a7874f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20W=C3=BCbbers?= Date: Sun, 27 Apr 2025 12:00:22 +0200 Subject: [PATCH] wip --- src/engine/Shared.h | 18 +++--- src/engine/main.cpp | 24 +++++--- src/game/Global.cpp | 22 ++++++-- src/game/Global.h | 3 +- src/game/Level.cpp | 3 +- src/game/Level.h | 6 +- src/game/Setup.cpp | 10 ++-- src/game/rendering/Rendering.cpp | 96 +++++++++++++++++++++++++++++++- 8 files changed, 148 insertions(+), 34 deletions(-) diff --git a/src/engine/Shared.h b/src/engine/Shared.h index 87c83c1..12f21fb 100644 --- a/src/engine/Shared.h +++ b/src/engine/Shared.h @@ -96,16 +96,18 @@ struct SharedDevData char ShaderLog[2048]{0}; }; +struct MemoryArena +{ + uint8_t* Ptr = nullptr; + uint64_t Size = 0; + uint64_t LastAllocSize = 0; +}; + struct GameData { - void* PermanentStorage = nullptr; - uint64_t PermanentStorageSize = 0; - - void* EntityStorage = nullptr; - uint64_t EntityStorageSize = 0; - - void* TransientStorage = nullptr; - uint64_t TransientStorageSize = 0; + MemoryArena PermanentArena; + MemoryArena EntityArena; + MemoryArena TransientArena; }; struct SharedData diff --git a/src/engine/main.cpp b/src/engine/main.cpp index 1a3bfbd..ce04bd2 100644 --- a/src/engine/main.cpp +++ b/src/engine/main.cpp @@ -23,6 +23,10 @@ constexpr const char* DLLPath = "libPuzGame.dll"; constexpr const wchar_t* DLLWatch = L"libPuzGame2.dll"; #endif +constexpr uint64_t KB = 1024LLU; +constexpr uint64_t MB = 1024LLU * 1024LLU; +constexpr uint64_t GB = 1024LLU * 1024LLU * 1024LLU; + namespace { bx::AllocatorI* defaultAllocator = new bx::DefaultAllocator{}; @@ -260,6 +264,14 @@ bool ReloadDLL() return true; } +void InitMemoryArena(MemoryArena& arena, uint64_t size) +{ + arena.Size = size; + arena.Ptr = reinterpret_cast( + VirtualAllocEx(GetCurrentProcess(), NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)); + arena.LastAllocSize = 0; +} + int main() { char PathBuf[512]{0}; @@ -301,15 +313,9 @@ int main() HANDLE compiledShaderThread = CreateThread(NULL, 0, FileWatcherThread, &DevData.FileWatcher.CompiledShaderWatcher, 0, &fileWatcherThreadId); - Shared.Game.PermanentStorageSize = 1024 * 1024; - Shared.Game.PermanentStorage = VirtualAllocEx( - GetCurrentProcess(), NULL, Shared.Game.PermanentStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - Shared.Game.EntityStorageSize = 1024 * 1024; - Shared.Game.EntityStorage = VirtualAllocEx( - GetCurrentProcess(), NULL, Shared.Game.EntityStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - Shared.Game.TransientStorageSize = 1024 * 1024 * 1024; - Shared.Game.TransientStorage = VirtualAllocEx( - GetCurrentProcess(), NULL, Shared.Game.TransientStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + InitMemoryArena(Shared.Game.PermanentArena, MB); + InitMemoryArena(Shared.Game.EntityArena, MB); + InitMemoryArena(Shared.Game.TransientArena, 2 * GB); StartupFunc(Shared); bool isRunning = true; diff --git a/src/game/Global.cpp b/src/game/Global.cpp index fd02264..9b00c74 100644 --- a/src/game/Global.cpp +++ b/src/game/Global.cpp @@ -37,16 +37,30 @@ namespace Game GameInst = &instance; } - void* AllocateScratch(size_t byteCount, size_t align) + uint8_t* AllocateScratch(size_t byteCount, size_t align) { size_t offset = GetInstance().UsedScratchAmount; - uint8_t* base = static_cast(GetShared().Game.TransientStorage); + uint8_t* base = GetShared().Game.TransientArena.Ptr; uint8_t* current = base + offset; size_t offsetAligned = ((offset + align - 1) / align) * align; uint8_t* ptrAligned = base + offsetAligned; size_t newOffset = offsetAligned + byteCount; - if (newOffset > GetShared().Game.TransientStorageSize) return nullptr; + if (newOffset > GetShared().Game.TransientArena.Size) return nullptr; GetInstance().UsedScratchAmount = newOffset; - return reinterpret_cast(ptrAligned); + GetShared().Game.TransientArena.LastAllocSize = byteCount; + return ptrAligned; + } + + bool ResizeLastScratchAlloc(size_t newByteCount) + { + auto& arena = GetShared().Game.TransientArena; + if (newByteCount > arena.LastAllocSize) + { + LOG_ERROR("Can't resize to more than previous size!"); + return false; + } + arena.Ptr -= arena.LastAllocSize; + arena.Ptr += newByteCount; + return true; } } // namespace Game diff --git a/src/game/Global.h b/src/game/Global.h index fbd3b74..e46ec8b 100644 --- a/src/game/Global.h +++ b/src/game/Global.h @@ -33,5 +33,6 @@ namespace Game void SetShared(SharedData& instance); GameInstance& GetInstance(); void SetInstance(GameInstance& instance); - void* AllocateScratch(size_t byteCount, size_t align = 16); + uint8_t* AllocateScratch(size_t byteCount, size_t align = 16); + bool ResizeLastScratchAlloc(size_t newByteCount); } // namespace Game diff --git a/src/game/Level.cpp b/src/game/Level.cpp index 817b83e..a13c5bf 100644 --- a/src/game/Level.cpp +++ b/src/game/Level.cpp @@ -102,7 +102,7 @@ namespace Game void Level::Setup(GameData& data) { LOG("Level setup"); - void* storagePtr = data.EntityStorage; + uint8_t* storagePtr = data.EntityArena.Ptr; bool needReset = false; needReset |= Cubes.Setup(storagePtr, needReset); needReset |= Tests.Setup(storagePtr, needReset); @@ -419,6 +419,7 @@ namespace Game UpdateMatrix(camTransform); Vec3 cameraPos = camTransform.Position; + // TODO: disable warning & check if parentheses make sense like this Vec2 uiOffset = Vec2{static_cast(Data.WidthTiles / Puzzle::Config::CardSize - 1), static_cast(Data.HeightTiles / Puzzle::Config::CardSize) - 1}; uiOffset *= -UICardOffset * 0.5f; diff --git a/src/game/Level.h b/src/game/Level.h index 91b282b..6ce4a95 100644 --- a/src/game/Level.h +++ b/src/game/Level.h @@ -72,7 +72,7 @@ namespace Game class IEntityManager { public: - virtual bool Setup(void*& ptr, bool forceReset) = 0; + virtual bool Setup(uint8_t*& ptr, bool forceReset) = 0; }; template class EntityManager : public IEntityManager @@ -86,7 +86,7 @@ namespace Game public: // Returns true if size changed - bool Setup(void*& ptr, bool forceReset) + bool Setup(uint8_t*& ptr, bool forceReset) { bool changed = false; if (EntitySize != sizeof(T) || forceReset) @@ -96,7 +96,7 @@ namespace Game } EntitySize = sizeof(T); Data = reinterpret_cast(ptr); - ptr = (uint8_t*)ptr + (C * EntitySize); + ptr += C * EntitySize; return changed; } diff --git a/src/game/Setup.cpp b/src/game/Setup.cpp index 7299960..9ffe6a1 100644 --- a/src/game/Setup.cpp +++ b/src/game/Setup.cpp @@ -33,22 +33,22 @@ namespace Game tracy::StartupProfiler(); #endif - if (shared.Game.PermanentStorage == nullptr) + if (shared.Game.PermanentArena.Ptr == nullptr) { LOG_ERROR("Game memory not initialized!!"); return; } - if (shared.Game.EntityStorage == nullptr) + if (shared.Game.EntityArena.Ptr == nullptr) { LOG_ERROR("Entity memory not initialized!"); return; } - if (shared.Game.PermanentStorageSize < sizeof(GameInstance)) + if (shared.Game.PermanentArena.Size < sizeof(GameInstance)) { - LOG_ERROR("Game memory too small! %u < %u", shared.Game.PermanentStorageSize, sizeof(GameInstance)); + LOG_ERROR("Game memory too small! %u < %u", shared.Game.PermanentArena.Size, sizeof(GameInstance)); return; } - GameInstance& instance = *reinterpret_cast(shared.Game.PermanentStorage); + GameInstance& instance = *reinterpret_cast(shared.Game.PermanentArena.Ptr); if (sizeof(GameInstance) != instance.Size) { LOG_WARN("Game instance size changed, resetting!"); diff --git a/src/game/rendering/Rendering.cpp b/src/game/rendering/Rendering.cpp index 6e7b206..72f3209 100644 --- a/src/game/rendering/Rendering.cpp +++ b/src/game/rendering/Rendering.cpp @@ -32,15 +32,104 @@ namespace Game { namespace { + constexpr size_t ChunkSize = 1024; + constexpr size_t MaxFileSize = ChunkSize * 1024 * 1024; + constexpr size_t MaxChunkCount = MaxFileSize / ChunkSize; + + bool BufferedFileRead(FILE* file, uint8_t* writePtr, size_t& totalReadCount) + { + for (int32_t i = 0; i < MaxChunkCount; ++i) + { + size_t readCount = std::fread(writePtr, 1, ChunkSize, file); + writePtr += readCount; + totalReadCount += readCount; + + if (readCount != ChunkSize) + { + if (std::feof(file)) + { + return true; + } + + int err = std::ferror(file); + if (err != 0) + { + LOG_ERROR("Error reading file: %i", err); + return false; + } + + LOG_ERROR("This should never happen!"); + return false; + } + } + + if (!std::feof(file)) + { + LOG_ERROR("File too big to be read!"); + return false; + } + + return true; + } + + const bgfx::Memory* LoadBinaryFile(const char* path, int32_t retryCount = 1) + { + FILE* file = nullptr; + for (int32_t i = 0; i < retryCount; ++i) + { + file = std::fopen(path, "rb"); + if (file == nullptr) + { + if (i < retryCount - 1) + { + std::this_thread::sleep_for(100ms); + LOG_WARN("Failed to open file, retrying..."); + break; + } + else + { + LOG_ERROR("Failed to open file!"); + return nullptr; + } + } + } + uint8_t* dataPtr = AllocateScratch(MaxFileSize); + if (dataPtr == nullptr) + { + LOG_ERROR("Failed to load file, exceeded scratch memory! %s", path); + return nullptr; + } + + uint64_t totalReadCount = 0; + bool success = BufferedFileRead(file, dataPtr, totalReadCount); + std::fclose(file); + + if (!success) + { + LOG_ERROR("Failed to read file %s", path); + ResizeLastScratchAlloc(0); + return nullptr; + } + + if (!ResizeLastScratchAlloc(totalReadCount)) + { + LOG_ERROR("This should never happen!"); + return nullptr; + } + + return bgfx::makeRef(dataPtr, totalReadCount); + } + const bgfx::Memory* loadFile(const char* path, bool appendZero = false, int32_t retryCount = 1) { FILE* file; for (int32_t i = 0; i < retryCount; ++i) { - file = fopen(path, "rb"); + file = std::fopen(path, "rb"); if (file == nullptr && i < retryCount - 1) { std::this_thread::sleep_for(100ms); + LOG_WARN("Failed to open file, retrying..."); break; } @@ -48,11 +137,12 @@ namespace Game long fileSize = ftell(file); fseek(file, 0, SEEK_SET); - long fileSizeX = appendZero ? fileSize + 1 : fileSize; + long fileSizeX = appendZero ? (fileSize + 1) : fileSize; void* rawMem = AllocateScratch(fileSizeX); if (rawMem == nullptr) { LOG_ERROR("Failed to load file, exceeded scratch memory! %s", path); + return nullptr; } const bgfx::Memory* mem = bgfx::makeRef(rawMem, fileSizeX); fread(mem->data, 1, fileSize, file); @@ -127,7 +217,7 @@ namespace Game bgfx::TextureHandle handle = BGFX_INVALID_HANDLE; bx::Error err; - const bgfx::Memory* data = loadFile(_filePath.getCPtr()); + const bgfx::Memory* data = LoadBinaryFile(_filePath.getCPtr()); if (data == nullptr || data->data == nullptr || data->size == 0) { LOG_WARN("Failed to find image %s", _filePath.getCPtr());