detached 8967242

test(vulkan): pin the sceneDelta-seeded partial redraw at zero allocations

TestRenderSteadyStateAllocations replicates Render's partial sequence for a
new scene Seq with one of two windows moved, asserts the redraw is partial
and that building and clipping its draws allocates nothing.
commit
8967242492da9807176f169f767457566f09db25
author
brice · · 2026-10-04 20:34 UTC
committer
brice · · 2026-10-04 20:57 UTC
parent
185b931
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +40 -1
M internal/adapters/vulkan/scene_perf_test.go +40 -1
@@ -12,7 +12,8 @@ import (
1212 // on a normal and on a rotated output (orient works in place), and that
1313 // building the draws of a scene with a moving window (a new Seq and window
1414 // slice every frame, as an animation publishes) allocates nothing.
15-// TODO(A2): add the partial redraw seeded by sceneDelta once it is merged.
15+// A new scene Seq with one of two windows moved is a partial redraw seeded by
16+// sceneDelta and allocates nothing either.
1617 func TestRenderSteadyStateAllocations(t *testing.T) {
1718 for _, tc := range []struct {
1819 name string
@@ -93,6 +94,44 @@ func TestRenderSteadyStateAllocations(t *testing.T) {
9394 if allocs := testing.AllocsPerRun(50, partial); allocs != 0 {
9495 t.Errorf("partial redraw draws: %.1f allocs/frame, want 0", allocs)
9596 }
97+ // A new scene Seq with one window moved: the delta against the
98+ // scene the target holds seeds the partial redraw (A2). The
99+ // stand-in target holds the old scene and is never updated.
100+ half := tc.sceneW / 2
101+ content2 := solidContent(t, 8, 8, color.RGBA{G: 255, A: 255})
102+ content2.ID, content2.Surface, content2.Seq, content2.Version = 2, 2, 1, 1
103+ dcontents := map[ports.WindowID]ports.SurfaceContent{1: content, 2: content2}
104+ before := ports.Scene{Seq: 200, Transform: tc.transform, Scale: 1, Windows: []ports.SceneWindow{
105+ {ID: 1, Rect: ports.Rect{W: half, H: tc.sceneH}},
106+ {ID: 2, Rect: ports.Rect{X: half, W: tc.sceneW - half, H: tc.sceneH}},
107+ }}
108+ moved := before
109+ moved.Seq = 201
110+ moved.Windows = []ports.SceneWindow{before.Windows[0], {ID: 2, Rect: ports.Rect{X: half + 1, W: tc.sceneW - half - 1, H: tc.sceneH}}}
111+ full := image.Rect(0, 0, r.width, r.height)
112+ held = &target{valid: true, sceneSeq: before.Seq, scene: before, windows: map[ports.WindowID]heldWindow{
113+ 1: {seq: 1, rect: image.Rect(0, 0, half, tc.sceneH)},
114+ 2: {seq: 1, rect: image.Rect(half, 0, tc.sceneW, tc.sceneH)},
115+ }}
116+ seeded := func() {
117+ dmg := r.frameDamage(held, moved, bounds)
118+ ds := r.draws(moved, dcontents, dmg)
119+ dmg.finish()
120+ ds = append(ds, draw{})
121+ copy(ds[1:], ds[:len(ds)-1])
122+ ds[0] = r.fillDraw(dmg.area, parseColor(moved.Background))
123+ ds = dmg.clip(ds)
124+ r.scratchDraws = ds
125+ r.orient(ds, moved.Transform)
126+ area, whole = dmg.area, dmg.all()
127+ }
128+ seeded()
129+ if whole || area.Empty() || area.Dx()*area.Dy() >= full.Dx()*full.Dy() {
130+ t.Fatalf("sceneDelta did not seed a partial redraw: all %v, area %v of %v", whole, area, bounds)
131+ }
132+ if allocs := testing.AllocsPerRun(50, seeded); allocs != 0 {
133+ t.Errorf("sceneDelta-seeded partial redraw draws: %.1f allocs/frame, want 0", allocs)
134+ }
96135 })
97136 }
98137 }
@@ -12,7 +12,8 @@ import (
12 // on a normal and on a rotated output (orient works in place), and that12 // on a normal and on a rotated output (orient works in place), and that
13 // building the draws of a scene with a moving window (a new Seq and window13 // building the draws of a scene with a moving window (a new Seq and window
14 // slice every frame, as an animation publishes) allocates nothing.14 // slice every frame, as an animation publishes) allocates nothing.
15-// TODO(A2): add the partial redraw seeded by sceneDelta once it is merged.15+// A new scene Seq with one of two windows moved is a partial redraw seeded by
16+// sceneDelta and allocates nothing either.
16 func TestRenderSteadyStateAllocations(t *testing.T) {17 func TestRenderSteadyStateAllocations(t *testing.T) {
17 for _, tc := range []struct {18 for _, tc := range []struct {
18 name string19 name string
@@ -93,6 +94,44 @@ func TestRenderSteadyStateAllocations(t *testing.T) {
93 if allocs := testing.AllocsPerRun(50, partial); allocs != 0 {94 if allocs := testing.AllocsPerRun(50, partial); allocs != 0 {
94 t.Errorf("partial redraw draws: %.1f allocs/frame, want 0", allocs)95 t.Errorf("partial redraw draws: %.1f allocs/frame, want 0", allocs)
95 }96 }
97+ // A new scene Seq with one window moved: the delta against the
98+ // scene the target holds seeds the partial redraw (A2). The
99+ // stand-in target holds the old scene and is never updated.
100+ half := tc.sceneW / 2
101+ content2 := solidContent(t, 8, 8, color.RGBA{G: 255, A: 255})
102+ content2.ID, content2.Surface, content2.Seq, content2.Version = 2, 2, 1, 1
103+ dcontents := map[ports.WindowID]ports.SurfaceContent{1: content, 2: content2}
104+ before := ports.Scene{Seq: 200, Transform: tc.transform, Scale: 1, Windows: []ports.SceneWindow{
105+ {ID: 1, Rect: ports.Rect{W: half, H: tc.sceneH}},
106+ {ID: 2, Rect: ports.Rect{X: half, W: tc.sceneW - half, H: tc.sceneH}},
107+ }}
108+ moved := before
109+ moved.Seq = 201
110+ moved.Windows = []ports.SceneWindow{before.Windows[0], {ID: 2, Rect: ports.Rect{X: half + 1, W: tc.sceneW - half - 1, H: tc.sceneH}}}
111+ full := image.Rect(0, 0, r.width, r.height)
112+ held = &target{valid: true, sceneSeq: before.Seq, scene: before, windows: map[ports.WindowID]heldWindow{
113+ 1: {seq: 1, rect: image.Rect(0, 0, half, tc.sceneH)},
114+ 2: {seq: 1, rect: image.Rect(half, 0, tc.sceneW, tc.sceneH)},
115+ }}
116+ seeded := func() {
117+ dmg := r.frameDamage(held, moved, bounds)
118+ ds := r.draws(moved, dcontents, dmg)
119+ dmg.finish()
120+ ds = append(ds, draw{})
121+ copy(ds[1:], ds[:len(ds)-1])
122+ ds[0] = r.fillDraw(dmg.area, parseColor(moved.Background))
123+ ds = dmg.clip(ds)
124+ r.scratchDraws = ds
125+ r.orient(ds, moved.Transform)
126+ area, whole = dmg.area, dmg.all()
127+ }
128+ seeded()
129+ if whole || area.Empty() || area.Dx()*area.Dy() >= full.Dx()*full.Dy() {
130+ t.Fatalf("sceneDelta did not seed a partial redraw: all %v, area %v of %v", whole, area, bounds)
131+ }
132+ if allocs := testing.AllocsPerRun(50, seeded); allocs != 0 {
133+ t.Errorf("sceneDelta-seeded partial redraw draws: %.1f allocs/frame, want 0", allocs)
134+ }
96 })135 })
97 }136 }
98 }137 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 23

Tags 10

↑↓ moveenter openesc close