From fafeeb8dd52def03fafd60ed5295e434b67935d2 Mon Sep 17 00:00:00 2001 From: RDW Date: Sun, 12 Oct 2025 01:49:21 +0200 Subject: [PATCH 01/10] Win32: Generalize the memory arena setup code Not much of a point in tagging with a lot of debug info right now,. --- Core/Platforms/Win32.cpp | 28 ++++---- Core/Platforms/Win32/DebugDraw.cpp | 18 +---- Core/Platforms/Win32/Memory.cpp | 108 +++++++---------------------- Core/Platforms/Win32/Memory.hpp | 39 +++++------ 4 files changed, 60 insertions(+), 133 deletions(-) diff --git a/Core/Platforms/Win32.cpp b/Core/Platforms/Win32.cpp index 603996aa..b50abc87 100644 --- a/Core/Platforms/Win32.cpp +++ b/Core/Platforms/Win32.cpp @@ -323,10 +323,14 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, MONOTONIC_CLOCK_SPEED = ticksPerSecond.QuadPart; hardware_tick_t lastUpdateTime = PerformanceMetricsNow(); - // TODO Override via CLI arguments or something? (Can also compute based on available RAM) - constexpr size_t MAIN_MEMORY_SIZE = Megabytes(85); - constexpr size_t TRANSIENT_MEMORY_SIZE = Megabytes(1596) + Kilobytes(896); - SystemMemoryInitializeArenas(MAIN_MEMORY_SIZE, TRANSIENT_MEMORY_SIZE); + PLACEHOLDER_MEMORY_CONFIGURATION.persistentMemoryOptions = PlatformDefaultAllocationOptions(); + PLACEHOLDER_MEMORY_CONFIGURATION.transientMemoryOptions = PlatformDefaultAllocationOptions(); +#ifdef RAGLITE_PREDICTABLE_MEMORY + PLACEHOLDER_MEMORY_CONFIGURATION.persistentMemoryOptions.startingAddress = (LPVOID)HIGHEST_VIRTUAL_ADDRESS; +#endif + PLACEHOLDER_MEMORY_CONFIGURATION.persistentMemoryOptions.reservedSize = Megabytes(85); + PLACEHOLDER_MEMORY_CONFIGURATION.transientMemoryOptions.reservedSize = Megabytes(1596) + Kilobytes(896); + PlatformInitializeProgramMemory(PLACEHOLDER_PROGRAM_MEMORY, PLACEHOLDER_MEMORY_CONFIGURATION); WNDCLASSEX windowClass = {}; // TODO Is this really a good idea? Beware the CS_OWNDC footguns... @@ -396,21 +400,21 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, PLACEHOLDER_DEMO_APP.offsetY++; size_t allocationSize = Megabytes(2); - if(!SystemMemoryCanAllocate(MAIN_MEMORY, allocationSize)) { - SystemMemoryReset(MAIN_MEMORY); + if(!SystemMemoryCanAllocate(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, allocationSize)) { + SystemMemoryReset(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory); } else { - uint8* mainMemory = (uint8*)SystemMemoryAllocate(MAIN_MEMORY, allocationSize); + uint8* mainMemory = (uint8*)SystemMemoryAllocate(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, allocationSize); *mainMemory = 0xDE; - SystemMemoryDebugTouch(MAIN_MEMORY, mainMemory); + SystemMemoryDebugTouch(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, mainMemory); } - if(!SystemMemoryCanAllocate(TRANSIENT_MEMORY, 2 * allocationSize)) { - SystemMemoryReset(TRANSIENT_MEMORY); + if(!SystemMemoryCanAllocate(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, 2 * allocationSize)) { + SystemMemoryReset(PLACEHOLDER_PROGRAM_MEMORY.transientMemory); } else { - uint8* transientMemory = (uint8*)SystemMemoryAllocate(TRANSIENT_MEMORY, 2 * allocationSize); + uint8* transientMemory = (uint8*)SystemMemoryAllocate(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, 2 * allocationSize); *transientMemory = 0xAB; - SystemMemoryDebugTouch(TRANSIENT_MEMORY, transientMemory); + SystemMemoryDebugTouch(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, transientMemory); } GamePadPollControllers(PLACEHOLDER_DEMO_APP.offsetX, PLACEHOLDER_DEMO_APP.offsetY); diff --git a/Core/Platforms/Win32/DebugDraw.cpp b/Core/Platforms/Win32/DebugDraw.cpp index d40fdb06..3403b5ef 100644 --- a/Core/Platforms/Win32/DebugDraw.cpp +++ b/Core/Platforms/Win32/DebugDraw.cpp @@ -509,20 +509,6 @@ INTERNAL void DebugDrawMemoryArenaHeatmap(HDC& displayDeviceContext, memory_aren constexpr size_t FORMAT_BUFFER_SIZE = 256; char formatBuffer[FORMAT_BUFFER_SIZE]; - StringCbPrintfA(formatBuffer, FORMAT_BUFFER_SIZE, "Name: %s", arena.displayName.buffer); - TextOutA(displayDeviceContext, startX + DEBUG_OVERLAY_PADDING_SIZE, lineY, formatBuffer, lstrlenA(formatBuffer)); - lineY += DEBUG_OVERLAY_LINE_HEIGHT; - - String lifetime = SystemMemoryDebugLifetime(arena); - StringCbPrintfA(formatBuffer, FORMAT_BUFFER_SIZE, "Lifetime: %s", lifetime.buffer); - TextOutA(displayDeviceContext, startX + DEBUG_OVERLAY_PADDING_SIZE, lineY, formatBuffer, lstrlenA(formatBuffer)); - lineY += DEBUG_OVERLAY_LINE_HEIGHT; - - String usage = SystemMemoryDebugUsage(arena); - StringCbPrintfA(formatBuffer, FORMAT_BUFFER_SIZE, "Usage: %s", usage.buffer); - TextOutA(displayDeviceContext, startX + DEBUG_OVERLAY_PADDING_SIZE, lineY, formatBuffer, lstrlenA(formatBuffer)); - lineY += DEBUG_OVERLAY_LINE_HEIGHT; - StringCbPrintfA(formatBuffer, FORMAT_BUFFER_SIZE, "Base: 0x%p", arena.baseAddress); TextOutA(displayDeviceContext, startX + DEBUG_OVERLAY_PADDING_SIZE, lineY, formatBuffer, lstrlenA(formatBuffer)); lineY += DEBUG_OVERLAY_LINE_HEIGHT; @@ -646,12 +632,12 @@ INTERNAL void DebugDrawMemoryUsageOverlay(HDC& displayDeviceContext) { startX += DEBUG_OVERLAY_PADDING_SIZE; heatmapWidth = MAIN_MEMORY_PANELS * heatmapWidth + (MAIN_MEMORY_PANELS - 1) * DEBUG_OVERLAY_MARGIN_SIZE; - DebugDrawMemoryArenaHeatmap(displayDeviceContext, MAIN_MEMORY, startX, lineY, heatmapWidth, heatmapHeight); + DebugDrawMemoryArenaHeatmap(displayDeviceContext, PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, startX, lineY, heatmapWidth, heatmapHeight); startX += heatmapWidth; startX += DEBUG_OVERLAY_MARGIN_SIZE; heatmapWidth = TRANSIENT_MEMORY_PANELS * heatmapWidth + (TRANSIENT_MEMORY_PANELS - 1) * DEBUG_OVERLAY_MARGIN_SIZE; - DebugDrawMemoryArenaHeatmap(displayDeviceContext, TRANSIENT_MEMORY, startX, lineY, heatmapWidth, heatmapHeight); + DebugDrawMemoryArenaHeatmap(displayDeviceContext, PLACEHOLDER_PROGRAM_MEMORY.transientMemory, startX, lineY, heatmapWidth, heatmapHeight); startX += heatmapWidth; startX += DEBUG_OVERLAY_PADDING_SIZE; diff --git a/Core/Platforms/Win32/Memory.cpp b/Core/Platforms/Win32/Memory.cpp index 6dd0afb9..91cd1c9c 100644 --- a/Core/Platforms/Win32/Memory.cpp +++ b/Core/Platforms/Win32/Memory.cpp @@ -1,93 +1,28 @@ constexpr size_t HIGHEST_VIRTUAL_ADDRESS = Terabytes(1); -constexpr size_t INVALID_VIRTUAL_ADDRESS = 0xDEADBEEFULL; +constexpr size_t UNSPECIFIED_VIRTUAL_ADDRESS = NULL; // NOTE: OS will determine where to allocate the region -GLOBAL memory_arena_t MAIN_MEMORY = { - .displayName = StringLiteral("Main Memory"), - .lifetime = KEEP_FOREVER_MANUAL_RESET, - .usage = UNUSED_PLACEHOLDER, - .baseAddress = (void*)INVALID_VIRTUAL_ADDRESS, - .reservedSize = 0, - .committedSize = 0, - .used = 0, - .allocationCount = 0 -}; +GLOBAL program_memory_t PLACEHOLDER_PROGRAM_MEMORY = {}; +GLOBAL memory_config_t PLACEHOLDER_MEMORY_CONFIGURATION = {}; -GLOBAL memory_arena_t TRANSIENT_MEMORY = { - .displayName = StringLiteral("Transient Memory"), - .lifetime = RESET_AFTER_EACH_FRAME, - .usage = UNUSED_PLACEHOLDER, - .baseAddress = (void*)INVALID_VIRTUAL_ADDRESS, - .reservedSize = 0, - .committedSize = 0, - .used = 0, - .allocationCount = 0 -}; - -// TBD Guard with feature flag (check if compiler removes when unused - assumption: yes) -INTERNAL String SystemMemoryDebugUsage(memory_arena_t& arena) { - switch(arena.lifetime) { - case UNUSED_PLACEHOLDER: - return StringLiteral("Unused (Placeholder)"); - case PREALLOCATED_ON_LOAD: - return StringLiteral("Preallocated (Default)"); - case DYNAMIC_RESIZE_FREELIST: - return StringLiteral("Dynamic (Resizeable)"); - case CAN_HOT_RELOAD: - return StringLiteral("Reloadable (Pinned)"); - default: - return StringLiteral("N/A"); - } -} - -INTERNAL String SystemMemoryDebugLifetime(memory_arena_t& arena) { - switch(arena.lifetime) { - case KEEP_FOREVER_MANUAL_RESET: - return StringLiteral("Forever (Global Arena)"); - case RESET_AFTER_EACH_FRAME: - return StringLiteral("Frame (Scoped Arena)"); - case RESET_AFTER_TASK_COMPLETION: - return StringLiteral("Task Completion (Transfer Arena)"); - case RESET_AUTOMATICALLY_TIMED_EXPIRY: - return StringLiteral("Auto-Expires (Caching Arena)"); - default: - return StringLiteral("N/A"); - } -} - -INTERNAL void SystemMemoryInitializeArenas(size_t mainMemorySize, size_t transientMemorySize) { - -#ifdef RAGLITE_PREDICTABLE_MEMORY - LPVOID baseAddress = 0; -#else - LPVOID baseAddress = (LPVOID)HIGHEST_VIRTUAL_ADDRESS; -#endif - - DWORD allocationTypeFlags = MEM_RESERVE | MEM_COMMIT; - DWORD memoryProtectionFlags = PAGE_READWRITE; - MAIN_MEMORY = { - .displayName = StringLiteral("Main Memory"), - .lifetime = KEEP_FOREVER_MANUAL_RESET, - .usage = PREALLOCATED_ON_LOAD, - .baseAddress = VirtualAlloc(baseAddress, mainMemorySize + transientMemorySize, allocationTypeFlags, memoryProtectionFlags), - .reservedSize = mainMemorySize, - .committedSize = 0, - .used = 0, - .allocationCount = 0 +INTERNAL inline allocation_options_t PlatformDefaultAllocationOptions() { + memory_allocation_options options = { + .allocationType = MEM_RESERVE | MEM_COMMIT, + .protectionConstraints = PAGE_READWRITE, + .startingAddress = (LPVOID)UNSPECIFIED_VIRTUAL_ADDRESS, }; + // TODO: Zeroize on push + // TODO: Align on push + // TODO: Append guard pages (in debug mode) + // TODO: Add source location (in debug mode) + return options; +} - TRANSIENT_MEMORY = { - .displayName = StringLiteral("Transient Memory"), - .lifetime = KEEP_FOREVER_MANUAL_RESET, - .usage = PREALLOCATED_ON_LOAD, - .baseAddress = (uint8*)MAIN_MEMORY.baseAddress + mainMemorySize, - .reservedSize = transientMemorySize, - .committedSize = 0, - .used = 0, - .allocationCount = 0 - }; +INTERNAL void SystemMemoryInitializeArena(memory_arena_t& arena, allocation_options_t& options) { + ZeroMemory(&arena, sizeof(arena)); + arena.baseAddress = VirtualAlloc(options.startingAddress, options.reservedSize, options.allocationType, options.protectionConstraints); - MAIN_MEMORY.committedSize = mainMemorySize; - TRANSIENT_MEMORY.committedSize = transientMemorySize; + arena.reservedSize = options.reservedSize; + if(options.allocationType & MEM_COMMIT) arena.committedSize = options.reservedSize; } INTERNAL void* SystemMemoryAllocate(memory_arena_t& arena, size_t allocationSize) { @@ -115,4 +50,9 @@ INTERNAL inline void SystemMemoryDebugTouch(memory_arena_t& arena, uint8* addres ASSUME(address >= arena.baseAddress, "Attempted to access an invalid arena offset"); size_t offset = address - (uint8*)arena.baseAddress; // TODO: Update last accessed time +} + +INTERNAL inline void PlatformInitializeProgramMemory(program_memory_t& programMemory, memory_config_t& configOptions) { + SystemMemoryInitializeArena(programMemory.persistentMemory, configOptions.persistentMemoryOptions); + SystemMemoryInitializeArena(programMemory.transientMemory, configOptions.transientMemoryOptions); } \ No newline at end of file diff --git a/Core/Platforms/Win32/Memory.hpp b/Core/Platforms/Win32/Memory.hpp index 9d8eed98..08f75659 100644 --- a/Core/Platforms/Win32/Memory.hpp +++ b/Core/Platforms/Win32/Memory.hpp @@ -1,28 +1,25 @@ -// NOTE: These are mutually exclusive - do not combine them ever (unhappiness will find you) -enum arena_lifetime_flag { - KEEP_FOREVER_MANUAL_RESET = 0, // Default choice (make sure the arena is small) - RESET_AFTER_EACH_FRAME, // Transient memory likely wants to use this mode - RESET_AFTER_TASK_COMPLETION, // Async workloads/resource loading (NYI) - RESET_AUTOMATICALLY_TIMED_EXPIRY, // For persistent resources/prefetcher/memory pressure mode (NYI) -}; - -// TBD: Not sure if these are useful for anything other than debug annotations (revisit later) -enum arena_usage_flag { - UNUSED_PLACEHOLDER = 0, - PREALLOCATED_ON_LOAD, // Sane default (choose whenever possible) - DYNAMIC_RESIZE_FREELIST, // NYI: Can remove this ideally? (not sure yet, keep as a reminder for now) - CAN_HOT_RELOAD, // NOTE: Must not change structures with this flag or things will go horribly wrong -}; - typedef struct virtual_memory_arena { - // TBD: Gate debug-time features via flags? Unlikely to matter for the time being (revisit later) - String displayName; - arena_lifetime_flag lifetime; - arena_usage_flag usage; // TBD: Store this header in the arena itself (required for free-lists/resizes - later)? void* baseAddress; size_t reservedSize; size_t committedSize; size_t used; size_t allocationCount; -} memory_arena_t; \ No newline at end of file +} memory_arena_t; + +typedef struct program_memory_state { + memory_arena_t persistentMemory; + memory_arena_t transientMemory; +} program_memory_t; + +typedef struct memory_allocation_options { + uint32 allocationType; + uint32 protectionConstraints; + size_t reservedSize; + void* startingAddress; +} allocation_options_t; + +typedef struct program_memory_requirements { + allocation_options_t persistentMemoryOptions; + allocation_options_t transientMemoryOptions; +} memory_config_t; \ No newline at end of file From 3f8302d8e759638844e038fe536d6ae0aac96420 Mon Sep 17 00:00:00 2001 From: RDW Date: Sun, 12 Oct 2025 02:10:39 +0200 Subject: [PATCH 02/10] Refactor: Extract world updates from the main loop --- Core/Platforms/Win32.cpp | 64 +++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/Core/Platforms/Win32.cpp b/Core/Platforms/Win32.cpp index b50abc87..aabaa703 100644 --- a/Core/Platforms/Win32.cpp +++ b/Core/Platforms/Win32.cpp @@ -2,12 +2,12 @@ #define TODO(msg) OutputDebugStringA(msg); -// TODO: Replace these with the actual game/application state later -typedef struct volatile_game_state { +typedef struct volatile_world_state { int32 offsetX; int32 offsetY; -} game_state_t; -GLOBAL game_state_t PLACEHOLDER_DEMO_APP = { +} world_state_t; + +GLOBAL world_state_t PLACEHOLDER_WORLD_STATE = { .offsetX = 0, .offsetY = 0, }; @@ -94,6 +94,33 @@ INTERNAL const char* ArchitectureToDebugName(WORD wProcessorArchitecture) { #include "Win32/DebugDraw.cpp" +INTERNAL void PlatformUpdateWorldState(world_state_t& worldState) { + worldState.offsetX++; + worldState.offsetY++; + worldState.offsetY++; + + size_t allocationSize = Megabytes(2); + if(!SystemMemoryCanAllocate(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, allocationSize)) { + SystemMemoryReset(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory); + } else { + uint8* mainMemory = (uint8*)SystemMemoryAllocate(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, allocationSize); + *mainMemory = 0xDE; + SystemMemoryDebugTouch(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, mainMemory); + } + + if(!SystemMemoryCanAllocate(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, 2 * allocationSize)) { + SystemMemoryReset(PLACEHOLDER_PROGRAM_MEMORY.transientMemory); + } else { + + uint8* transientMemory = (uint8*)SystemMemoryAllocate(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, 2 * allocationSize); + *transientMemory = 0xAB; + SystemMemoryDebugTouch(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, transientMemory); + } + + GamePadPollControllers(worldState.offsetX, worldState.offsetY); + DebugDrawUpdateBackgroundPattern(); +} + INTERNAL void SurfacePresentFrameBuffer(gdi_surface_t& surface, gdi_offscreen_buffer_t& backBuffer) { if(!surface.displayDeviceContext || !surface.offscreenDeviceContext || !backBuffer.handle) { // Minimized or not yet initialized @@ -128,7 +155,7 @@ INTERNAL void MainWindowRedrawEverything(HWND& window) { } hardware_tick_t before = PerformanceMetricsNow(); - DebugDrawIntoFrameBuffer(GDI_BACKBUFFER, PLACEHOLDER_DEMO_APP.offsetX, PLACEHOLDER_DEMO_APP.offsetY); + DebugDrawIntoFrameBuffer(GDI_BACKBUFFER, PLACEHOLDER_WORLD_STATE.offsetX, PLACEHOLDER_WORLD_STATE.offsetY); CPU_PERFORMANCE_METRICS.worldRenderTime = PerformanceMetricsGetTimeSince(before); before = PerformanceMetricsNow(); @@ -393,32 +420,7 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, hardware_tick_t before = PerformanceMetricsNow(); if(!APPLICATION_SHOULD_PAUSE) { - - // NOTE: Application/game state updates should go here (later) - PLACEHOLDER_DEMO_APP.offsetX++; - PLACEHOLDER_DEMO_APP.offsetY++; - PLACEHOLDER_DEMO_APP.offsetY++; - - size_t allocationSize = Megabytes(2); - if(!SystemMemoryCanAllocate(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, allocationSize)) { - SystemMemoryReset(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory); - } else { - uint8* mainMemory = (uint8*)SystemMemoryAllocate(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, allocationSize); - *mainMemory = 0xDE; - SystemMemoryDebugTouch(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, mainMemory); - } - - if(!SystemMemoryCanAllocate(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, 2 * allocationSize)) { - SystemMemoryReset(PLACEHOLDER_PROGRAM_MEMORY.transientMemory); - } else { - - uint8* transientMemory = (uint8*)SystemMemoryAllocate(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, 2 * allocationSize); - *transientMemory = 0xAB; - SystemMemoryDebugTouch(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, transientMemory); - } - - GamePadPollControllers(PLACEHOLDER_DEMO_APP.offsetX, PLACEHOLDER_DEMO_APP.offsetY); - DebugDrawUpdateBackgroundPattern(); + PlatformUpdateWorldState(PLACEHOLDER_WORLD_STATE); } CPU_PERFORMANCE_METRICS.worldUpdateTime = PerformanceMetricsGetTimeSince(before); From d03fed1915a928dfcad43c298f99635b9b311ddb Mon Sep 17 00:00:00 2001 From: RDW Date: Sun, 12 Oct 2025 02:25:34 +0200 Subject: [PATCH 03/10] Win32: Introduce defines to resize the default arenas --- Core/Platforms/Win32.cpp | 4 ++-- Core/RagLite2.hpp | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Core/Platforms/Win32.cpp b/Core/Platforms/Win32.cpp index aabaa703..8bcdf651 100644 --- a/Core/Platforms/Win32.cpp +++ b/Core/Platforms/Win32.cpp @@ -355,8 +355,8 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, #ifdef RAGLITE_PREDICTABLE_MEMORY PLACEHOLDER_MEMORY_CONFIGURATION.persistentMemoryOptions.startingAddress = (LPVOID)HIGHEST_VIRTUAL_ADDRESS; #endif - PLACEHOLDER_MEMORY_CONFIGURATION.persistentMemoryOptions.reservedSize = Megabytes(85); - PLACEHOLDER_MEMORY_CONFIGURATION.transientMemoryOptions.reservedSize = Megabytes(1596) + Kilobytes(896); + PLACEHOLDER_MEMORY_CONFIGURATION.persistentMemoryOptions.reservedSize = RAGLITE_PERSISTENT_MEMORY; + PLACEHOLDER_MEMORY_CONFIGURATION.transientMemoryOptions.reservedSize = RAGLITE_TRANSIENT_MEMORY; PlatformInitializeProgramMemory(PLACEHOLDER_PROGRAM_MEMORY, PLACEHOLDER_MEMORY_CONFIGURATION); WNDCLASSEX windowClass = {}; diff --git a/Core/RagLite2.hpp b/Core/RagLite2.hpp index f1858c16..d7b36411 100644 --- a/Core/RagLite2.hpp +++ b/Core/RagLite2.hpp @@ -48,4 +48,12 @@ static_assert(PLATFORM_POINTER_SIZE == Bits(64), "Only 64-bit platforms are curr #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #error "Only Little-Endian platforms are currently supported" +#endif + +#ifndef RAGLITE_PERSISTENT_MEMORY +#define RAGLITE_PERSISTENT_MEMORY Megabytes(85) +#endif + +#ifndef RAGLITE_TRANSIENT_MEMORY +#define RAGLITE_TRANSIENT_MEMORY Megabytes(1596) + Kilobytes(896) #endif \ No newline at end of file From 7bce2922311df4022ec0aa568f46a8d629d6a66c Mon Sep 17 00:00:00 2001 From: RDW Date: Sun, 12 Oct 2025 21:18:28 +0200 Subject: [PATCH 04/10] Refactor: Move global simulation state to the RagLite2 program Doesn't really fit into the platform layer, which is supposed to run multiple programs after all. --- Core/{Platforms/Win32 => }/Memory.hpp | 0 Core/Platforms/Win32.cpp | 11 ----------- Core/Platforms/Win32/Memory.cpp | 3 --- Core/RagLite2.cpp | 12 ++++++++++++ 4 files changed, 12 insertions(+), 14 deletions(-) rename Core/{Platforms/Win32 => }/Memory.hpp (100%) diff --git a/Core/Platforms/Win32/Memory.hpp b/Core/Memory.hpp similarity index 100% rename from Core/Platforms/Win32/Memory.hpp rename to Core/Memory.hpp diff --git a/Core/Platforms/Win32.cpp b/Core/Platforms/Win32.cpp index 8bcdf651..8a59e50d 100644 --- a/Core/Platforms/Win32.cpp +++ b/Core/Platforms/Win32.cpp @@ -2,16 +2,6 @@ #define TODO(msg) OutputDebugStringA(msg); -typedef struct volatile_world_state { - int32 offsetX; - int32 offsetY; -} world_state_t; - -GLOBAL world_state_t PLACEHOLDER_WORLD_STATE = { - .offsetX = 0, - .offsetY = 0, -}; - constexpr size_t MAX_ERROR_MSG_SIZE = 512; GLOBAL TCHAR SYSTEM_ERROR_MESSAGE[MAX_ERROR_MSG_SIZE]; @@ -84,7 +74,6 @@ INTERNAL const char* ArchitectureToDebugName(WORD wProcessorArchitecture) { } #include "Win32/DebugDraw.hpp" -#include "Win32/Memory.hpp" #include "Win32/GamePad.cpp" #include "Win32/Keyboard.cpp" diff --git a/Core/Platforms/Win32/Memory.cpp b/Core/Platforms/Win32/Memory.cpp index 91cd1c9c..88792245 100644 --- a/Core/Platforms/Win32/Memory.cpp +++ b/Core/Platforms/Win32/Memory.cpp @@ -1,9 +1,6 @@ constexpr size_t HIGHEST_VIRTUAL_ADDRESS = Terabytes(1); constexpr size_t UNSPECIFIED_VIRTUAL_ADDRESS = NULL; // NOTE: OS will determine where to allocate the region -GLOBAL program_memory_t PLACEHOLDER_PROGRAM_MEMORY = {}; -GLOBAL memory_config_t PLACEHOLDER_MEMORY_CONFIGURATION = {}; - INTERNAL inline allocation_options_t PlatformDefaultAllocationOptions() { memory_allocation_options options = { .allocationType = MEM_RESERVE | MEM_COMMIT, diff --git a/Core/RagLite2.cpp b/Core/RagLite2.cpp index f4abb3f7..e89b2d05 100644 --- a/Core/RagLite2.cpp +++ b/Core/RagLite2.cpp @@ -9,6 +9,18 @@ #include "Numbers.hpp" #include "Strings.hpp" +#include "Memory.hpp" + +GLOBAL program_memory_t PLACEHOLDER_PROGRAM_MEMORY = {}; +GLOBAL memory_config_t PLACEHOLDER_MEMORY_CONFIGURATION = {}; + +typedef struct volatile_world_state { + int32 offsetX; + int32 offsetY; +} world_state_t; + +GLOBAL world_state_t PLACEHOLDER_WORLD_STATE = {}; + #ifdef RAGLITE_PLATFORM_WINDOWS #include "Platforms/Win32.cpp" #endif \ No newline at end of file From 8f44ffd8fb561fdcc0f273804ceb2a4e6e08781c Mon Sep 17 00:00:00 2001 From: RDW Date: Sun, 12 Oct 2025 21:35:01 +0200 Subject: [PATCH 05/10] Build: Create a separate build target for the Win32 runtime Need to use DLLs for hot reloading/to support multiple programs. --- build.bat | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/build.bat b/build.bat index aa7b41ba..1c440fe9 100644 --- a/build.bat +++ b/build.bat @@ -1,8 +1,13 @@ @echo off +set DEBUG_EXE=RagLiteWin32Dbg.exe +set RELEASE_EXE=RagLiteWin32.exe + set CPP_MAIN=Core\RagLite2.cpp -set DEBUG_EXE=RagLite2Dbg.exe -set RELEASE_EXE=RagLite2.exe +set DLL_MAIN=Core\RagLite2.cpp +set DEBUG_DLL=RagLite2Dbg.dll +set RELEASE_DLL=RagLite2.dll + set RUNTIME_LIBS=gdi32.lib shlwapi.lib user32.lib xinput.lib winmm.lib for /f "delims=" %%i in ('call git describe --always --dirty') do set GIT_COMMIT_HASH=\"%%i\" @@ -80,13 +85,8 @@ set DEBUG_LINK_FLAGS=%DEBUG_LINK_FLAGS% /DEBUG set DEBUG_COMPILE_FLAGS=%DEBUG_COMPILE_FLAGS% %SHARED_COMPILE_FLAGS% set DEBUG_LINK_FLAGS=%DEBUG_LINK_FLAGS% %SHARED_LINK_FLAGS% -echo The Ancient One speaketh: -echo Let us now turn %CPP_MAIN% into %DEBUG_EXE%! -echo Harken, mortal, as I prepare thy unholy incantation... -echo cl%DEBUG_COMPILE_FLAGS% %CPP_MAIN% %RUNTIME_LIBS% /link %DEBUG_LINK_FLAGS% %ICON_RES% /out:%DEBUG_EXE% -echo -------------------------------------------------------------------------------------------------------- cl %DEBUG_COMPILE_FLAGS% %CPP_MAIN% %RUNTIME_LIBS% /link %DEBUG_LINK_FLAGS% %ICON_RES% /out:%DEBUG_EXE% || exit /b -echo -------------------------------------------------------------------------------------------------------- +cl %DEBUG_COMPILE_FLAGS% %DLL_MAIN% %RUNTIME_LIBS% /DLL /link %DEBUG_LINK_FLAGS% %ICON_RES% /out:%DEBUG_DLL% || exit /b :::::: Build release binary set RELEASE_COMPILE_FLAGS= @@ -119,16 +119,12 @@ set RELEASE_LINK_FLAGS=%RELEASE_LINK_FLAGS% /OPT:ICF set RELEASE_COMPILE_FLAGS=%RELEASE_COMPILE_FLAGS% %SHARED_COMPILE_FLAGS% set RELEASE_LINK_FLAGS=%RELEASE_LINK_FLAGS% %SHARED_LINK_FLAGS% -echo The Ancient One speaketh: -echo Let us now turn %CPP_MAIN% into %RELEASE_EXE%! -echo Harken, mortal, as I prepare thy unholy incantation... -echo cl%RELEASE_COMPILE_FLAGS% %CPP_MAIN% %RUNTIME_LIBS% /link %RELEASE_LINK_FLAGS% %ICON_RES% /out:%RELEASE_EXE% -echo -------------------------------------------------------------------------------------------------------- cl %RELEASE_COMPILE_FLAGS% %CPP_MAIN% %RUNTIME_LIBS% /link %RELEASE_LINK_FLAGS% %ICON_RES% /out:%RELEASE_EXE% || exit /b -echo -------------------------------------------------------------------------------------------------------- +cl %RELEASE_COMPILE_FLAGS% %DLL_MAIN% %RUNTIME_LIBS% /DLL /link %RELEASE_LINK_FLAGS% %ICON_RES% /out:%RELEASE_DLL% || exit /b :: Cleanup -move RagLite2*.exe %DEFAULT_BUILD_DIR% 2> NUL +move RagLite*.exe %DEFAULT_BUILD_DIR% 2> NUL +move RagLite*.dll %DEFAULT_BUILD_DIR% 2> NUL move *.idb %DEFAULT_BUILD_DIR% 2> NUL move *.obj %DEFAULT_BUILD_DIR% 2> NUL move *.pdb %DEFAULT_BUILD_DIR% 2> NUL \ No newline at end of file From 192c7caf635a1753580a7c2f6fd95a66d4fc3c81 Mon Sep 17 00:00:00 2001 From: RDW Date: Sun, 12 Oct 2025 22:12:15 +0200 Subject: [PATCH 06/10] Refactor: Move simulation updates to the program DLL --- Core/Modules.hpp | 29 ++++ Core/Platforms/Win32.cpp | 71 +++++----- Core/Platforms/Win32.hpp | 44 +++++- Core/Platforms/Win32/DebugDraw.cpp | 167 ----------------------- Core/Platforms/Win32/DebugDraw.hpp | 10 -- Core/RagLite2.cpp | 206 ++++++++++++++++++++++++++++- Core/RagLite2.hpp | 1 + build.bat | 10 +- 8 files changed, 326 insertions(+), 212 deletions(-) create mode 100644 Core/Modules.hpp diff --git a/Core/Modules.hpp b/Core/Modules.hpp new file mode 100644 index 00000000..f8cbdc7d --- /dev/null +++ b/Core/Modules.hpp @@ -0,0 +1,29 @@ +#pragma once + +typedef struct simulation_frame_inputs { + uint64 clock; + milliseconds uptime; + // TODO: Controller/keyboard/mouse inputs +} program_input_t; + +// TODO sync with GDI struct (single source of truth) +typedef struct { + int32 width; // TBD: uint32? + int32 height; + int32 bytesPerPixel; + int32 stride; + void* pixelBuffer; +} offscreen_buffer_t; + +typedef struct simulation_frame_outputs { + // TODO: Should push render commands and not actually draw into a buffer + offscreen_buffer_t canvas; + + // TODO: Audio buffer/outputs + uint32 bitrateSamplesPerSecond; + uint32 samplesArraySize; + int16 samples; +} program_output_t; + +// TBD: AdvanceSimulation +EXPORT void SimulateNextFrame(program_memory_t* memory, program_input_t* inputs, program_output_t* outputs); diff --git a/Core/Platforms/Win32.cpp b/Core/Platforms/Win32.cpp index 8a59e50d..a25ac6fe 100644 --- a/Core/Platforms/Win32.cpp +++ b/Core/Platforms/Win32.cpp @@ -83,33 +83,6 @@ INTERNAL const char* ArchitectureToDebugName(WORD wProcessorArchitecture) { #include "Win32/DebugDraw.cpp" -INTERNAL void PlatformUpdateWorldState(world_state_t& worldState) { - worldState.offsetX++; - worldState.offsetY++; - worldState.offsetY++; - - size_t allocationSize = Megabytes(2); - if(!SystemMemoryCanAllocate(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, allocationSize)) { - SystemMemoryReset(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory); - } else { - uint8* mainMemory = (uint8*)SystemMemoryAllocate(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, allocationSize); - *mainMemory = 0xDE; - SystemMemoryDebugTouch(PLACEHOLDER_PROGRAM_MEMORY.persistentMemory, mainMemory); - } - - if(!SystemMemoryCanAllocate(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, 2 * allocationSize)) { - SystemMemoryReset(PLACEHOLDER_PROGRAM_MEMORY.transientMemory); - } else { - - uint8* transientMemory = (uint8*)SystemMemoryAllocate(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, 2 * allocationSize); - *transientMemory = 0xAB; - SystemMemoryDebugTouch(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, transientMemory); - } - - GamePadPollControllers(worldState.offsetX, worldState.offsetY); - DebugDrawUpdateBackgroundPattern(); -} - INTERNAL void SurfacePresentFrameBuffer(gdi_surface_t& surface, gdi_offscreen_buffer_t& backBuffer) { if(!surface.displayDeviceContext || !surface.offscreenDeviceContext || !backBuffer.handle) { // Minimized or not yet initialized @@ -144,7 +117,8 @@ INTERNAL void MainWindowRedrawEverything(HWND& window) { } hardware_tick_t before = PerformanceMetricsNow(); - DebugDrawIntoFrameBuffer(GDI_BACKBUFFER, PLACEHOLDER_WORLD_STATE.offsetX, PLACEHOLDER_WORLD_STATE.offsetY); + // TODO move to program code (cannot access buffer/clock directly, though) + // DebugDrawIntoFrameBuffer(GDI_BACKBUFFER, 0, 0); CPU_PERFORMANCE_METRICS.worldRenderTime = PerformanceMetricsGetTimeSince(before); before = PerformanceMetricsNow(); @@ -219,7 +193,7 @@ LRESULT CALLBACK MainWindowProcessIncomingMessage(HWND window, UINT message, WPA case WM_SIZE: { MainWindowCreateFrameBuffers(window, GDI_SURFACE, GDI_BACKBUFFER); // NOTE: Updating again allows the simulation to appear more fluid (evaluate UX later) - DebugDrawUpdateBackgroundPattern(); + // DebugDrawUpdateBackgroundPattern(); MainWindowRedrawEverything(window); } break; @@ -347,6 +321,8 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, PLACEHOLDER_MEMORY_CONFIGURATION.persistentMemoryOptions.reservedSize = RAGLITE_PERSISTENT_MEMORY; PLACEHOLDER_MEMORY_CONFIGURATION.transientMemoryOptions.reservedSize = RAGLITE_TRANSIENT_MEMORY; PlatformInitializeProgramMemory(PLACEHOLDER_PROGRAM_MEMORY, PLACEHOLDER_MEMORY_CONFIGURATION); + // PlatformLoadModule("RagLite2Dbg.dll"); + GameCode game = LoadGameCode("RagLite2Dbg.dll", "RagLite2Dbg.pdb"); // TBD Dbg or release... WNDCLASSEX windowClass = {}; // TODO Is this really a good idea? Beware the CS_OWNDC footguns... @@ -409,7 +385,42 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, hardware_tick_t before = PerformanceMetricsNow(); if(!APPLICATION_SHOULD_PAUSE) { - PlatformUpdateWorldState(PLACEHOLDER_WORLD_STATE); + // GamePadPollControllers(worldState.offsetX, worldState.offsetY); // TODO pass to program + + // TODO Add to debug UI (?) + FILETIME new_time = GetLastWriteTime("RagLite2Dbg.dll"); // TBD Dbg or release + if(CompareFileTime(&new_time, &game.last_write_time) != 0) { + // DLL changed + UnloadGameCode(&game); + game = LoadGameCode("RagLite2Dbg.dll", "RagLite2Dbg.pdb"); + } + + program_input_t inputs = { + .clock = PerformanceMetricsNow(), + .uptime = PerformanceMetricsGetTimeSince(applicationStartTime), + }; + program_output_t outputs = { + .canvas = { + .width = GDI_BACKBUFFER.width, + .height = GDI_BACKBUFFER.height, + .bytesPerPixel = GDI_BACKBUFFER.bytesPerPixel, + .stride = GDI_BACKBUFFER.stride, + .pixelBuffer = GDI_BACKBUFFER.pixelBuffer, + } + }; + + ASSUME(game.SimulateNextFrame, "Failed to load program module (cannot advance the simulation)"); + if(game.SimulateNextFrame) game.SimulateNextFrame(&PLACEHOLDER_PROGRAM_MEMORY, &inputs, &outputs); + + size_t allocationSize = Megabytes(2); + if(!SystemMemoryCanAllocate(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, 2 * allocationSize)) { + SystemMemoryReset(PLACEHOLDER_PROGRAM_MEMORY.transientMemory); + } else { + + uint8* transientMemory = (uint8*)SystemMemoryAllocate(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, 2 * allocationSize); + *transientMemory = 0xAB; + SystemMemoryDebugTouch(PLACEHOLDER_PROGRAM_MEMORY.transientMemory, transientMemory); + } } CPU_PERFORMANCE_METRICS.worldUpdateTime = PerformanceMetricsGetTimeSince(before); diff --git a/Core/Platforms/Win32.hpp b/Core/Platforms/Win32.hpp index d3e4bb21..e03316ec 100644 --- a/Core/Platforms/Win32.hpp +++ b/Core/Platforms/Win32.hpp @@ -6,4 +6,46 @@ #include #include #include -#include \ No newline at end of file +#include + +struct GameCode { + HMODULE dll; + FILETIME last_write_time; + void (*SimulateNextFrame)(program_memory_t* memory, program_input_t* inputs, program_output_t* outputs); +}; + +FILETIME GetLastWriteTime(const char* filename) { + WIN32_FILE_ATTRIBUTE_DATA data; + if(GetFileAttributesExA(filename, GetFileExInfoStandard, &data)) + return data.ftLastWriteTime; + FILETIME empty = {}; + return empty; +} + +GameCode LoadGameCode(const char* dll_path, const char* pdb_path) { + GameCode result = {}; + result.last_write_time = GetLastWriteTime(dll_path); + + // char temp_dll[MAX_PATH]; + // sprintf_s(temp_dll, "", dll_path); + + // Copy to temp to allow rebuilds + // TBD: Also copy debug info to avoid having to add custom path mappings in the debugger... + CopyFileA(pdb_path, "RagLite2Dbg.loaded.pdb", FALSE); + CopyFileA(dll_path, "RagLite2Dbg.loaded.dll", FALSE); + result.dll = LoadLibraryA("RagLite2Dbg.loaded.dll"); + // TBD: Should probably delete this on exit? + // result.dll = LoadLibraryA(dll_path); + if(result.dll) + result.SimulateNextFrame = (void (*)(program_memory_t*, program_input_t*, program_output_t*))GetProcAddress(result.dll, "SimulateNextFrame"); + + return result; +} + +void UnloadGameCode(GameCode* code) { + if(code->dll) { + FreeLibrary(code->dll); + code->dll = 0; + code->SimulateNextFrame = 0; + } +} \ No newline at end of file diff --git a/Core/Platforms/Win32/DebugDraw.cpp b/Core/Platforms/Win32/DebugDraw.cpp index 3403b5ef..85f0484e 100644 --- a/Core/Platforms/Win32/DebugDraw.cpp +++ b/Core/Platforms/Win32/DebugDraw.cpp @@ -1004,170 +1004,3 @@ INTERNAL void DebugDrawKeyboardOverlay(HDC& displayDeviceContext) { SelectObject(displayDeviceContext, oldFont); } - -INTERNAL void DebugDrawUpdateBackgroundPattern() { - DWORD ticks = GetTickCount(); - seconds elapsed = (seconds)ticks / MILLISECONDS_PER_SECOND; - seconds updateInterval = 5.0f; - - gdi_debug_pattern_t newPattern = (gdi_debug_pattern_t)(elapsed / updateInterval); - GDI_DEBUG_PATTERN = (gdi_debug_pattern_t)(newPattern % PATTERN_COUNT); -} - -INTERNAL void DebugDrawUseMarchingGradientPattern(gdi_offscreen_buffer_t& bitmap, - int offsetBlue, - int offsetGreen) { - if(!bitmap.pixelBuffer) - return; - - uint8* row = (uint8*)bitmap.pixelBuffer; - for(int y = 0; y < bitmap.height; ++y) { - uint32* pixel = (uint32*)row; - for(int x = 0; x < bitmap.width; ++x) { - uint8 blue = (x + offsetBlue) & 0xFF; - uint8 green = (y + offsetGreen) & 0xFF; - - *pixel++ = ((green << 8) | blue); - } - - row += bitmap.stride; - } -} - -INTERNAL void DebugDrawUseRipplingSpiralPattern(gdi_offscreen_buffer_t& bitmap, int time, - int) { - if(!bitmap.pixelBuffer) - return; - - uint8* row = (uint8*)bitmap.pixelBuffer; - - for(int y = 0; y < bitmap.height; ++y) { - uint32* pixel = (uint32*)row; - for(int x = 0; x < bitmap.width; ++x) { - - int centerX = bitmap.width / 2; - int centerY = bitmap.height / 2; - float dx = (float)(x - centerX); - float dy = (float)(y - centerY); - float dist = sqrtf(dx * dx + dy * dy); - float wave = 0.5f + 0.5f * sinf(dist / 5.0f - time * 0.1f); - - uint8 blue = (uint8)(wave * 255); - uint8 green = (uint8)((1.0f - wave) * 255); - uint8 red = (uint8)((0.5f + 0.5f * sinf(time * 0.05f)) * 255); - - *pixel++ = (red << 16) | (green << 8) | blue; - } - row += bitmap.stride; - } -} - -INTERNAL void DebugDrawUseCheckeredFloorPattern(gdi_offscreen_buffer_t& bitmap, int time, - int) { - if(!bitmap.pixelBuffer) - return; - - uint8* row = (uint8*)bitmap.pixelBuffer; - - float angle = time * 0.02f; - float cosA = cosf(angle); - float sinA = sinf(angle); - - int cx = bitmap.width / 2; - int cy = bitmap.height / 2; - - int squareSize = 32; - - for(int y = 0; y < bitmap.height; ++y) { - uint32* pixel = (uint32*)row; - for(int x = 0; x < bitmap.width; ++x) { - int rx = x - cx; - int ry = y - cy; - - float rX = rx * cosA - ry * sinA; - float rY = rx * sinA + ry * cosA; - - int checkerX = ((int)floorf(rX / squareSize)) & 1; - int checkerY = ((int)floorf(rY / squareSize)) & 1; - - uint8 c = (checkerX ^ checkerY) ? (PROGRESS_BAR_WIDTH - 1) : 80; - *pixel++ = (c << 16) | (c << 8) | c; - } - row += bitmap.stride; - } -} - -INTERNAL void DebugDrawUseColorGradientPattern(gdi_offscreen_buffer_t& bitmap, int, - int) { - if(!bitmap.pixelBuffer) - return; - - uint8* row = (uint8*)bitmap.pixelBuffer; - - int cx = bitmap.width / 2; - int cy = bitmap.height / 2; - - for(int y = 0; y < bitmap.height; ++y) { - uint32* pixel = (uint32*)row; - for(int x = 0; x < bitmap.width; ++x) { - uint8 red = (uint8)((x * 255) / bitmap.width); - uint8 green = (uint8)((y * 255) / bitmap.height); - uint8 blue = 0; - - if(x == cx || y == cy) { - red = green = blue = 255; - } - - *pixel++ = (red << 16) | (green << 8) | blue; - } - row += bitmap.stride; - } -} - -INTERNAL void DebugDrawUseMovingScanlinePattern(gdi_offscreen_buffer_t& bitmap, int time, - int) { - if(!bitmap.pixelBuffer) - return; - - uint8* row = (uint8*)bitmap.pixelBuffer; - - int gridSpacing = 32; - int scanY = (time / 2) % bitmap.height; - - for(int y = 0; y < bitmap.height; ++y) { - uint32* pixel = (uint32*)row; - for(int x = 0; x < bitmap.width; ++x) { - uint8 c = 180; - - if(x % gridSpacing == 0 || y % gridSpacing == 0) - c = 100; - - if(y == scanY) - c = 255; - - *pixel++ = (c << 16) | (c << 8) | c; - } - row += bitmap.stride; - } -} - -INTERNAL void DebugDrawIntoFrameBuffer(gdi_offscreen_buffer_t& bitmap, int paramA, - int paramB) { - switch(GDI_DEBUG_PATTERN) { - case PATTERN_SHIFTING_GRADIENT: - DebugDrawUseMarchingGradientPattern(bitmap, paramA, paramB); - break; - case PATTERN_CIRCULAR_RIPPLE: - DebugDrawUseRipplingSpiralPattern(bitmap, paramA, paramB); - break; - case PATTERN_CHECKERBOARD: - DebugDrawUseCheckeredFloorPattern(bitmap, paramA, paramB); - break; - case PATTERN_AXIS_GRADIENTS: - DebugDrawUseColorGradientPattern(bitmap, paramA, paramB); - break; - case PATTERN_GRID_SCANLINE: - DebugDrawUseMovingScanlinePattern(bitmap, paramA, paramB); - break; - } -} diff --git a/Core/Platforms/Win32/DebugDraw.hpp b/Core/Platforms/Win32/DebugDraw.hpp index 2651240d..60733a17 100644 --- a/Core/Platforms/Win32/DebugDraw.hpp +++ b/Core/Platforms/Win32/DebugDraw.hpp @@ -17,18 +17,8 @@ typedef struct gdi_surface { int height; } gdi_surface_t; -typedef enum : uint8 { - PATTERN_SHIFTING_GRADIENT, - PATTERN_CIRCULAR_RIPPLE, - PATTERN_CHECKERBOARD, - PATTERN_AXIS_GRADIENTS, - PATTERN_GRID_SCANLINE, - PATTERN_COUNT -} gdi_debug_pattern_t; - GLOBAL gdi_offscreen_buffer_t GDI_BACKBUFFER = {}; GLOBAL gdi_surface_t GDI_SURFACE = {}; -GLOBAL gdi_debug_pattern_t GDI_DEBUG_PATTERN = PATTERN_SHIFTING_GRADIENT; typedef union gdi_rgba_color { // NOTE: For simplicity, ensure this matches the pixel format used by GDI bitmaps diff --git a/Core/RagLite2.cpp b/Core/RagLite2.cpp index e89b2d05..9c142415 100644 --- a/Core/RagLite2.cpp +++ b/Core/RagLite2.cpp @@ -10,17 +10,221 @@ #include "Strings.hpp" #include "Memory.hpp" +#include "Modules.hpp" +// TODO move or remove GLOBAL program_memory_t PLACEHOLDER_PROGRAM_MEMORY = {}; GLOBAL memory_config_t PLACEHOLDER_MEMORY_CONFIGURATION = {}; +#ifdef RAGLITE_HOT_RELOAD + +// TODO Eliminate this +#include + +typedef enum : uint8 { + PATTERN_SHIFTING_GRADIENT, + PATTERN_CIRCULAR_RIPPLE, + PATTERN_CHECKERBOARD, + PATTERN_AXIS_GRADIENTS, + PATTERN_GRID_SCANLINE, + PATTERN_COUNT +} gdi_debug_pattern_t; + typedef struct volatile_world_state { + uint64 createdTimestamp; int32 offsetX; int32 offsetY; + gdi_debug_pattern_t activeDebugDrawingPattern; } world_state_t; -GLOBAL world_state_t PLACEHOLDER_WORLD_STATE = {}; +INTERNAL void DebugDrawUpdateBackgroundPattern(world_state_t* worldState, program_input_t* inputs) { + // DWORD ticks = GetTickCount(); + seconds elapsed = inputs->uptime / MILLISECONDS_PER_SECOND; + seconds updateInterval = 5.0f; + + gdi_debug_pattern_t newPattern = (gdi_debug_pattern_t)(elapsed / updateInterval); + worldState->activeDebugDrawingPattern = (gdi_debug_pattern_t)(newPattern % PATTERN_COUNT); +} + +INTERNAL void DebugDrawUseMarchingGradientPattern(offscreen_buffer_t& bitmap, + int offsetBlue, + int offsetGreen) { + if(!bitmap.pixelBuffer) + return; + + uint8* row = (uint8*)bitmap.pixelBuffer; + for(int y = 0; y < bitmap.height; ++y) { + uint32* pixel = (uint32*)row; + for(int x = 0; x < bitmap.width; ++x) { + uint8 blue = (x + offsetBlue) & 0xFF; + uint8 green = (y + offsetGreen) & 0xFF; + + *pixel++ = ((green << 8) | blue); + } + + row += bitmap.stride; + } +} + +INTERNAL void DebugDrawUseRipplingSpiralPattern(offscreen_buffer_t& bitmap, int time, + int) { + if(!bitmap.pixelBuffer) + return; + + uint8* row = (uint8*)bitmap.pixelBuffer; + + for(int y = 0; y < bitmap.height; ++y) { + uint32* pixel = (uint32*)row; + for(int x = 0; x < bitmap.width; ++x) { + + int centerX = bitmap.width / 2; + int centerY = bitmap.height / 2; + float dx = (float)(x - centerX); + float dy = (float)(y - centerY); + float dist = sqrtf(dx * dx + dy * dy); + float wave = 0.5f + 0.5f * sinf(dist / 5.0f - time * 0.1f); + + uint8 blue = (uint8)(wave * 255); + uint8 green = (uint8)((1.0f - wave) * 255); + uint8 red = (uint8)((0.5f + 0.5f * sinf(time * 0.05f)) * 255); + + *pixel++ = (red << 16) | (green << 8) | blue; + } + row += bitmap.stride; + } +} + +INTERNAL void DebugDrawUseCheckeredFloorPattern(offscreen_buffer_t& bitmap, int time, + int) { + if(!bitmap.pixelBuffer) + return; + + uint8* row = (uint8*)bitmap.pixelBuffer; + + float angle = time * 0.02f; + float cosA = cosf(angle); + float sinA = sinf(angle); + + int cx = bitmap.width / 2; + int cy = bitmap.height / 2; + + int squareSize = 32; + + for(int y = 0; y < bitmap.height; ++y) { + uint32* pixel = (uint32*)row; + for(int x = 0; x < bitmap.width; ++x) { + int rx = x - cx; + int ry = y - cy; + + float rX = rx * cosA - ry * sinA; + float rY = rx * sinA + ry * cosA; + + int checkerX = ((int)floorf(rX / squareSize)) & 1; + int checkerY = ((int)floorf(rY / squareSize)) & 1; + + uint8 c = (checkerX ^ checkerY) ? UINT8_MAX : 80; + *pixel++ = (c << 16) | (c << 8) | c; + } + row += bitmap.stride; + } +} + +INTERNAL void DebugDrawUseColorGradientPattern(offscreen_buffer_t& bitmap, int, + int) { + if(!bitmap.pixelBuffer) + return; + + uint8* row = (uint8*)bitmap.pixelBuffer; + + int cx = bitmap.width / 2; + int cy = bitmap.height / 2; + + for(int y = 0; y < bitmap.height; ++y) { + uint32* pixel = (uint32*)row; + for(int x = 0; x < bitmap.width; ++x) { + uint8 red = (uint8)((x * 255) / bitmap.width); + uint8 green = (uint8)((y * 255) / bitmap.height); + uint8 blue = 0; + + if(x == cx || y == cy) { + red = green = blue = 255; + } + + *pixel++ = (red << 16) | (green << 8) | blue; + } + row += bitmap.stride; + } +} + +INTERNAL void DebugDrawUseMovingScanlinePattern(offscreen_buffer_t& bitmap, int time, + int) { + if(!bitmap.pixelBuffer) + return; + + uint8* row = (uint8*)bitmap.pixelBuffer; + + int gridSpacing = 32; + int scanY = (time / 2) % bitmap.height; + + for(int y = 0; y < bitmap.height; ++y) { + uint32* pixel = (uint32*)row; + for(int x = 0; x < bitmap.width; ++x) { + uint8 c = 180; + + if(x % gridSpacing == 0 || y % gridSpacing == 0) + c = 100; + + if(y == scanY) + c = 255; + + *pixel++ = (c << 16) | (c << 8) | c; + } + row += bitmap.stride; + } +} + +INTERNAL void DebugDrawIntoFrameBuffer(world_state_t* worldState, offscreen_buffer_t& bitmap) { + int paramA = worldState->offsetX; + int paramB = worldState->offsetY; + switch(worldState->activeDebugDrawingPattern) { + case PATTERN_SHIFTING_GRADIENT: + DebugDrawUseMarchingGradientPattern(bitmap, paramA, paramB); + break; + case PATTERN_CIRCULAR_RIPPLE: + DebugDrawUseRipplingSpiralPattern(bitmap, paramA, paramB); + break; + case PATTERN_CHECKERBOARD: + DebugDrawUseCheckeredFloorPattern(bitmap, paramA, paramB); + break; + case PATTERN_AXIS_GRADIENTS: + DebugDrawUseColorGradientPattern(bitmap, paramA, paramB); + break; + case PATTERN_GRID_SCANLINE: + DebugDrawUseMovingScanlinePattern(bitmap, paramA, paramB); + break; + } +} + +EXPORT void SimulateNextFrame(program_memory_t* memory, program_input_t* inputs, program_output_t* outputs) { + world_state_t* worldState = (world_state_t*)memory->persistentMemory.baseAddress; + if(!worldState->createdTimestamp) { + worldState->createdTimestamp = inputs->clock; + worldState->activeDebugDrawingPattern = PATTERN_SHIFTING_GRADIENT; + } + + worldState->offsetX++; + worldState->offsetX++; + worldState->offsetY++; + // TODO update/render time needs to be fixed in the profiler? + DebugDrawUpdateBackgroundPattern(worldState, inputs); + DebugDrawIntoFrameBuffer(worldState, outputs->canvas); + + // NYI: Push draw commands to the platform's render queue +} +#else #ifdef RAGLITE_PLATFORM_WINDOWS #include "Platforms/Win32.cpp" +#endif + #endif \ No newline at end of file diff --git a/Core/RagLite2.hpp b/Core/RagLite2.hpp index d7b36411..4694375a 100644 --- a/Core/RagLite2.hpp +++ b/Core/RagLite2.hpp @@ -25,6 +25,7 @@ #ifdef _MSC_VER #undef RAGLITE_COMPILER_MSVC #define RAGLITE_COMPILER_MSVC 1 +#define EXPORT extern "C" __declspec(dllexport) #else #define RAGLITE_UNSUPPORTED_COMPILER #endif diff --git a/build.bat b/build.bat index 1c440fe9..867d1612 100644 --- a/build.bat +++ b/build.bat @@ -7,6 +7,9 @@ set CPP_MAIN=Core\RagLite2.cpp set DLL_MAIN=Core\RagLite2.cpp set DEBUG_DLL=RagLite2Dbg.dll set RELEASE_DLL=RagLite2.dll +set DLL_FLAGS=/LD /DRAGLITE_HOT_RELOAD + +:: TODO: Skip .lib generation? set RUNTIME_LIBS=gdi32.lib shlwapi.lib user32.lib xinput.lib winmm.lib @@ -43,7 +46,7 @@ set SHARED_COMPILE_FLAGS=%SHARED_COMPILE_FLAGS% /options:strict :: /W4 Enable informational warnings (levels 0 through 4) set SHARED_COMPILE_FLAGS=%SHARED_COMPILE_FLAGS% /W4 :: ...except useless ones -set SHARED_COMPILE_FLAGS=%SHARED_COMPILE_FLAGS% /wd4189 /wd4100 +set SHARED_COMPILE_FLAGS=%SHARED_COMPILE_FLAGS% /wd4189 /wd4100 /wd4505 :: /WX Treat all warnings as errors set SHARED_COMPILE_FLAGS=%SHARED_COMPILE_FLAGS% /WX :: /Zc:strictStrings Require const qualifier for pointers initialized via string literals @@ -86,7 +89,7 @@ set DEBUG_COMPILE_FLAGS=%DEBUG_COMPILE_FLAGS% %SHARED_COMPILE_FLAGS% set DEBUG_LINK_FLAGS=%DEBUG_LINK_FLAGS% %SHARED_LINK_FLAGS% cl %DEBUG_COMPILE_FLAGS% %CPP_MAIN% %RUNTIME_LIBS% /link %DEBUG_LINK_FLAGS% %ICON_RES% /out:%DEBUG_EXE% || exit /b -cl %DEBUG_COMPILE_FLAGS% %DLL_MAIN% %RUNTIME_LIBS% /DLL /link %DEBUG_LINK_FLAGS% %ICON_RES% /out:%DEBUG_DLL% || exit /b +cl %DEBUG_COMPILE_FLAGS% %DLL_MAIN% %RUNTIME_LIBS% %DLL_FLAGS% /link %DEBUG_LINK_FLAGS% /out:%DEBUG_DLL% || exit /b :::::: Build release binary set RELEASE_COMPILE_FLAGS= @@ -120,11 +123,12 @@ set RELEASE_COMPILE_FLAGS=%RELEASE_COMPILE_FLAGS% %SHARED_COMPILE_FLAGS% set RELEASE_LINK_FLAGS=%RELEASE_LINK_FLAGS% %SHARED_LINK_FLAGS% cl %RELEASE_COMPILE_FLAGS% %CPP_MAIN% %RUNTIME_LIBS% /link %RELEASE_LINK_FLAGS% %ICON_RES% /out:%RELEASE_EXE% || exit /b -cl %RELEASE_COMPILE_FLAGS% %DLL_MAIN% %RUNTIME_LIBS% /DLL /link %RELEASE_LINK_FLAGS% %ICON_RES% /out:%RELEASE_DLL% || exit /b +cl %RELEASE_COMPILE_FLAGS% %DLL_MAIN% %RUNTIME_LIBS% %DLL_FLAGS% /link %RELEASE_LINK_FLAGS% /out:%RELEASE_DLL% || exit /b :: Cleanup move RagLite*.exe %DEFAULT_BUILD_DIR% 2> NUL move RagLite*.dll %DEFAULT_BUILD_DIR% 2> NUL move *.idb %DEFAULT_BUILD_DIR% 2> NUL +move *.lib %DEFAULT_BUILD_DIR% 2> NUL move *.obj %DEFAULT_BUILD_DIR% 2> NUL move *.pdb %DEFAULT_BUILD_DIR% 2> NUL \ No newline at end of file From 90596cca6a6035a69a710282557bd09bba4787e8 Mon Sep 17 00:00:00 2001 From: RDW Date: Mon, 13 Oct 2025 16:55:56 +0200 Subject: [PATCH 07/10] Win32: Fix time computations inside the program DLL Can't base it on HW ticks (no OS API = unknown frame of reference). --- Core/RagLite2.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Core/RagLite2.cpp b/Core/RagLite2.cpp index 9c142415..5692376a 100644 --- a/Core/RagLite2.cpp +++ b/Core/RagLite2.cpp @@ -38,11 +38,8 @@ typedef struct volatile_world_state { } world_state_t; INTERNAL void DebugDrawUpdateBackgroundPattern(world_state_t* worldState, program_input_t* inputs) { - // DWORD ticks = GetTickCount(); - seconds elapsed = inputs->uptime / MILLISECONDS_PER_SECOND; - seconds updateInterval = 5.0f; - - gdi_debug_pattern_t newPattern = (gdi_debug_pattern_t)(elapsed / updateInterval); + milliseconds updateInterval = 5.0f * MILLISECONDS_PER_SECOND; + gdi_debug_pattern_t newPattern = (gdi_debug_pattern_t)(inputs->uptime / updateInterval); worldState->activeDebugDrawingPattern = (gdi_debug_pattern_t)(newPattern % PATTERN_COUNT); } @@ -94,14 +91,14 @@ INTERNAL void DebugDrawUseRipplingSpiralPattern(offscreen_buffer_t& bitmap, int } } -INTERNAL void DebugDrawUseCheckeredFloorPattern(offscreen_buffer_t& bitmap, int time, - int) { +INTERNAL void DebugDrawUseCheckeredFloorPattern(offscreen_buffer_t& bitmap, program_input_t* inputs) { if(!bitmap.pixelBuffer) return; uint8* row = (uint8*)bitmap.pixelBuffer; - float angle = time * 0.02f; + milliseconds rotationInterval = 5.0f * MILLISECONDS_PER_SECOND; + float angle = inputs->uptime / rotationInterval; float cosA = cosf(angle); float sinA = sinf(angle); @@ -183,7 +180,8 @@ INTERNAL void DebugDrawUseMovingScanlinePattern(offscreen_buffer_t& bitmap, int } } -INTERNAL void DebugDrawIntoFrameBuffer(world_state_t* worldState, offscreen_buffer_t& bitmap) { +INTERNAL void DebugDrawIntoFrameBuffer(world_state_t* worldState, program_input_t* inputs, program_output_t* outputs) { + offscreen_buffer_t bitmap = outputs->canvas; int paramA = worldState->offsetX; int paramB = worldState->offsetY; switch(worldState->activeDebugDrawingPattern) { @@ -194,7 +192,7 @@ INTERNAL void DebugDrawIntoFrameBuffer(world_state_t* worldState, offscreen_buff DebugDrawUseRipplingSpiralPattern(bitmap, paramA, paramB); break; case PATTERN_CHECKERBOARD: - DebugDrawUseCheckeredFloorPattern(bitmap, paramA, paramB); + DebugDrawUseCheckeredFloorPattern(bitmap, inputs); break; case PATTERN_AXIS_GRADIENTS: DebugDrawUseColorGradientPattern(bitmap, paramA, paramB); @@ -217,7 +215,7 @@ EXPORT void SimulateNextFrame(program_memory_t* memory, program_input_t* inputs, worldState->offsetY++; // TODO update/render time needs to be fixed in the profiler? DebugDrawUpdateBackgroundPattern(worldState, inputs); - DebugDrawIntoFrameBuffer(worldState, outputs->canvas); + DebugDrawIntoFrameBuffer(worldState, inputs, outputs); // NYI: Push draw commands to the platform's render queue } From e3aca5d5b5ebee1c6e43885129d794b0a68dd6c5 Mon Sep 17 00:00:00 2001 From: RDW Date: Mon, 13 Oct 2025 17:06:49 +0200 Subject: [PATCH 08/10] Refactor: Rename memory functions exclusive to the platform layer These should never be called from within the program DLL and might later be moved elsewhere. --- Core/Platforms/Win32/Memory.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/Platforms/Win32/Memory.cpp b/Core/Platforms/Win32/Memory.cpp index 88792245..3d8fe490 100644 --- a/Core/Platforms/Win32/Memory.cpp +++ b/Core/Platforms/Win32/Memory.cpp @@ -14,7 +14,7 @@ INTERNAL inline allocation_options_t PlatformDefaultAllocationOptions() { return options; } -INTERNAL void SystemMemoryInitializeArena(memory_arena_t& arena, allocation_options_t& options) { +INTERNAL void PlatformInitializeMemoryArena(memory_arena_t& arena, allocation_options_t& options) { ZeroMemory(&arena, sizeof(arena)); arena.baseAddress = VirtualAlloc(options.startingAddress, options.reservedSize, options.allocationType, options.protectionConstraints); @@ -50,6 +50,6 @@ INTERNAL inline void SystemMemoryDebugTouch(memory_arena_t& arena, uint8* addres } INTERNAL inline void PlatformInitializeProgramMemory(program_memory_t& programMemory, memory_config_t& configOptions) { - SystemMemoryInitializeArena(programMemory.persistentMemory, configOptions.persistentMemoryOptions); - SystemMemoryInitializeArena(programMemory.transientMemory, configOptions.transientMemoryOptions); + PlatformInitializeMemoryArena(programMemory.persistentMemory, configOptions.persistentMemoryOptions); + PlatformInitializeMemoryArena(programMemory.transientMemory, configOptions.transientMemoryOptions); } \ No newline at end of file From f7671c9f94d4b840ae683b2bc3ba0ba535d2a194 Mon Sep 17 00:00:00 2001 From: RDW Date: Mon, 13 Oct 2025 17:12:57 +0200 Subject: [PATCH 09/10] Build: Disable access to Win32 platform APIs when building the program DLL There may be a need to provide OS services that aren't yet covered later. For now, strictly separate them and pass HW inputs each frame. --- Core/RagLite2.cpp | 2 +- Core/RagLite2.hpp | 5 +++++ build.bat | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Core/RagLite2.cpp b/Core/RagLite2.cpp index 5692376a..7bdd4dca 100644 --- a/Core/RagLite2.cpp +++ b/Core/RagLite2.cpp @@ -16,7 +16,7 @@ GLOBAL program_memory_t PLACEHOLDER_PROGRAM_MEMORY = {}; GLOBAL memory_config_t PLACEHOLDER_MEMORY_CONFIGURATION = {}; -#ifdef RAGLITE_HOT_RELOAD +#ifdef RAGLITE_PLATFORM_NONE // TODO Eliminate this #include diff --git a/Core/RagLite2.hpp b/Core/RagLite2.hpp index 4694375a..eee20561 100644 --- a/Core/RagLite2.hpp +++ b/Core/RagLite2.hpp @@ -4,6 +4,9 @@ #define RAGLITE_COMMIT_HASH "N/A" #endif +#ifndef RAGLITE_PLATFORM_NONE +// NOTE: Disabling all platform APIs for program DLLs for now to avoid accidental callbacks into the OS + #ifdef _WIN32 #define RAGLITE_PLATFORM_WINDOWS #elifdef __APPLE__ @@ -18,6 +21,8 @@ #error "Unsupported Platform: OS-specific code paths have yet to be ported" #endif +#endif + #define RAGLITE_COMPILER_GCC 0 #define RAGLITE_COMPILER_LLVM 0 #define RAGLITE_COMPILER_MSVC 0 diff --git a/build.bat b/build.bat index 867d1612..b77a4911 100644 --- a/build.bat +++ b/build.bat @@ -7,7 +7,7 @@ set CPP_MAIN=Core\RagLite2.cpp set DLL_MAIN=Core\RagLite2.cpp set DEBUG_DLL=RagLite2Dbg.dll set RELEASE_DLL=RagLite2.dll -set DLL_FLAGS=/LD /DRAGLITE_HOT_RELOAD +set DLL_FLAGS=/LD /DRAGLITE_PLATFORM_NONE :: TODO: Skip .lib generation? From b2f2076dd3216570b80976f26f5476be36798024 Mon Sep 17 00:00:00 2001 From: RDW Date: Mon, 13 Oct 2025 17:18:15 +0200 Subject: [PATCH 10/10] Refactor: Split memory arena and platform memory APIs For convenience, program code should still be able to use arena APIs. --- Core/Memory.hpp | 29 ++++++++++++++++++++++++++++- Core/Platforms/Win32/Memory.cpp | 27 --------------------------- Core/RagLite2.cpp | 11 +++++++++++ 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/Core/Memory.hpp b/Core/Memory.hpp index 08f75659..c9b2ba54 100644 --- a/Core/Memory.hpp +++ b/Core/Memory.hpp @@ -22,4 +22,31 @@ typedef struct memory_allocation_options { typedef struct program_memory_requirements { allocation_options_t persistentMemoryOptions; allocation_options_t transientMemoryOptions; -} memory_config_t; \ No newline at end of file +} memory_config_t; + +INTERNAL void* SystemMemoryAllocate(memory_arena_t& arena, size_t allocationSize) { + size_t totalUsed = arena.used + allocationSize; + ASSUME(totalUsed <= arena.reservedSize, "Attempting to allocate outside the reserved set"); + + void* memoryRegionStartPointer = (uint8*)arena.baseAddress + arena.used; + arena.used = totalUsed; + arena.allocationCount++; + + return memoryRegionStartPointer; +} + +INTERNAL bool SystemMemoryCanAllocate(memory_arena_t& arena, size_t allocationSize) { + if(arena.used + allocationSize > arena.reservedSize) return false; + return true; +} + +void SystemMemoryReset(memory_arena_t& arena) { + arena.allocationCount = 0; + arena.used = 0; +} + +INTERNAL inline void SystemMemoryDebugTouch(memory_arena_t& arena, uint8* address) { + ASSUME(address >= arena.baseAddress, "Attempted to access an invalid arena offset"); + size_t offset = address - (uint8*)arena.baseAddress; + // TODO: Update last accessed time +} \ No newline at end of file diff --git a/Core/Platforms/Win32/Memory.cpp b/Core/Platforms/Win32/Memory.cpp index 3d8fe490..b5fbed79 100644 --- a/Core/Platforms/Win32/Memory.cpp +++ b/Core/Platforms/Win32/Memory.cpp @@ -22,33 +22,6 @@ INTERNAL void PlatformInitializeMemoryArena(memory_arena_t& arena, allocation_op if(options.allocationType & MEM_COMMIT) arena.committedSize = options.reservedSize; } -INTERNAL void* SystemMemoryAllocate(memory_arena_t& arena, size_t allocationSize) { - size_t totalUsed = arena.used + allocationSize; - ASSUME(totalUsed <= arena.reservedSize, "Attempting to allocate outside the reserved set"); - - void* memoryRegionStartPointer = (uint8*)arena.baseAddress + arena.used; - arena.used = totalUsed; - arena.allocationCount++; - - return memoryRegionStartPointer; -} - -INTERNAL bool SystemMemoryCanAllocate(memory_arena_t& arena, size_t allocationSize) { - if(arena.used + allocationSize > arena.reservedSize) return false; - return true; -} - -void SystemMemoryReset(memory_arena_t& arena) { - arena.allocationCount = 0; - arena.used = 0; -} - -INTERNAL inline void SystemMemoryDebugTouch(memory_arena_t& arena, uint8* address) { - ASSUME(address >= arena.baseAddress, "Attempted to access an invalid arena offset"); - size_t offset = address - (uint8*)arena.baseAddress; - // TODO: Update last accessed time -} - INTERNAL inline void PlatformInitializeProgramMemory(program_memory_t& programMemory, memory_config_t& configOptions) { PlatformInitializeMemoryArena(programMemory.persistentMemory, configOptions.persistentMemoryOptions); PlatformInitializeMemoryArena(programMemory.transientMemory, configOptions.transientMemoryOptions); diff --git a/Core/RagLite2.cpp b/Core/RagLite2.cpp index 7bdd4dca..a2a74ec2 100644 --- a/Core/RagLite2.cpp +++ b/Core/RagLite2.cpp @@ -217,6 +217,17 @@ EXPORT void SimulateNextFrame(program_memory_t* memory, program_input_t* inputs, DebugDrawUpdateBackgroundPattern(worldState, inputs); DebugDrawIntoFrameBuffer(worldState, inputs, outputs); + // NOTE: Access to the memory arena APIs should be platform-agnostic (no OS interaction required, just pointer math) + memory->persistentMemory.used += sizeof(worldState); // Avoid overwriting the actual program state (temporary hack) + size_t allocationSize = Megabytes(2); + if(!SystemMemoryCanAllocate(memory->persistentMemory, 2 * allocationSize)) { + SystemMemoryReset(memory->persistentMemory); + } else { + uint8* address = (uint8*)SystemMemoryAllocate(memory->persistentMemory, 2 * allocationSize); + *address = 0xAB; + SystemMemoryDebugTouch(memory->persistentMemory, address); + } + // NYI: Push draw commands to the platform's render queue } #else