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) {