app,app/internal/gpu: split render loop from GPU

The policy of rendering on a separate goroutine is separate from
the actual rendering. Reflect that by introducing the RenderLoop
type for driving a GPU from a separate goroutine.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-11-29 19:42:29 +01:00
parent 8cec7d1a40
commit 5fa3dbc70d
4 changed files with 255 additions and 205 deletions
+19 -20
View File
@@ -9,7 +9,6 @@ import (
"time"
"gioui.org/app/internal/gl"
"gioui.org/app/internal/gpu"
"gioui.org/app/internal/input"
"gioui.org/app/internal/window"
"gioui.org/io/event"
@@ -27,7 +26,7 @@ type Option func(opts *window.Options)
// Window represents an operating system window.
type Window struct {
driver window.Driver
gpu *gpu.GPU
loop *renderLoop
// driverFuncs is a channel of functions to run when
// the Window has a valid driver.
@@ -127,7 +126,7 @@ func (w *Window) update(frame *op.Ops) {
}
func (w *Window) draw(frameStart time.Time, size image.Point, frame *op.Ops) {
sync := w.gpu.Draw(w.queue.q.Profiling(), size, frame)
sync := w.loop.Draw(w.queue.q.Profiling(), size, frame)
w.queue.q.Frame(frame)
switch w.queue.q.TextInputState() {
case input.TextInputOpen:
@@ -139,7 +138,7 @@ func (w *Window) draw(frameStart time.Time, size image.Point, frame *op.Ops) {
frameDur := time.Since(frameStart)
frameDur = frameDur.Truncate(100 * time.Microsecond)
q := 100 * time.Microsecond
timings := fmt.Sprintf("tot:%7s %s", frameDur.Round(q), w.gpu.Timings())
timings := fmt.Sprintf("tot:%7s %s", frameDur.Round(q), w.loop.Summary())
w.queue.q.AddProfile(profile.Event{Timings: timings})
}
if t, ok := w.queue.q.WakeupTime(); ok {
@@ -218,9 +217,9 @@ func (w *Window) destroy(err error) {
}
func (w *Window) destroyGPU() {
if w.gpu != nil {
w.gpu.Release()
w.gpu = nil
if w.loop != nil {
w.loop.Release()
w.loop = nil
}
}
@@ -252,12 +251,12 @@ func (w *Window) run(opts *window.Options) {
case e := <-w.in:
switch e2 := e.(type) {
case system.StageEvent:
if w.gpu != nil {
if w.loop != nil {
if e2.Stage < system.StageRunning {
w.gpu.Release()
w.gpu = nil
w.loop.Release()
w.loop = nil
} else {
w.gpu.Refresh()
w.loop.Refresh()
}
}
w.stage = e2.Stage
@@ -277,19 +276,19 @@ func (w *Window) run(opts *window.Options) {
e2.Frame = w.update
w.out <- e2.FrameEvent
var err error
if w.gpu != nil {
if w.loop != nil {
if e2.Sync {
w.gpu.Refresh()
w.loop.Refresh()
}
if err = w.gpu.Flush(); err != nil {
w.gpu.Release()
w.gpu = nil
if err = w.loop.Flush(); err != nil {
w.loop.Release()
w.loop = nil
}
} else {
var ctx gl.Context
ctx, err = w.driver.NewContext()
if err == nil {
w.gpu, err = gpu.New(ctx)
w.loop, err = newLoop(ctx)
if err != nil {
ctx.Release()
}
@@ -318,9 +317,9 @@ func (w *Window) run(opts *window.Options) {
w.frameAck <- struct{}{}
}
if e2.Sync {
if err := w.gpu.Flush(); err != nil {
w.gpu.Release()
w.gpu = nil
if err := w.loop.Flush(); err != nil {
w.loop.Release()
w.loop = nil
w.destroy(err)
return
}