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 <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-01-08 20:05:21 +01:00
parent 5f6fa25209
commit 759b796283
+14 -3
View File
@@ -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 {