Fix CPU spike when mouse is inside window and stationary - #2972
Conversation
Troubleshooting: - Profiled the TIC-80 main thread under different mouse states and observed that active CPU usage spikes from ~2% (outside window) to ~11% (inside window, stationary). - Verified that frame rate remains a steady 38 FPS in both states. - Traced the C draw cache validation (draw_cache.c) and discovered that match_a (RAM block A, containing VRAM/tiles/map) was failing on every single frame when the mouse was inside. - Instrumented the C block comparison to log the first differing offset. Found that offset 16379 (0x3FFB) was changing on every frame. This offset corresponds to vars.cursor.sprite in VRAM. - Traced the lifecycle of vars.cursor: 1. At the start of every frame, processMouseStates resets it to the default arrow cursor. 2. During the frame update, the active editor processes mouse hover and sets it back to a custom cursor (like ibeam or hand). 3. This reset-and-override loop ran on every single frame, modifying RAM and invalidating the draw cache. Fix: - Added a mouse.cursor state tracking structure to the Studio definition in studio.c to decouple cursor state updates from direct VRAM/RAM writes. - Modified processMouseStates and setCursor to update the Studio state rather than modifying RAM directly. - Implemented cursor state synchronization in renderStudio right before tic_core_tick_end, only writing the cursor sprite to RAM if it has actually changed since the last frame. - This prevents VRAM modifications on stationary mouse frames, allowing the draw cache to hit and reducing main thread active tick game CPU usage by over 25x.
Please explain how this relates to the draw cache exactly - and what the cost here is with no draw cache. Most games redraw every single frame, so I'm confused why copying a few bytes of memory multiple times would have any real cost at all... |
In every frame, draw cache memcpy memory at The issue with previous cod is, draw cache will always get invalidated in studio, due to the latter set it to an non-final value during
I explained in the description: The fix will have no effect without the Draw Cache PR.
games are not affected by this kind of issue, as they strictly redraw during TIC(), which is between
This has huge cost when using the studio in low power devices such as iPhones or iPads. Say when you carry your mobile device during a travel and want to develop a game on the go, you will have 10-25X difference on battery drain in the code/music/sprite editing mode. Without this patch, editor just runs like a 60fps action game. With this patch applied, it only do redraw then cursor blinks. |
Yeah, I think that's one of the issues I was having - just trying to understand it from reading the patch in isolation. Stiill confused if there is a comparison (and from loop to loop the mouse VRAM isn't truly changing then that comparison should match and therefore it shouldn't be redrawn in the first place)? |
previous loop current loop the difference between the two is, we now have all status change happening within tic_core_tick_start/end |
Troubleshooting:
Fix:
Note: