Each ETC2 upload created and destroyed its own staging buffer on the render
thread. Uploads now take ranges of 16 MiB blocks, reused once every range
is released; four empty blocks are kept. Profile traces gain per-frame CPU
time counters and slices for staging and driver memory calls.
Uploads decode on a background dispatcher and the submit carries a
timeline semaphore wait, so the GPU waits for the texture rather than
the render thread. The gather of the application's compressed bytes
moves there too when they are already mapped; unmapping or freeing that
memory drains the decodes still reading it.
Staged copies gain an explicit host-write barrier. A queue submission
only makes host writes from before it visible to the device, and these
writes land after the submit.
Devices without timelineSemaphore, and submits whose pNext already sizes
arrays by their semaphore counts, decode inline as before.
Blade Ball, median of three: worst vkQueueSubmit 140ms -> 1ms, p99
4.9ms -> 0.05ms, total 2534ms -> 309ms. Frame interval unchanged; its
tail is the engine's own main-thread step.
Default title is Roblox, details "Playing {place_name}", and state
"by {creator_name}". The creator comes from the games API response
already fetched for the place name. A text field that expands an
empty placeholder is left out, so the state never shows a bare "by".
Release the GameMode request when the daemon narrows the CPU mask; the pin
concentrates Roblox's worker pool and is re-applied every few seconds, so
ending the request is the only thing that lifts it. `gamemode: on` keeps it.
Emit texture uploads on worker threads instead of serially inside
vkQueueSubmit, in two passes so mip 0 lands before the levels scaled from it.
Decode ETC2 through a persistent pool and lower the parallel floor to one
128x128 image, so small batches stop running single-threaded.
Document all three in docs/PERFORMANCE.md.
Records presents, GPU waits, submits, ETC2 decode, and pipeline and shader creation for ui.perfetto.dev. Adds a benchmark guide and a trace summary script.
text.title sets the activity name, images.* set the large and small icons and hover text, and text.state may be empty to hide it. Text and image fields expand {place_name} and {place_icon}; fields that render empty are omitted. show_place_name: false now also hides the place thumbnail.
Discord Rich Presence item 1 is custom presence fields; the private-server
join item is dropped. The profiling item names the Chrome trace format
instead of Perfetto.
Item 2 covered hot-plug and input release on disconnect, which already
work, so it is now only the button glyph gap. Raw mouse and the pointer
fix move to Shipped.
Drops the BCH donation address from the README.