all: serialize ops

Pros:
- Much less per-frame garbage
- Allow future preprocessing of ops while building it
- Much fewer interface calls and pointer chasing
- Allow future serialization of ops for remote rendering

Cons:
- Slightly clumsier API

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-04-24 13:33:01 +02:00
parent 7b6e1ce35a
commit 252e058766
21 changed files with 809 additions and 385 deletions
+27 -28
View File
@@ -11,6 +11,7 @@ import (
"gioui.org/ui"
"gioui.org/ui/app/internal/gpu"
"gioui.org/ui/internal/ops"
"gioui.org/ui/key"
"gioui.org/ui/pointer"
)
@@ -41,6 +42,8 @@ type Window struct {
hasNextFrame bool
nextFrame time.Time
delayedDraw *time.Timer
reader ops.Reader
}
// driver is the interface for the platform implementation
@@ -89,7 +92,7 @@ func (w *Window) Err() error {
return w.err
}
func (w *Window) Draw(root ui.Op) {
func (w *Window) Draw(root *ui.Ops) {
if !w.IsAlive() {
return
}
@@ -132,13 +135,35 @@ func (w *Window) Draw(root ui.Op) {
w.timings = fmt.Sprintf("t:%7s %s", frameDur, w.gpu.Timings())
w.setNextFrame(time.Time{})
}
if t, ok := collectRedraws(root); ok {
w.reader.Reset(root.Data(), root.Refs())
if t, ok := collectRedraws(&w.reader); ok {
w.setNextFrame(t)
}
w.updateAnimation()
w.gpu.Draw(w.Profiling, size, root)
}
func collectRedraws(r *ops.Reader) (time.Time, bool) {
var t time.Time
redraw := false
for {
data, ok := r.Decode()
if !ok {
break
}
switch ops.OpType(data[0]) {
case ops.TypeRedraw:
var op ui.OpRedraw
op.Decode(data)
if !redraw || op.At.Before(t) {
redraw = true
t = op.At
}
}
}
return t, redraw
}
func (w *Window) Redraw() {
if !w.IsAlive() {
return
@@ -256,29 +281,3 @@ func (w *Window) event(e Event) {
close(w.events)
}
}
func collectRedraws(op ui.Op) (time.Time, bool) {
type childOp interface {
ChildOp() ui.Op
}
switch op := op.(type) {
case ui.Ops:
var earliest time.Time
var valid bool
for _, op := range op {
if t, ok := collectRedraws(op); ok {
if !valid || t.Before(earliest) {
valid = true
earliest = t
}
}
}
return earliest, valid
case ui.OpRedraw:
return op.At, true
case childOp:
return collectRedraws(op.ChildOp())
default:
return time.Time{}, false
}
}