From 86533ae683e06627066e9d4ea1d3c9ede5a99784 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 12 Jul 2019 15:31:29 +0200 Subject: [PATCH] ui/input/system: introduce package for system events And add ProfileOp and ProfileEvent for registering and receiving profile data. Remove the Profiling field and Timings method from app.Window. Signed-off-by: Elias Naur --- ui/app/internal/input/router.go | 20 ++++++++++++++++ ui/app/window.go | 15 ++++-------- ui/input/system/system.go | 41 +++++++++++++++++++++++++++++++++ ui/internal/ops/ops.go | 5 +++- 4 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 ui/input/system/system.go diff --git a/ui/app/internal/input/router.go b/ui/app/internal/input/router.go index 4520fc9d..77c3ad12 100644 --- a/ui/app/internal/input/router.go +++ b/ui/app/internal/input/router.go @@ -7,6 +7,7 @@ import ( "gioui.org/ui" "gioui.org/ui/input" + "gioui.org/ui/input/system" "gioui.org/ui/internal/ops" "gioui.org/ui/key" "gioui.org/ui/pointer" @@ -21,9 +22,13 @@ type Router struct { handlers handlerEvents reader ui.OpsReader + // InvalidateOp summary. redraw bool redrawTime time.Time + + // ProfileOp summary. + profHandlers []input.Key } type handlerEvents struct { @@ -38,6 +43,7 @@ func (q *Router) Events(k input.Key) []input.Event { func (q *Router) Frame(ops *ui.Ops) { q.handlers.Clear() q.redraw = false + q.profHandlers = q.profHandlers[:0] q.reader.Reset(ops) q.collect() @@ -69,10 +75,24 @@ func (q *Router) collect() { q.redraw = true q.redrawTime = op.At } + case ops.TypeProfile: + var op system.ProfileOp + op.Decode(encOp.Data, encOp.Refs) + q.profHandlers = append(q.profHandlers, op.Key) } } } +func (q *Router) AddProfile(e system.ProfileEvent) { + for _, h := range q.profHandlers { + q.handlers.Add(h, e) + } +} + +func (q *Router) Profiling() bool { + return len(q.profHandlers) > 0 +} + func (q *Router) RedrawTime() (time.Time, bool) { return q.redrawTime, q.redraw } diff --git a/ui/app/window.go b/ui/app/window.go index 40fa883f..6b7d50b9 100644 --- a/ui/app/window.go +++ b/ui/app/window.go @@ -13,6 +13,7 @@ import ( "gioui.org/ui/app/internal/gpu" iinput "gioui.org/ui/app/internal/input" "gioui.org/ui/input" + "gioui.org/ui/input/system" "gioui.org/ui/key" ) @@ -23,13 +24,10 @@ type WindowOptions struct { } type Window struct { - Profiling bool - driver *window lastFrame time.Time drawStart time.Time gpu *gpu.GPU - timings string inputState key.TextInputState err error @@ -74,10 +72,6 @@ func (w *Window) Events() <-chan Event { return w.events } -func (w *Window) Timings() string { - return w.timings -} - func (w *Window) setTextInput(s key.TextInputState) { if s != w.inputState && (s == key.TextInputClose || s == key.TextInputOpen) { w.driver.setTextInput(s) @@ -134,7 +128,7 @@ func (w *Window) Draw(root *ui.Ops) { return } } - w.gpu.Draw(w.Profiling, size, root) + w.gpu.Draw(w.router.Profiling(), size, root) w.router.Frame(root) now := time.Now() w.mu.Lock() @@ -142,9 +136,10 @@ func (w *Window) Draw(root *ui.Ops) { frameDur := now.Sub(w.lastFrame) frameDur = frameDur.Truncate(100 * time.Microsecond) w.lastFrame = now - if w.Profiling { + if w.router.Profiling() { q := 100 * time.Microsecond - w.timings = fmt.Sprintf("tot:%7s cpu:%7s %s", frameDur.Round(q), drawDur.Round(q), w.gpu.Timings()) + timings := fmt.Sprintf("tot:%7s cpu:%7s %s", frameDur.Round(q), drawDur.Round(q), w.gpu.Timings()) + w.router.AddProfile(system.ProfileEvent{Timings: timings}) w.setNextFrame(time.Time{}) } if t, ok := w.router.RedrawTime(); ok { diff --git a/ui/input/system/system.go b/ui/input/system/system.go new file mode 100644 index 00000000..3ca5485c --- /dev/null +++ b/ui/input/system/system.go @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +// Package system contain ops and types for +// system events. +package system + +import ( + "gioui.org/ui" + "gioui.org/ui/input" + "gioui.org/ui/internal/ops" +) + +// ProfileOp registers a handler for receiving +// ProfileEvents. +type ProfileOp struct { + Key input.Key +} + +// ProfileEvent contain profile data from a single +// rendered frame. +type ProfileEvent struct { + // String with timings. Very likely to change. + Timings string +} + +func (p ProfileOp) Add(o *ui.Ops) { + data := make([]byte, ops.TypeProfileLen) + data[0] = byte(ops.TypeProfile) + o.Write(data, p.Key) +} + +func (p *ProfileOp) Decode(d []byte, refs []interface{}) { + if ops.OpType(d[0]) != ops.TypeProfile { + panic("invalid op") + } + *p = ProfileOp{ + Key: refs[0].(input.Key), + } +} + +func (p ProfileEvent) ImplementsInputEvent() {} diff --git a/ui/internal/ops/ops.go b/ui/internal/ops/ops.go index 4366d7a6..6e577213 100644 --- a/ui/internal/ops/ops.go +++ b/ui/internal/ops/ops.go @@ -23,6 +23,7 @@ const ( TypePop TypeAux TypeClip + TypeProfile ) const ( @@ -43,6 +44,7 @@ const ( TypePopLen = 1 TypeAuxLen = 1 + 4 TypeClipLen = 1 + 4*4 + TypeProfileLen = 1 ) func (t OpType) Size() int { @@ -64,12 +66,13 @@ func (t OpType) Size() int { TypePopLen, TypeAuxLen, TypeClipLen, + TypeProfileLen, }[t-firstOpIndex] } func (t OpType) NumRefs() int { switch t { - case TypeBlock, TypeImage, TypeKeyHandler, TypePointerHandler: + case TypeBlock, TypeImage, TypeKeyHandler, TypePointerHandler, TypeProfile: return 1 default: return 0