From 84b586ae6ce6de14f9310425dc948c5ab3c5df5d Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 22 Jan 2021 18:33:34 +0100 Subject: [PATCH] gpu: don't automatically clear screen before rendering Gio UI may be overlaid on top of custom graphics such as in the glfw example. That will only work if Gio doesn't clear the screen (to white). Signed-off-by: Elias Naur --- app/headless/headless.go | 2 ++ app/loop.go | 2 ++ gpu/compute.go | 12 ++++++++++-- gpu/gpu.go | 23 ++++++++++++++++++++--- internal/rendertest/util_test.go | 2 +- 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/app/headless/headless.go b/app/headless/headless.go index 9a9ad25b..a8abeb6f 100644 --- a/app/headless/headless.go +++ b/app/headless/headless.go @@ -6,6 +6,7 @@ package headless import ( "image" + "image/color" "runtime" "gioui.org/gpu" @@ -108,6 +109,7 @@ func (w *Window) Release() { // operation list. func (w *Window) Frame(frame *op.Ops) error { return contextDo(w.ctx, func() error { + w.gpu.Clear(color.NRGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff}) w.gpu.Collect(w.size, frame) return w.gpu.Frame() }) diff --git a/app/loop.go b/app/loop.go index c6c9b2ef..cf00c415 100644 --- a/app/loop.go +++ b/app/loop.go @@ -4,6 +4,7 @@ package app import ( "image" + "image/color" "runtime" "gioui.org/app/internal/window" @@ -85,6 +86,7 @@ func (l *renderLoop) renderLoop(ctx window.Context) error { l.refreshErr <- ctx.MakeCurrent() case frame := <-l.frames: ctx.Lock() + g.Clear(color.NRGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff}) g.Collect(frame.viewport, frame.ops) // Signal that we're done with the frame ops. l.ack <- struct{}{} diff --git a/gpu/compute.go b/gpu/compute.go index 1e37067b..bd19e742 100644 --- a/gpu/compute.go +++ b/gpu/compute.go @@ -230,6 +230,11 @@ func (g *compute) Collect(viewport image.Point, ops *op.Ops) { } } +func (g *compute) Clear(col color.NRGBA) { + g.drawOps.clear = true + g.drawOps.clearColor = f32color.LinearFromSRGB(col) +} + func (g *compute) Frame() error { viewport := g.drawOps.viewport tileDims := image.Point{ @@ -285,8 +290,11 @@ func (g *compute) encode(viewport image.Point) { // Flip Y-axis. flipY := f32.Affine2D{}.Scale(f32.Pt(0, 0), f32.Pt(1, -1)).Offset(f32.Pt(0, float32(viewport.Y))) g.enc.transform(flipY) - g.enc.rect(f32.Rectangle{Max: layout.FPt(viewport)}, false) - g.enc.fill(f32color.NRGBAToRGBA(g.drawOps.clearColor.SRGB())) + if g.drawOps.clear { + g.drawOps.clear = false + g.enc.rect(f32.Rectangle{Max: layout.FPt(viewport)}, false) + g.enc.fill(f32color.NRGBAToRGBA(g.drawOps.clearColor.SRGB())) + } g.encodeOps(flipY, viewport, g.drawOps.allImageOps) } diff --git a/gpu/gpu.go b/gpu/gpu.go index db914552..566e8f39 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -31,9 +31,17 @@ import ( ) type GPU interface { + // Release non-Go resources. The GPU is no longer valid after Release. Release() - Collect(viewport image.Point, frameOps *op.Ops) + // Clear sets the clear color for the next Frame. + Clear(color color.NRGBA) + // Collect the graphics operations from frame, given the viewport. + Collect(viewport image.Point, frame *op.Ops) + // Frame clears the color buffer and draws the collected operations. Frame() error + // Profile returns the last available profiling information. Profiling + // information is requested when Collect sees a ProfileOp, and the result + // is available through Profile at some later time. Profile() string } @@ -65,6 +73,7 @@ type drawOps struct { cache *resourceCache vertCache []byte viewport image.Point + clear bool clearColor f32color.RGBA // allImageOps is the combined list of imageOps and // zimageOps, in drawing order. @@ -404,6 +413,11 @@ func (g *gpu) init(ctx backend.Device) error { return nil } +func (g *gpu) Clear(col color.NRGBA) { + g.drawOps.clear = true + g.drawOps.clearColor = f32color.LinearFromSRGB(col) +} + func (g *gpu) Release() { g.renderer.release() g.drawOps.pathCache.release() @@ -442,7 +456,10 @@ func (g *gpu) Frame() error { g.ctx.DepthFunc(backend.DepthFuncGreater) // Note that Clear must be before ClearDepth if nothing else is rendered // (len(zimageOps) == 0). If not, the Fairphone 2 will corrupt the depth buffer. - g.ctx.Clear(g.drawOps.clearColor.Float32()) + if g.drawOps.clear { + g.drawOps.clear = false + g.ctx.Clear(g.drawOps.clearColor.Float32()) + } g.ctx.ClearDepth(0.0) g.ctx.Viewport(0, 0, viewport.X, viewport.Y) g.renderer.drawZOps(g.cache, g.drawOps.zimageOps) @@ -799,7 +816,6 @@ func floor(v float32) int { func (d *drawOps) reset(cache *resourceCache, viewport image.Point) { d.profile = false - d.clearColor = f32color.RGBA{R: 1.0, G: 1.0, B: 1.0, A: 1.0} d.cache = cache d.viewport = viewport d.imageOps = d.imageOps[:0] @@ -1006,6 +1022,7 @@ loop: d.imageOps = d.imageOps[:0] z = 0 d.clearColor = mat.color.Opaque() + d.clear = true continue } z++ diff --git a/internal/rendertest/util_test.go b/internal/rendertest/util_test.go index daa31a89..f86f40e6 100644 --- a/internal/rendertest/util_test.go +++ b/internal/rendertest/util_test.go @@ -161,7 +161,7 @@ func verifyRef(t *testing.T, img *image.RGBA, frame int) (ok bool) { } ref, ok := r.(*image.RGBA) if !ok { - t.Error("ref image note RGBA") + t.Errorf("image is a %T, expected *image.RGBA", r) return } if len(ref.Pix) != len(img.Pix) {