fix: accurate frame elision and draw performance - #110
Conversation
|
I should credit @hkf57 in #108 for making me look at render performance and correctness. It also addresses uninitialised padding via tight struct packing; noting that accesses were already unaligned due to allocating commands immediately adjacent to each other. I also considered incremental hashing as the commands were being produced to amortise the cost but it's tricky to tell when a command is fully written with the current borrowed pointers, so a one-shot hash in EndFrame before rendering starts is quick enough. We already blocked on the async hash computation so I removed all the scaffolding for querying it between layers and instead decide immediately; saving GPU clearing/drawing effort. |
18e245e to
0dc718f
Compare
We always resolve the command buffer hash before drawing any layers so there is no need for mid-draw bail logic. Replaced MurmurHash64A with xxHash's way faster XXH3 for command buffer hashing. Only consider textures used for layer geometry when determining frame completeness for elision. Command buffer command structs are now packed on 1-byte alignment and the command key has shrunk from int to u8. Getting rid of padding isn't crucial as subsequent identical frames should both touch the padding bytes in similar ways, but it's nice.
Cross-thread communication has previously been achieved by polling state and sleeping for a millisecond between attempts. This leads to a steady stream of worker threads being woken and scheduled unnecessarily. As the sleeps are not part of any form of intelligent wait, they also delay processing of work by up to a millisecond which for the console window has implications on the latency of window messages. For non-window threads, this is now generally replaced by efficient and responsive waiting on condition variables. For the console thread as that hosts a window, it uses Win32 events and `MsgWaitForMultipleObjects` to be responsive both to shutdown requests and message processing.
This change adds in-process use of the Superluminal Profiler API to instrument function scopes like texture and module loading to annotate profiles with the file paths being processed.
MSVC nags when building `base64.c` as we used diacritics in comments. Those were unnecessary and have been rephrased.
0dc718f to
ac79468
Compare
This system spun up a polling thread even when not in active use. It has rotted over time and does not currently function, crashing immediately when enabled.
Variables from finding Superluminal were used before they were populated, causing inconsistencies between clean and incremental builds. Protect against use of null shader objects when querying image sizes.
Hold textures with shared_ptr throughout the async loading process to ensure that they don't go out of scope. Handles have strong references while the renderer only has weak ones to share currently loaded textures on demand. As this can lead to textures unloading during simulation, render layers now keep a set of strong texture pointers referenced in a frame to keep them alive for the duration. Fonts now asynchronously load the image contents and wait for the size to be known to be able to precompute the atlas coordinates.
We always resolve the command buffer hash before drawing any layers so there is no need for mid-draw bail logic.
Replaced MurmurHash64A with xxHash's way faster XXH3 for command buffer hashing.
Only consider textures used for layer geometry when determining frame completeness for elision.
Command buffer command structs are now packed on 1-byte alignment and the command key has shrunk from int to u8. Getting rid of padding isn't crucial as subsequent identical frames should both touch the padding bytes in similar ways, but it's nice.