From 759b7962838e78d171ce24b9fef10f4cb9c74c8c Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 8 Jan 2021 20:05:21 +0100 Subject: [PATCH] app: treat Invalidate more like InvalidateOp Using Window.Invalidate for animation with, say var w Window var e FrameEvent w.Invalidate() e.Frame(...) stops and immediately starts animation mode which is inefficient and may cause jitter in the redraw timing. InvalidateOp is the efficient and sure way to achieve smooth animation, and Invalidate only exists for external events where there is nowhere to add an InvalidateOp. We can do better, so this change makes Invalidate almost as efficient as InvalidateOp by checking for Invalidates at the same time we check for InvalidateOps. Note that we can't avoid the inefficiency in all cases, for example when the calls above are swapped, e.Frame(...) w.Invalidate() the Invalidate may not be registered before the check during Frame. While here, add a note to Invalidate that it's meant for externally triggered redraws. Signed-off-by: Elias Naur --- app/window.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/app/window.go b/app/window.go index 641e1441..8700aae0 100644 --- a/app/window.go +++ b/app/window.go @@ -185,14 +185,25 @@ func (w *Window) processFrame(frameStart time.Time, size image.Point, frame *op. if t, ok := w.queue.q.WakeupTime(); ok { w.setNextFrame(t) } + // Opportunistically check whether Invalidate has been called, to avoid + // stopping and starting animation mode. + select { + case <-w.invalidates: + w.setNextFrame(time.Time{}) + default: + } w.updateAnimation() // Wait for the GPU goroutine to finish processing frame. <-sync } -// Invalidate the window such that a FrameEvent will be generated -// immediately. If the window is inactive, the event is sent when the -// window becomes active. +// Invalidate the window such that a FrameEvent will be generated immediately. +// If the window is inactive, the event is sent when the window becomes active. +// +// Note that Invalidate is intended for externally triggered updates, such as a +// response from a network request. InvalidateOp is more efficient for animation +// and similar internal updates. +// // Invalidate is safe for concurrent use. func (w *Window) Invalidate() { select {