brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
platform-abstractionExpert platform abstraction layers for game engines — OS abstraction, filesystem, threads, windowing, input, timers, dynamic loading, and platform-conditional code across Windows/Linux/console.
Independent GitHub snapshot · Automated classification · Original documentation governs
The PAL (Platform Abstraction Layer) is the layer that lets one engine codebase run on Windows, Linux, macOS, and every console generation. If it's leaky, every feature becomes a platform #ifdef. If it's designed well, 95% of engine code is pure, portable C++.
| Concern | Platform-specific | Engine API |
|---|---|---|
| Memory | VirtualAlloc / mmap / heap | VirtualAlloc, Memory::Reserve |
| Threads | CreateThread / pthread / fiber | Thread, JobSystem handles |
| Filesystem | CreateFile / open | FileSystem::Open, paths {Platform.VirtualPath} |
| Time | QueryPerformanceCounter / clock_gettime | Time::Now(), Time::Delta() |
| Windowing | Win32 / SDL / GLFW | Window, InputEvent |
| Input | RawInput / XInput / hid | InputDevice, ActionMap |
| Dynamic loading | LoadLibrary / dlopen | Module::Load |
| Console slots | device-specific | Console::WaitForDebugger |
| Render RHI | D3D12 / Vulkan / Metal | RHIDevice (see vulkan skill) |
| Networking | winsock / BSD sockets | NetworkProtocol (see netcode skill) |
Rule: every platform-only symbol lives behind an interface; portals are forbidden (#ifdef WIN32 inside gameplay code).
struct PAL {
// Memory
virtual MemoryPage* Reserve(uint64_t bytes) = 0;
virtual void Commit(void* p, uint64_t bytes) = 0;
// Threads
virtual Thread* CreateThread(ThreadFn, void*, size_t stack) = 0;
virtual void Sleep(uint32_t ms) = 0;
virtual uint32_t HardwareThreadCount() = 0;
// Files
virtual FileHandle* Open(const Path&, FileMode) = 0;
virtual void ReadAsync(FileHandle*, uint8_t*, size_t, IoCallback) = 0;
// Time
virtual TimePoint Now() = 0;
virtual double PeriodSeconds() = 0;
// Misc
virtual uint32_t ProcessId() = 0;
virtual void* LoadModule(const Path&) = 0;
virtual void Exit(int code) = 0;
};
extern PAL* g_platform; // set once at startup to the platform implementation
Debug-build placeholder: a NullPAL that asserts on unsupported calls keeps unsupported code from silently running.
PlatformWindows.cpp — Win32 + DirectXMath conveniences.PlatformPosix.cpp — pthread, open, clock_gettime(CLOCK_MONOTONIC_RAW).If a feature isn't available (e.g., energy-perf mode, large pages on older Windows), the PAL returns "unsupported" and the engine falls back — no hard crash. Platform::Capabilities struct at init reports feature flags (huge pages, GPU async, RTX, max threads, etc.).
The Path type has:
{GameData}/levels/Zone1/lvl.map — portable, artifact-independent.{GameData} -> D:\...\Packaged\Game\Data).Path p = Platform::ResolveVirtual("{GameData}/shaders/lighting.hlsl");
{EngineRoot} -> engine-source-tree
{GameData} -> <install>/GameData
{SaveFiles} -> platform writable dir (AppData / xdg-data-home / console save)
{Temp} -> sphere-scoped scratch
Save dir differs per platform — the PAL owns the resolution. All asset loading goes through the mount table (no raw D:\ paths in assets).
See virtual-memory.md and asset-pipeline.md. Crude: ReadFile, fopen. Production: async I/O + memory mapping for big read-only assets; the PAL exposes both.
QueryPerformanceCounter (QPC), divisor = frequency.clock_gettime(CLOCK_MONOTONIC_RAW) (unaffected by NTP jumps).struct TimePoint { uint64_t ticks; };
static TimePoint Now() { return { static_cast<uint64_t>(g_qpc) }; }
dt, and the engine's accumulator converts to fixed-step sim (see game-loop-and-timestep.md).PAL threads wrap CreateThread/std::thread with generous split:
Thread = OS thread handle + id + created name (for the debugger).JobSystem (see its skill) uses PAL threads underneath.Thread* t = Platform::CreateThread(bind(&MySystem::Run), this, 256 * 1024);
Platform::CreateFiber, SwitchToFiber — the PAL isolates the platform fiber API so switch cost stays cheap. (See fibers-and-async.md.)
Platform::AtomicIncrement, InterlockedCompareExchange, YieldProcessor, WaitOnAddress, WaitForSingleObject. Wrap so the engine never touches platform intrinsics directly.
Raw device → engine input:
struct InputRawFrame {
float leftStickX, leftStickY, rightStickX, rightStickY;
float triggers[2]; bool buttons[14];
// per player: controller ID
};
The PAL enqueues a raw frame per input device per frame; the engine's input system (see client-engine/input-systems.md) maps actions onto it.
The PAL owns window creation (or wraps SDL/GLFW). Gameplay code must NOT see Win32 WM_ messages. Convert to engine events: WindowEvent::Closed, InputEvent::KeyDown(KeyCode::W), AppEvent::Focus, DropFileEvent.
PAL owns: window resize (render resizes the RHI swapchain), minimize (frame skip), focus change (pause), and the app-level quit.
void* h = Platform::LoadModule("{Engine}/devmods/buddha-bot");
auto fn = (CreateDevModFn)Platform::GetProcAddress(h, "CreateDevMod");
Used for: dev mods, platform-specific render modules, tool builds, and the game DLL (hot-reload of gameplay). The hot-reload pipeline reloads the module, re-wires entry points, and migrates state (see asset-pipeline.md).
while(!IsDebuggerAttached()) Sleep(1) so a debugger can attach before crash.SetUnhandledExceptionFilter) → writes a minidump + logs the callstack + hook to telemetry.Platform::GetMemoryUsage() for the memory dashboard.Platform::GetCommandLine, GetArguments.Acceptable #ifdefs (in the PAL and its consumers):
PLATFORM_WINDOWS, PLATFORM_POSIX, PLATFORM_CONSOLE_*.BUILD_DEBUG, BUILD_SHIPPING.FEATURE_HUGE_PAGES, FEATURE_ASAN.Forbidden: CPU #ifdefs deep in gameplay; #ifdef _WIN32 touching window or file code outside the PAL; #ifndef as feature gates.
Keeping the engine's gameplay code #ifdef-free is the goal; every platform symbol in gameplay is a code smell.
#ifdefs confined to the PAL + feature flags.references/os-interface.md — PAL interface, capabilities, platform detection, error handlingreferences/filesystem.md — mount table, virtual paths, async I/O, mmap, save/loadreferences/threading.md — thread/atomic/fiber wrappers, worker setup, priorityreferences/windowing.md — window creation, events, resize/focus, multi-windowreferences/input-devices.md — raw input, gamepads, keyboard/mouse, hid, mapping to engine eventsreferences/modules-and-tools.md — dynamic loading, hot reload, crash handling, dev-tool integration