From 45ef1134f772cd3aba2778d4e2b54f71fb4b6cf5 Mon Sep 17 00:00:00 2001 From: Patedam Date: Sat, 31 Jan 2026 23:20:26 -0500 Subject: [PATCH] Updating memory arena by hand because Gemini did something weird. Added some os functions for memory handling. Starting conversion to memory arena --- Juliet.sln | 7 +- Juliet/Juliet.vcxproj | 5 + Juliet/Juliet.vcxproj.filters | 30 +++ Juliet/include/Core/Common/CoreUtils.h | 39 +++ Juliet/include/Core/HAL/OS/OS.h | 36 +++ Juliet/include/Core/Logging/LogManager.h | 6 + Juliet/include/Core/Main.h | 47 ++++ Juliet/include/Core/Math/MathUtils.h | 12 + Juliet/include/Core/Memory/MemoryArena.h | 67 +++++- Juliet/include/Core/Memory/Utils.h | 2 + Juliet/src/Core/HAL/OS/OS.cpp | 29 +++ Juliet/src/Core/HAL/OS/OS_Private.h | 19 ++ Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp | 84 +++++++ Juliet/src/Core/HAL/Win32.h | 7 +- Juliet/src/Core/Juliet.cpp | 9 +- Juliet/src/Core/Memory/MemoryArena.cpp | 224 ++++++++++++++++-- Juliet/src/Core/Memory/MemoryArenaTests.cpp | 44 ++++ .../src/Core/Networking/SocketPlatformImpl.h | 12 +- .../Win32/Win32SocketPlatformImpl.cpp | 1 + Juliet/src/Engine/Engine.cpp | 7 + JulietApp/JulietApp.bff | 9 + JulietApp/main.cpp | 15 +- 22 files changed, 647 insertions(+), 64 deletions(-) create mode 100644 Juliet/include/Core/HAL/OS/OS.h create mode 100644 Juliet/include/Core/Main.h create mode 100644 Juliet/src/Core/HAL/OS/OS.cpp create mode 100644 Juliet/src/Core/HAL/OS/OS_Private.h create mode 100644 Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp diff --git a/Juliet.sln b/Juliet.sln index 5d65aa0..ae5e343 100644 --- a/Juliet.sln +++ b/Juliet.sln @@ -1,4 +1,4 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.22823.1 MinimumVisualStudioVersion = 10.0.40219.1 @@ -7,11 +7,6 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Game", "Game\Game.vcxproj", "{B1D040D0-6C94-4F93-BC2A-7F5284B7D434}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JulietApp", "JulietApp\JulietApp.vcxproj", "{1DEE51CA-6C94-4F93-BC2A-7F5284B7D434}" - ProjectSection(ProjectDependencies) = postProject - {AB9C7E88-6C94-4F93-BC2A-7F5284B7D434} = {AB9C7E88-6C94-4F93-BC2A-7F5284B7D434} - {C16FFE36-6C94-4F93-BC2A-7F5284B7D434} = {C16FFE36-6C94-4F93-BC2A-7F5284B7D434} - {B1D040D0-6C94-4F93-BC2A-7F5284B7D434} = {B1D040D0-6C94-4F93-BC2A-7F5284B7D434} - EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Juliet", "Juliet\Juliet.vcxproj", "{AB9C7E88-6C94-4F93-BC2A-7F5284B7D434}" EndProject diff --git a/Juliet/Juliet.vcxproj b/Juliet/Juliet.vcxproj index 64bcda9..3ee2bbb 100644 --- a/Juliet/Juliet.vcxproj +++ b/Juliet/Juliet.vcxproj @@ -72,12 +72,14 @@ + + @@ -140,6 +142,9 @@ + + + diff --git a/Juliet/Juliet.vcxproj.filters b/Juliet/Juliet.vcxproj.filters index 8b26a25..863a7bf 100644 --- a/Juliet/Juliet.vcxproj.filters +++ b/Juliet/Juliet.vcxproj.filters @@ -64,6 +64,9 @@ include\Core\HAL\Mouse + + include\Core\HAL\OS + include\Core\HotReload @@ -82,6 +85,9 @@ include\Core\Logging + + include\Core + include\Core\Math @@ -267,6 +273,15 @@ src\Core\HAL\IO\Win32 + + src\Core\HAL\OS + + + src\Core\HAL\OS + + + src\Core\HAL\OS\Win32 + src\Core\HAL @@ -552,6 +567,11 @@ {4c7d6b5f-6c94-4f93-bc2a-7f5284b7d434} + + + {8d491e18-6c94-4f93-bc2a-7f5284b7d434} + + {fe4e9898-6c94-4f93-bc2a-7f5284b7d434} @@ -672,6 +692,16 @@ {37523cd5-6c94-4f93-bc2a-7f5284b7d434} + + + {d679d621-6c94-4f93-bc2a-7f5284b7d434} + + + + + {f6713825-6c94-4f93-bc2a-7f5284b7d434} + + {35231af8-6c94-4f93-bc2a-7f5284b7d434} diff --git a/Juliet/include/Core/Common/CoreUtils.h b/Juliet/include/Core/Common/CoreUtils.h index ce1dbb4..caefd05 100644 --- a/Juliet/include/Core/Common/CoreUtils.h +++ b/Juliet/include/Core/Common/CoreUtils.h @@ -4,11 +4,16 @@ #include #include +#include +#include +#include #include namespace Juliet { +#define global static + #if JULIET_DEBUG #define JULIET_ASSERT_INTERNAL(expression, message) \ __pragma(warning(push)) __pragma(warning(disable : 4127)) __pragma(warning(disable : 4548)) do \ @@ -100,4 +105,38 @@ namespace Juliet } extern JULIET_API void Free(ByteBuffer& buffer); + + template + [[nodiscard]] constexpr T AlignPow2(T x, T alignment) + { + // Safety Check: + Assert(std::has_single_bit(static_cast(alignment))); + + return (x + alignment - 1) & ~(alignment - 1); + } + + // Move to another file dedicated to those +#if defined(__clang__) +#define COMPILER_CLANG 1 +#elif defined(_MSC_VER) +#define COMPILER_MSVC 1 +#endif + + // Undef anything not defined +#if !defined(COMPILER_CLANG) +#define COMPILER_CLANG 0 +#endif +#if !defined(COMPILER_MSVC) +#define COMPILER_MSVC 0 +#endif + +#if COMPILER_MSVC +#define AlignOf(T) __alignof(T) +#elif COMPILER_CLANG +#define AlignOf(T) __alignof(T) +#elif COMPILER_GCC +#define AlignOf(T) __alignof__(T) +#else +#error AlignOf not defined for this compiler. +#endif } // namespace Juliet diff --git a/Juliet/include/Core/HAL/OS/OS.h b/Juliet/include/Core/HAL/OS/OS.h new file mode 100644 index 0000000..3cf8a54 --- /dev/null +++ b/Juliet/include/Core/HAL/OS/OS.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +namespace Juliet +{ + namespace Memory + { + Byte* OS_Reserve(size_t size); + bool OS_Commit(Byte* ptr, size_t size); + void OS_Release(Byte* ptr, size_t size); + + template + Type* OS_Reserve(size_t size) + { + return reinterpret_cast(OS_Reserve(size)); + } + + template + bool OS_Commit(Type* ptr, size_t size) + { + return OS_Commit(reinterpret_cast(ptr), size); + } + + template + void OS_Release(Type* ptr, size_t size) + { + OS_Release(reinterpret_cast(ptr), size); + } + + } // namespace Memory + + using EntryPointFunc = int (*)(int, wchar_t**); + JULIET_API int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv); +} // namespace Juliet diff --git a/Juliet/include/Core/Logging/LogManager.h b/Juliet/include/Core/Logging/LogManager.h index 48dfd61..edb2ee0 100644 --- a/Juliet/include/Core/Logging/LogManager.h +++ b/Juliet/include/Core/Logging/LogManager.h @@ -6,7 +6,13 @@ // TODO : Juliet strings #include // TODO Juliet Containers + Allocators... +// TODO: Juliet chrono, because it prevents me from doing #define global static +#ifdef global +#undef global +#endif #include +#define global static + #include namespace Juliet diff --git a/Juliet/include/Core/Main.h b/Juliet/include/Core/Main.h new file mode 100644 index 0000000..31e0b03 --- /dev/null +++ b/Juliet/include/Core/Main.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +extern int JulietMain(int, wchar_t**); + +#if JULIET_WIN32 +#ifndef WINAPI +#define WINAPI __stdcall +#endif + +#if COMPILER_MSVC +#if UNICODE +int wmain(int argc, wchar_t** argv) +{ + return Juliet::Bootstrap(JulietMain, argc, argv); +} +#else +int main(int argc, char** argv) +{ + return Juliet::Bootstrap(JulietMain, argc, argv); +} +#endif +#endif + +extern "C" { + +typedef struct HINSTANCE__* HINSTANCE; +typedef char* LPSTR; +typedef wchar_t* PWSTR; + +#if UNICODE +int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrev, PWSTR szCmdLine, int sw) +#else +int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) +#endif +{ + (void)hInst; + (void)hPrev; + (void)szCmdLine; + (void)sw; + return Juliet::Bootstrap(JulietMain, __argc, __wargv); +} +} +#else +#error "Only windows main is implemented" +#endif diff --git a/Juliet/include/Core/Math/MathUtils.h b/Juliet/include/Core/Math/MathUtils.h index f301591..f7b6aff 100644 --- a/Juliet/include/Core/Math/MathUtils.h +++ b/Juliet/include/Core/Math/MathUtils.h @@ -24,6 +24,18 @@ namespace Juliet return lhs < rhs ? rhs : lhs; } + template + constexpr Type ClampTop(Type value, Type X) + { + return Min(value, X); + } + + template + constexpr Type ClampBottom(Type value, Type X) + { + return Max(value, X); + } + template constexpr Type Clamp(Type val, Type min, Type max) { diff --git a/Juliet/include/Core/Memory/MemoryArena.h b/Juliet/include/Core/Memory/MemoryArena.h index b5f005b..f89c5c8 100644 --- a/Juliet/include/Core/Memory/MemoryArena.h +++ b/Juliet/include/Core/Memory/MemoryArena.h @@ -2,12 +2,58 @@ #include #include +#include #include #include #include namespace Juliet { + constexpr global uint64 g_Arena_Default_Reserve_Size = Megabytes(64); + constexpr global uint64 g_Arena_Default_Commit_Size = Kilobytes(64); + constexpr global uint64 k_ArenaHeaderSize = 128; + + // Refactor + struct Arena + { + Arena* Previous; + Arena* Current; + + uint64 BasePosition; + uint64 Position; + uint64 Capacity; + uint64 Alignment; + + uint64 CommitSize; + uint64 ReserveSize; + + uint64 Committed; + uint64 Reserved; + }; + static_assert(sizeof(Arena) <= k_ArenaHeaderSize); + + struct ArenaParams + { + uint64 ReserveSize = g_Arena_Default_Reserve_Size; + uint64 CommitSize = g_Arena_Default_Commit_Size; + }; + + [[nodiscard]] Arena* ArenaAllocate(const ArenaParams& params = {}, + const std::source_location& loc = std::source_location::current()); + void ArenaRelease(NonNullPtr arena); + + // Raw Push, can be used but templated helpers exists below + [[nodiscard]] void* ArenaPush(NonNullPtr arena, size_t size, size_t align, bool shouldBeZeroed); + void ArenaPopTo(NonNullPtr arena, size_t position); + void ArenaPop(NonNullPtr arena, size_t amount); + void ArenaClear(NonNullPtr arena); + [[nodiscard]] size_t ArenaPos(NonNullPtr arena); + + template + [[nodiscard]] Type* ArenaPushStruct(NonNullPtr arena) + { + return static_cast(ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), true)); + } // --- Paged Memory Architecture --- struct ArenaAllocation @@ -25,23 +71,23 @@ namespace Juliet MemoryBlock* Next; // Next block in the chain (Arena) or FreeList (Pool) size_t TotalSize; // Total size of this block (including header) size_t Used; // Offset relative to the start of Data - + #if JULIET_DEBUG ArenaAllocation* FirstAllocation = nullptr; uint64 Pad; // Ensure 16-byte alignment (Size 40 -> 48) #endif - // Data follows immediately. + // Data follows immediately. // We use a helper to access it to avoid C++ flexible array warning issues if strict - uint8* GetData() { return reinterpret_cast(this + 1); } + uint8* GetData() { return reinterpret_cast(this + 1); } const uint8* GetData() const { return reinterpret_cast(this + 1); } }; struct MemoryPool { void* BaseAddress = nullptr; - size_t TotalSize = 0; - MemoryBlock* FreeList = nullptr; + size_t TotalSize = 0; + MemoryBlock* FreeList = nullptr; [[nodiscard]] MemoryBlock* AllocateBlock(size_t minCapacity); void FreeBlock(MemoryBlock* block); @@ -52,7 +98,7 @@ namespace Juliet MemoryPool* BackingPool; MemoryBlock* CurrentBlock; MemoryBlock* FirstBlock; - // Marker behavior is now tricky with pages. + // Marker behavior is now tricky with pages. // Simple Marker = { Block*, Offset } }; @@ -62,12 +108,11 @@ namespace Juliet size_t Offset; }; - - JULIET_API void MemoryArenaCreate(MemoryArena* arena, MemoryPool* pool); + JULIET_API void MemoryArenaCreate(MemoryArena* arena, MemoryPool* pool); JULIET_API void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment, String tag); - JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment, String tag); - JULIET_API bool ArenaPop(MemoryArena* arena, void* ptr, size_t size); - JULIET_API void ArenaReset(MemoryArena* arena); + JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment, String tag); + JULIET_API bool ArenaPop(MemoryArena* arena, void* ptr, size_t size); + JULIET_API void ArenaReset(MemoryArena* arena); JULIET_API ArenaMarker ArenaGetMarker(MemoryArena* arena); JULIET_API void ArenaResetToMarker(MemoryArena* arena, ArenaMarker marker); diff --git a/Juliet/include/Core/Memory/Utils.h b/Juliet/include/Core/Memory/Utils.h index de0c966..01f438d 100644 --- a/Juliet/include/Core/Memory/Utils.h +++ b/Juliet/include/Core/Memory/Utils.h @@ -22,4 +22,6 @@ namespace Juliet // TODO: homemade versions #define MemSet memset #define MemCopy memcpy + +#define MemoryZero(dst, size) MemSet(dst, 0, size) } // namespace Juliet diff --git a/Juliet/src/Core/HAL/OS/OS.cpp b/Juliet/src/Core/HAL/OS/OS.cpp new file mode 100644 index 0000000..fc0b655 --- /dev/null +++ b/Juliet/src/Core/HAL/OS/OS.cpp @@ -0,0 +1,29 @@ +#include +#include + +namespace Juliet +{ + namespace Memory + { + Byte* OS_Reserve(size_t size) + { + return Internal::OS_Reserve(size); + } + + bool OS_Commit(Byte* ptr, size_t size) + { + return Internal::OS_Commit(ptr, size); + } + + void OS_Release(Byte* ptr, size_t size) + { + Internal::OS_Release(ptr, size); + } + } // namespace Memory + + int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv) + { + return Internal::OS_Main(entryPointFunc, argc, argv); + } + +} // namespace Juliet diff --git a/Juliet/src/Core/HAL/OS/OS_Private.h b/Juliet/src/Core/HAL/OS/OS_Private.h new file mode 100644 index 0000000..4c67ab7 --- /dev/null +++ b/Juliet/src/Core/HAL/OS/OS_Private.h @@ -0,0 +1,19 @@ +#pragma once + +namespace Juliet +{ + namespace Memory + { + namespace Internal + { + Byte* OS_Reserve(size_t size); + bool OS_Commit(Byte* ptr, size_t size); + void OS_Release(Byte* ptr, size_t size); + } // namespace Internal + } // namespace Memory + + namespace Internal + { + int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv); + } +} // namespace Juliet diff --git a/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp b/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp new file mode 100644 index 0000000..642497e --- /dev/null +++ b/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include + +namespace Juliet +{ + namespace + { + global RIO_EXTENSION_FUNCTION_TABLE w32_rio_functions = {}; + } + + namespace Memory::Internal + { + Byte* OS_Reserve(size_t size) + { + auto result = static_cast(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE)); + return result; + } + + bool OS_Commit(Byte* ptr, size_t size) + { + bool result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != nullptr); + + Assert(size <= static_cast(MaxValueOf())); + + w32_rio_functions.RIODeregisterBuffer( + w32_rio_functions.RIORegisterBuffer(reinterpret_cast(ptr), static_cast(size))); + return result; + } + + void OS_Release(Byte* ptr, size_t size) + { + // size not used on windows + std::ignore = size; + + VirtualFree(ptr, 0, MEM_RELEASE); + } + } // namespace Memory::Internal + + namespace + { + // Used to handle a crash/exception + LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* exceptionPtrs) + { + (void)exceptionPtrs; + // See for more info https://github.com/EpicGamesExt/raddebugger/blob/master/src/os/core/win32/os_core_win32.c + ExitProcess(1); + } + } // namespace + + namespace Internal + { + int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv) + { + (void)argc; + (void)argv; + SetUnhandledExceptionFilter(&ExceptionFilter); + + // Allow only one instance to be launched. + CreateMutex(nullptr, false, L"Local\\Juliet.App"); + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION); + return EXIT_FAILURE; + } + + // Create a dummy socket to access RIO functions. Those will be used to do fine memory management + { + WSADATA WinSockData; + WSAStartup(MAKEWORD(2, 2), &WinSockData); + GUID guid = WSAID_MULTIPLE_RIO; + DWORD rio_byte = 0; + SOCKET Sock = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + WSAIoctl(Sock, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), + (void**)&w32_rio_functions, sizeof(w32_rio_functions), &rio_byte, nullptr, nullptr); + closesocket(Sock); + } + + return entryPointFunc(argc, argv); + } + } // namespace Internal +} // namespace Juliet diff --git a/Juliet/src/Core/HAL/Win32.h b/Juliet/src/Core/HAL/Win32.h index f551b44..42d933d 100644 --- a/Juliet/src/Core/HAL/Win32.h +++ b/Juliet/src/Core/HAL/Win32.h @@ -26,7 +26,7 @@ #define WINVER _WIN32_WINNT #ifdef __clang__ - #pragma clang diagnostic pop +#pragma clang diagnostic pop #endif #define NOIME @@ -66,6 +66,11 @@ #define NOTAPE #define ANSI_ONLY +// Keep includes in that order +#include + +#include + #include #undef min diff --git a/Juliet/src/Core/Juliet.cpp b/Juliet/src/Core/Juliet.cpp index 7577b64..a05a8d6 100644 --- a/Juliet/src/Core/Juliet.cpp +++ b/Juliet/src/Core/Juliet.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace Juliet @@ -41,11 +42,6 @@ namespace Juliet void JulietInit(JulietInit_Flags flags) { - // Mandatory systems - MemoryArenasInit(); - - InitFilesystem(); - // Optional systems if ((flags & JulietInit_Flags::Display) != JulietInit_Flags::None) { @@ -62,9 +58,6 @@ namespace Juliet DecrementSystemRefCount(JulietInit_Flags::Display); ShutdownDisplaySystem(); } - - ShutdownFilesystem(); - MemoryArenasShutdown(); } } // namespace Juliet diff --git a/Juliet/src/Core/Memory/MemoryArena.cpp b/Juliet/src/Core/Memory/MemoryArena.cpp index 174d460..12a0707 100644 --- a/Juliet/src/Core/Memory/MemoryArena.cpp +++ b/Juliet/src/Core/Memory/MemoryArena.cpp @@ -4,10 +4,181 @@ #include #include // For std::max +#include +#include +#include #include namespace Juliet { + + // TODO Get page size from os kernel call (dwPageSize) + namespace + { + constexpr uint64 k_PageSize = Kilobytes(4); + } // namespace + + // https://github.com/EpicGamesExt/raddebugger/blob/master/src/base/base_arena.c + + Arena* ArenaAllocate(const ArenaParams& params, const std::source_location& loc) + { + Log(LogLevel::Message, LogCategory::Core, "Allocating from %s : %ul", loc.file_name(), loc.line()); + + Byte* baseMem = nullptr; + + uint64 reserve_size = AlignPow2(params.ReserveSize, k_PageSize); + uint64 commit_size = AlignPow2(params.CommitSize, k_PageSize); + + // TODO: handle large pages + baseMem = Memory::OS_Reserve(reserve_size); + Memory::OS_Commit(baseMem, commit_size); + + Arena* arena = reinterpret_cast(baseMem); + arena->Current = arena; + + arena->CommitSize = commit_size; + arena->ReserveSize = reserve_size; + + arena->Committed = commit_size; + arena->Reserved = reserve_size; + + arena->BasePosition = 0; + arena->Position = k_ArenaHeaderSize; + + return arena; + } + + void ArenaRelease(NonNullPtr arena) + { + for (Arena *node = arena->Current, *previous = nullptr; node != nullptr; node = previous) + { + previous = node->Previous; + Memory::OS_Release(node, node->Reserved); + } + } + + void* ArenaPush(NonNullPtr arena, size_t size, size_t align, bool shouldBeZeroed) + { + Arena* current = arena->Current; + size_t positionPrePush = AlignPow2(current->Position, align); + size_t positionPostPush = positionPrePush + size; + + // If allowed and needed, add a new block and chain it to the arena. + if (current->Reserved < positionPostPush /* flags : chaining allowed */) + { + Arena* newBlock = nullptr; + // TODO : use the free list + + if (newBlock == nullptr) + { + size_t reserveSize = current->ReserveSize; + size_t commitSize = current->CommitSize; + + if (size + k_ArenaHeaderSize > reserveSize) + { + reserveSize = AlignPow2(size + k_ArenaHeaderSize, align); + commitSize = AlignPow2(size + k_ArenaHeaderSize, align); + } + newBlock = ArenaAllocate({ .ReserveSize = reserveSize, .CommitSize = commitSize }); + } + + newBlock->BasePosition = current->BasePosition + current->Reserved; + // Push on the linkedlist + newBlock->Previous = arena->Current; + arena->Current = newBlock; + + // TODO: Think about ryan fleur way to push: + // SLLStackPush_N(arena->current, new_block, prev); + // #define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n)) + + current = newBlock; + positionPrePush = AlignPow2(current->Position, align); + positionPostPush = positionPrePush + size; + } + + size_t sizeToZero = 0; + if (shouldBeZeroed) + { + sizeToZero = Min(current->Committed, positionPostPush) - positionPrePush; + } + + // If needed commit new pages + if (current->Committed < positionPostPush) + { + size_t commitPostAligned = positionPostPush + current->CommitSize - 1; + commitPostAligned -= commitPostAligned % current->CommitSize; + size_t commitPostClamped = ClampTop(commitPostAligned, current->Reserved); + // size_t commitSize = commitPostClamped - current->Committed; + // Byte* commitPtr = reinterpret_cast(current) + current->Committed; + + // TODO os_commit / commit_large + // os_commit(commitPtr, commitSize); + + current->Committed = commitPostClamped; + } + + // Push on the current block + void* result = nullptr; + if (current->Committed >= positionPostPush) + { + result = reinterpret_cast(current) + positionPrePush; + current->Position = positionPostPush; + if (sizeToZero != 0) + { + MemoryZero(result, sizeToZero); + } + } + + // If alloc failed, log and assert + if (result == nullptr) [[unlikely]] + { + Assert(false, "Fatal Allocation Failure - Unexpected allocation failure"); + } + + return result; + } + + void ArenaPopTo(NonNullPtr arena, size_t position) + { + size_t bbbPosition = ClampBottom(k_ArenaHeaderSize, position); + Arena* current = arena->Current; + + // TODO : Free list + for (Arena* previous = nullptr; current->BasePosition >= bbbPosition; current = previous) + { + previous = current->Previous; + Memory::OS_Release(current, current->Reserved); + } + + arena->Current = current; + size_t newPosition = bbbPosition - current->BasePosition; + Assert(newPosition <= current->Position); + current->Position = newPosition; + } + + void ArenaPop(NonNullPtr arena, size_t amount) + { + size_t oldPosition = ArenaPos(arena); + size_t newPosition = oldPosition; + if (amount < oldPosition) + { + newPosition = oldPosition - amount; + } + ArenaPopTo(arena, newPosition); + } + + void ArenaClear(NonNullPtr arena) + { + ArenaPopTo(arena, 0); + } + + size_t ArenaPos(NonNullPtr arena) + { + Arena* current = arena->Current; + size_t position = current->BasePosition + current->Position; + return position; + } + namespace UnitTest { extern void TestMemoryArena(); @@ -18,7 +189,10 @@ namespace Juliet #if JULIET_DEBUG static void FreeDebugAllocations(MemoryBlock* blk) { - if (!blk) return; + if (!blk) + { + return; + } ArenaAllocation* curr = blk->FirstAllocation; while (curr) { @@ -188,23 +362,25 @@ namespace Juliet // Commit blk->Used += alignmentOffset; void* ptr = blk->GetData() + blk->Used; - + #if JULIET_DEBUG ArenaAllocation* node = (ArenaAllocation*)Malloc(sizeof(ArenaAllocation)); - node->Offset = blk->Used; - node->Size = size; - node->Tag = tag; - node->Next = nullptr; - - if (!blk->FirstAllocation) blk->FirstAllocation = node; + node->Offset = blk->Used; + node->Size = size; + node->Tag = tag; + node->Next = nullptr; + + if (!blk->FirstAllocation) + blk->FirstAllocation = node; else { - ArenaAllocation* t = blk->FirstAllocation; - while(t->Next) t = t->Next; - t->Next = node; + ArenaAllocation* t = blk->FirstAllocation; + while (t->Next) + t = t->Next; + t->Next = node; } #endif - + blk->Used += size; return ptr; @@ -234,7 +410,8 @@ namespace Juliet #if JULIET_DEBUG { ArenaAllocation* t = blk->FirstAllocation; - while (t && t->Next) t = t->Next; + while (t && t->Next) + t = t->Next; if (t) t->Size += (newSize - oldSize); } #endif @@ -268,13 +445,24 @@ namespace Juliet blk->Used -= size; #if JULIET_DEBUG { - ArenaAllocation* t = blk->FirstAllocation; + ArenaAllocation* t = blk->FirstAllocation; ArenaAllocation* prev = nullptr; - while (t && t->Next) { prev = t; t = t->Next; } - if (t) { + while (t && t->Next) + { + prev = t; + t = t->Next; + } + if (t) + { SafeFree(t); - if (prev) prev->Next = nullptr; - else blk->FirstAllocation = nullptr; + if (prev) + { + prev->Next = nullptr; + } + else + { + blk->FirstAllocation = nullptr; + } } } #endif diff --git a/Juliet/src/Core/Memory/MemoryArenaTests.cpp b/Juliet/src/Core/Memory/MemoryArenaTests.cpp index 4afc055..f1a153a 100644 --- a/Juliet/src/Core/Memory/MemoryArenaTests.cpp +++ b/Juliet/src/Core/Memory/MemoryArenaTests.cpp @@ -7,12 +7,56 @@ namespace Juliet::UnitTest { + struct TestStruct + { + uint8 First; + uint16 Second; + }; // Need access to internal Pool functions? They are in the header now! // MemoryPool is declared in header. void TestMemoryArena() { printf("Running Paged Memory Arena Tests...\n"); + // New Arena! + Arena* testArena = ArenaAllocate(); + + size_t pos = ArenaPos(testArena); + Assert(pos == k_ArenaHeaderSize); + + TestStruct* myStruct = ArenaPushStruct(testArena); + Assert(myStruct->First == 0); + Assert(myStruct->Second == 0); + pos = ArenaPos(testArena); + Assert(pos == k_ArenaHeaderSize + sizeof(TestStruct)); + + TestStruct* myStruct2 = ArenaPushStruct(testArena); + Assert(myStruct2->First == 0); + Assert(myStruct2->Second == 0); + + myStruct->First = 5; + myStruct->Second = 125; + myStruct2->First = 5; + myStruct2->Second = 125; + + ArenaClear(testArena); + pos = ArenaPos(testArena); + Assert(pos == k_ArenaHeaderSize); + + myStruct = ArenaPushStruct(testArena); + Assert(myStruct->First == 0); + Assert(myStruct->Second == 0); + pos = ArenaPos(testArena); + Assert(pos == k_ArenaHeaderSize + sizeof(TestStruct)); + + TestStruct* myStruct3 = ArenaPushStruct(testArena); + Assert(myStruct3->First == 0); + Assert(myStruct3->Second == 0); + pos = ArenaPos(testArena); + Assert(pos == k_ArenaHeaderSize + sizeof(TestStruct) * 2); + + ArenaRelease(testArena); + // Setup Pool and Arena for Pop Tests size_t testPoolSize = Megabytes(1); void* testBacking = Calloc(1, testPoolSize); diff --git a/Juliet/src/Core/Networking/SocketPlatformImpl.h b/Juliet/src/Core/Networking/SocketPlatformImpl.h index b185804..b86dff5 100644 --- a/Juliet/src/Core/Networking/SocketPlatformImpl.h +++ b/Juliet/src/Core/Networking/SocketPlatformImpl.h @@ -5,13 +5,11 @@ // Windows uses a non standard header to define its socket types. // Because of that we need to include those in this header. // TODO : implement for other platforms -#if JULIET_WIN32 - -#include - -#else -// UNIMPLEMENT_SOCKETS -#endif +// #if JULIET_WIN32 +// #include +// #else +// // UNIMPLEMENT_SOCKETS +// #endif namespace Juliet::SocketImpl { diff --git a/Juliet/src/Core/Networking/Win32/Win32SocketPlatformImpl.cpp b/Juliet/src/Core/Networking/Win32/Win32SocketPlatformImpl.cpp index b7fff31..494ee13 100644 --- a/Juliet/src/Core/Networking/Win32/Win32SocketPlatformImpl.cpp +++ b/Juliet/src/Core/Networking/Win32/Win32SocketPlatformImpl.cpp @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/Juliet/src/Engine/Engine.cpp b/Juliet/src/Engine/Engine.cpp index 1934ae7..c37685c 100644 --- a/Juliet/src/Engine/Engine.cpp +++ b/Juliet/src/Engine/Engine.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -129,12 +130,18 @@ namespace Juliet void InitializeEngine(JulietInit_Flags flags) { InitializeLogManager(); + MemoryArenasInit(); + InitFilesystem(); + JulietInit(flags); } void ShutdownEngine() { JulietShutdown(); + + ShutdownFilesystem(); + MemoryArenasShutdown(); ShutdownLogManager(); } diff --git a/JulietApp/JulietApp.bff b/JulietApp/JulietApp.bff index a14b5dc..4c22f30 100644 --- a/JulietApp/JulietApp.bff +++ b/JulietApp/JulietApp.bff @@ -80,6 +80,15 @@ } .LinkerOptions + .CRTLibs + // Pointing the entry point + .SubSystem = ' /SUBSYSTEM:WINDOWS' + If ( .BuildConfigName == 'Debug' ) + { + ^SubSystem = ' /SUBSYSTEM:WINDOWS' // We use console in debug + + } + .LinkerOptions + .SubSystem + // Manifest .LinkerAssemblyResources = .ManifestFile .LinkerOptions + ' /MANIFEST:EMBED' diff --git a/JulietApp/main.cpp b/JulietApp/main.cpp index 8bfe4f1..be29479 100644 --- a/JulietApp/main.cpp +++ b/JulietApp/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -23,7 +24,6 @@ #include #ifdef JULIET_ENABLE_IMGUI -#include #include #endif @@ -454,19 +454,8 @@ JulietApplication& GetEditorApplication() return EditorApplication; } -int main(int /*argc*/, char** /*argv*/) +int JulietMain(int, wchar_t**) { - // Allow only one instance to be launched. - // Need to create Mutex code in the lib because i dont want to include windows.h in this file anymore - // CreateMutex(0, false, L"Local\\Juliet.App"); - // if (GetLastError() == ERROR_ALREADY_EXISTS) - // { - // MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION); - // return EXIT_FAILURE; - // } - - setvbuf(stdout, nullptr, _IONBF, 0); - if (__argc > 1) { for (int i = 1; i < __argc; ++i)