Performance & Zero Copy Assets
been spending some time under the hood…
this one’s almost entirely backend. no new features, mostly went through the render thread, asset pipeline, & a handful of ECS loops to squeeze out more performance.
it was incredibly rage inducing at times.. but seeing the profiler diff against baseline.. i am satisfied.. almost at peace.. but was considering becoming a farmer & never touching a computer again.. mostly because i thought i’d messed up more than i did.. but.. im happy now.
changes
threading & ecs
i’ve reinvented the wheel enough already… but had to redo how tasks are dispatched.
-
ThreadPoolused to take astd::function, which heap allocates if you capture more than a couple pointers. scripts dispatch through this every frame, so it added up. swapped it for a customTasktype a 56-byte inline buffer, no heap allocs - swapped the pending-task counter to a lock free atomic decrement instead of a mutex on every completion…
rendering
been cleaning up how the main thread interacts with the render thread.
- the main & render threads used to awkwardly poll eachothers framebuffers. now theres a
m_ReadyFramesdeque main pushes a frame index, render pops it. much cleaner :) - ImGui draw data is now reused in-place instead of allocating & freeing a fresh clone every frame
(ive put off fixing that hack for a while so its nice to finally come around to it).
- instanced draws no longer store a
vector<mat4>per draw call, transforms get appended into one giant staging buffer per frame now. addedSubmitPersistentfor things that already own a long-lived buffer (like the map tile renderer) to skip the copy entirely. - swapped a bunch of
unordered_maps for flat vectors in the texture/VAO/uniform caches for a handful of items, linear scan beats hashing. batched rendering also caches the last bound texture & color uniform so b2b batches sharing a texture dont rebind needlessly. - added a zero-size window safeguard for Wayland so it stops wrecking the renderer when the window briefly reports 0x0 during resize (also turned vsync back on, weird syscall spam otherwise)
assets & packaging
- added
VFS::ReadVirtualViewto hand outstring_views directly into memory instead of owned strings - for packaged builds,
ContainerReadernowmmaps the.obpakfile directly, uncompressed stuff (textures, uncompiled maps) gets handed right to the parser without a copy. also now move only, with a destructor that unmaps memory instead of holding a copied vector of chars
scripting
- the script hot-reloader was doing a
stat()syscall on every script file every frame. oops. now polls every 300 frames & caches resolved paths.. thought i already debounced this.. guess not.. - the
on_update&on_destroywork buckets used to be freshly allocated vectors every frame… nowstatic, so they just clear & reuse capacity
editor & ui
- finally ripped out the old in game debug UI (
GameUI.cpp), it had fallen out of sync with the ECS anyway
(used it for debug visuals while implementing the first version of the ecs.. then forgot about it) the editors inspector does all of this better now, so replaced it with a minimal FPS counter
audio & map
- audio engine now sets an explicit period size (2048 frames) via miniaudio to cut IPC roundtrips to the audio daemon..
(this one was annoying to figure out.. god bless strace & gdb)
- the map’s visible transforms buffer is now double buffered, rebuilds write to the back buffer while the render thread reads the front, no race conditions. also swapped
typeMatsfrom anunordered_mapto a flat vector
nothing user facing changed this time, but frame pacing feels noticeably smoother (somewhat suprised), & the packaged build starts noticeably faster
i know it could probably be a lot better, but im still a bit of a noob at C++, so this is one hell of a learning project
Comments 1
also sorry for weird aah wording.. the character limit was raging at me
Sign in to join the conversation.