gpu: build gpu data also when outside window

This commit fixes a bug where a shape first drawn off-screen
and later moved into screen would not display properly. Since we
cache CPU operations (vertex transform / construction) we need to
upload the constructed data to the GPU after it was build, or a later
frame will use non-initialized memory for it's draw call.

Note that this fix removes the optimization of not processing clip
paths outside the screen - but this is assumed to be uncommon except
when it is first drawn off screen to later be moved in (e.g. in a scrolling list)
in which case we do want to upload the data and prepare for that later
call.

This commit also does a few minor clean ups and adds a test case.

Signed-off-by: Viktor <viktor.ogeman@gmail.com>
This commit is contained in:
Viktor
2020-06-20 23:30:01 +02:00
committed by Elias Naur
parent 901478d102
commit cee045bf92
7 changed files with 108 additions and 14 deletions
+43 -3
View File
@@ -15,7 +15,7 @@ func TestTransformMacro(t *testing.T) {
// testcase resulting from original bug when rendering layout.Stacked
// pre-build the text
c := createText()
c := constSqPath()
run(t, func(o *op.Ops) {
@@ -101,7 +101,7 @@ func TestNoClipFromPaint(t *testing.T) {
})
}
func createText() op.CallOp {
func constSqPath() op.CallOp {
innerOps := new(op.Ops)
m := op.Record(innerOps)
builder := clip.Path{}
@@ -115,6 +115,14 @@ func createText() op.CallOp {
return m.Stop()
}
func constSqCirc() op.CallOp {
innerOps := new(op.Ops)
m := op.Record(innerOps)
clip.Rect{Rect: f32.Rect(0, 0, 40, 40),
NW: 20, NE: 20, SW: 20, SE: 20}.Add(innerOps)
return m.Stop()
}
func drawChild(ops *op.Ops, text op.CallOp) op.CallOp {
r1 := op.Record(ops)
text.Add(ops)
@@ -123,7 +131,7 @@ func drawChild(ops *op.Ops, text op.CallOp) op.CallOp {
}
func TestReuseStencil(t *testing.T) {
txt := createText()
txt := constSqPath()
run(t, func(ops *op.Ops) {
c1 := drawChild(ops, txt)
c2 := drawChild(ops, txt)
@@ -142,3 +150,35 @@ func TestReuseStencil(t *testing.T) {
r.expect(5, 55, colornames.Black)
})
}
func TestBuildOffscreen(t *testing.T) {
// Check that something we in one frame build outside the screen
// still is rendered correctly if moved into the screen in a later
// frame.
txt := constSqCirc()
draw := func(off float32, o *op.Ops) {
s := op.Push(o)
op.TransformOp{}.Offset(f32.Pt(0, off)).Add(o)
txt.Add(o)
paint.PaintOp{Rect: f32.Rect(0, 0, 40, 40)}.Add(o)
s.Pop()
}
multiRun(t,
frame(
func(ops *op.Ops) {
draw(-100, ops)
}, func(r result) {
r.expect(5, 5, colornames.White)
r.expect(20, 20, colornames.White)
}),
frame(
func(ops *op.Ops) {
draw(0, ops)
}, func(r result) {
r.expect(2, 2, colornames.White)
r.expect(20, 20, colornames.Black)
r.expect(38, 38, colornames.White)
}))
}