Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions Core/Memory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
typedef struct virtual_memory_arena {
// 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;

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;

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
}
29 changes: 29 additions & 0 deletions Core/Modules.hpp
Original file line number Diff line number Diff line change
@@ -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);
78 changes: 42 additions & 36 deletions Core/Platforms/Win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@

#define TODO(msg) OutputDebugStringA(msg);

// TODO: Replace these with the actual game/application state later
typedef struct volatile_game_state {
int32 offsetX;
int32 offsetY;
} game_state_t;
GLOBAL game_state_t PLACEHOLDER_DEMO_APP = {
.offsetX = 0,
.offsetY = 0,
};

constexpr size_t MAX_ERROR_MSG_SIZE = 512;
GLOBAL TCHAR SYSTEM_ERROR_MESSAGE[MAX_ERROR_MSG_SIZE];

Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -128,7 +117,8 @@ INTERNAL void MainWindowRedrawEverything(HWND& window) {
}

hardware_tick_t before = PerformanceMetricsNow();
DebugDrawIntoFrameBuffer(GDI_BACKBUFFER, PLACEHOLDER_DEMO_APP.offsetX, PLACEHOLDER_DEMO_APP.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();
Expand Down Expand Up @@ -203,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;

Expand Down Expand Up @@ -323,10 +313,16 @@ 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 = 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...
Expand Down Expand Up @@ -389,32 +385,42 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR,

hardware_tick_t before = PerformanceMetricsNow();
if(!APPLICATION_SHOULD_PAUSE) {
// 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");
}

// NOTE: Application/game state updates should go here (later)
PLACEHOLDER_DEMO_APP.offsetX++;
PLACEHOLDER_DEMO_APP.offsetY++;
PLACEHOLDER_DEMO_APP.offsetY++;
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,
}
};

size_t allocationSize = Megabytes(2);
if(!SystemMemoryCanAllocate(MAIN_MEMORY, allocationSize)) {
SystemMemoryReset(MAIN_MEMORY);
} else {
uint8* mainMemory = (uint8*)SystemMemoryAllocate(MAIN_MEMORY, allocationSize);
*mainMemory = 0xDE;
SystemMemoryDebugTouch(MAIN_MEMORY, mainMemory);
}
ASSUME(game.SimulateNextFrame, "Failed to load program module (cannot advance the simulation)");
if(game.SimulateNextFrame) game.SimulateNextFrame(&PLACEHOLDER_PROGRAM_MEMORY, &inputs, &outputs);

if(!SystemMemoryCanAllocate(TRANSIENT_MEMORY, 2 * allocationSize)) {
SystemMemoryReset(TRANSIENT_MEMORY);
size_t allocationSize = Megabytes(2);
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);
DebugDrawUpdateBackgroundPattern();
}
CPU_PERFORMANCE_METRICS.worldUpdateTime = PerformanceMetricsGetTimeSince(before);

Expand Down
44 changes: 43 additions & 1 deletion Core/Platforms/Win32.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,46 @@
#include <psapi.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <timeapi.h>
#include <timeapi.h>

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;
}
}
Loading