Skip to content

Fix/widget framerate drag - #26

Merged
BuddhaCodes merged 8 commits into
masterfrom
fix/widget-framerate-drag
Nov 5, 2026
Merged

BuddhaCodes merged 8 commits into
masterfrom
fix/widget-framerate-drag

Conversation

@BuddhaCodes

Copy link
Copy Markdown
Owner

No description provided.

BuddhaCodes and others added 8 commits November 2, 2026 19:44
- Standalone sketch windows (exports, the separate-window run, widgets,
  SketchApp) no longer record rewind history: every frame was being
  copied and compressed in the background (PNG for see-through
  widgets), roughly halving the frame rate and growing memory until it
  was trimmed, then again.
- Dragging moves the window by hand instead of BeginMoveDrag(): on
  Windows the system's move loop stopped the sketch until release.
  WindowX/WindowY now follow the drag smoothly.
- Widgets on Windows opt out of power throttling (EcoQoS and coarse
  timers for windows not in front) and use 1 ms timers while open.
Frames are paced by a timer; at Windows' default 15.6 ms resolution 60 fps
becomes ~32 and uneven, and it only looked smooth while another app (a
video, music) raised the resolution system-wide.
The canvas advanced frames from a DispatcherTimer, which on Windows is
WM_TIMER: the lowest-priority message, delivered only when the queue is
empty and coalesced while the process looks idle. Dragging a widget (a
flood of mouse and move messages) starved it until release, and a
widget nobody clicks got late ticks -- smooth only while music kept the
process awake.

On screen, frames now follow Avalonia's animation frames (the
compositor's clock, render priority, above input). Each refresh runs the
sketch's frame when it's due on a fixed schedule, so the average is the
sketch's frame rate on any refresh rate (60 fps on 144 Hz, not 48). The
timer still runs hidden frames and restarts the loop after a pause.
- Widgets supersample to match the screen (1x at 100%, 2x at 125-200%)
  instead of the canvas's default 2x: on a 100% screen that painted four
  times the pixels, and the audio widget's soft glows made it the whole
  frame budget (about 25 fps instead of 60).
- While dragging, only the latest target position is applied, once per
  display refresh: a mouse reports up to 1000 moves a second and moving
  a (see-through) window each time starved the frames.
A file named dana.trace next to the program (or DANA_FRAME_TRACE=1)
logs, every second, to dana-trace.log beside it: frames, Draw() and blit
times, the largest gap between frames, display-loop and timer ticks,
window moves, garbage collections, CPU and memory; and once, whether
Skia renders on the GPU or in software, the transparency the system
granted, screen scaling and supersampling.
On Windows Avalonia renders when a System.Threading.Timer ticks every
16 ms, as precise as the process's timer resolution -- which Windows
keeps fine for the app in front and coarsens for the rest. A widget ran
smoothly while it was the active window and stuttered as soon as another
window was clicked.

RenderClock replaces that timer in Avalonia's render loop: its own thread
above normal priority, waiting on a high-resolution waitable timer and
ticking on DWM's vblank (the clock attached sketches use). IRenderTimer is
hidden from compilation, so it's implemented with a DispatchProxy and put
in by reflection; anything unexpected leaves Avalonia's timer as it is.
DANA_RENDER_CLOCK=0 turns it off, =1 forces it (testing).
Moving the widget between monitors changes its supersampling, which
replaces the canvas's offscreen surface; the sketch wasn't rebound and
kept drawing into the disposed canvas, crashing the process in native
code. The same could happen in the IDE when it drops supersampling while
you type. The surface swap now always rebinds the sketch.
@BuddhaCodes
BuddhaCodes merged commit a98bbb4 into master Nov 5, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant