v0.3.0 cf370a0

scene_perf_test.go RawHistoryFolder

1package vulkan
2
3import (
4	"image"
5	"image/color"
6	"testing"
7
8	"github.com/bnema/neferwl/internal/ports"
9)
10
11// TestRenderSteadyStateAllocations measures the cost of a small stable scene,
12// on a normal and on a rotated output (orient works in place).
13func TestRenderSteadyStateAllocations(t *testing.T) {
14	for _, tc := range []struct {
15		name           string
16		transform      ports.BufferTransform
17		tw, th         int
18		sceneW, sceneH int
19	}{
20		{"transform 0", 0, 32, 32, 32, 32},
21		{"transform 1", 1, 32, 24, 24, 32},
22	} {
23		t.Run(tc.name, func(t *testing.T) {
24			r, err := New(tc.tw, tc.th)
25			if err != nil {
26				t.Skipf("Vulkan unavailable: %v", err)
27			}
28			defer r.Close()
29			scene := ports.Scene{Seq: 1, Transform: tc.transform, Scale: 1, Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: tc.sceneW, H: tc.sceneH}}}}
30			content := solidContent(t, 8, 8, color.RGBA{R: 255, A: 255})
31			content.ID, content.Surface, content.Seq, content.Version = 1, 1, 1, 1
32			contents := map[ports.WindowID]ports.SurfaceContent{1: content}
33			frame := func() {
34				if err := render(r, scene, contents); err != nil {
35					t.Fatal(err)
36				}
37			}
38			frame()
39			if allocs := testing.AllocsPerRun(20, frame); allocs > 13 {
40				t.Errorf("small steady-state Render: %.1f allocs/frame, want <=13", allocs)
41			} else {
42				t.Logf("small steady-state Render: %.1f allocs/frame", allocs)
43			}
44		})
45	}
46}
47
48// TestSceneWalkUnchangedTiledSHM guards the GPU copy budget of an unchanged
49// subsurface tree. Each child has its own real wl_shm pool.
50func TestSceneWalkUnchangedTiledSHM(t *testing.T) {
51	const tiles = 64
52	r, err := New(128, 128)
53	if err != nil {
54		t.Skipf("Vulkan unavailable: %v", err)
55	}
56	defer r.Close()
57	root := ports.SurfaceContent{ID: 1, Seq: 1, Surface: 1, Version: 1}
58	for i := range tiles {
59		child := solidContent(t, 8, 8, color.RGBA{R: uint8(i + 1), A: 255})
60		child.ID, child.Seq, child.Surface, child.Version = 1, 1, uint64(i+2), 1
61		root.Children = append(root.Children, ports.Subsurface{X: i % 8 * 8, Y: i / 8 * 8, SurfaceContent: child})
62	}
63	video := solidContent(t, 8, 8, color.RGBA{G: 255, A: 255})
64	video.ID, video.Seq, video.Surface, video.Version = 1, 1, 66, 1
65	root.Children = append(root.Children, ports.Subsurface{X: 80, Y: 0, SurfaceContent: video})
66	scene := ports.Scene{Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 128, H: 128}}}}
67	contents := map[ports.WindowID]ports.SurfaceContent{1: root}
68	if err := render(r, scene, contents); err != nil {
69		t.Fatal(err)
70	}
71	for _, count := range []int{16, 64} {
72		contents[1] = ports.SurfaceContent{ID: 1, Seq: root.Seq, Surface: root.Surface, Version: root.Version, Children: root.Children[:count]}
73		walk := func() {
74			dmg := newDamage(&target{}, scene, image.Rect(0, 0, r.width, r.height))
75			_ = r.draws(scene, contents, dmg)
76		}
77		walk()
78		if allocs := testing.AllocsPerRun(20, walk); allocs > 8 {
79			t.Errorf("%d tiles: %.1f allocations/walk, want <=8", count, allocs)
80		} else {
81			t.Logf("%d tiles: %.1f allocations/walk", count, allocs)
82		}
83	}
84	contents[1] = root
85	// The same renderer and scene are reused; measure only steady-state frame work.
86	frame := func() {
87		if err := render(r, scene, contents); err != nil {
88			t.Fatal(err)
89		}
90	}
91	frame()
92	if allocs := testing.AllocsPerRun(20, frame); allocs > 16 {
93		t.Errorf("steady-state Render: %.1f allocs/frame, want <=16", allocs)
94	} else {
95		t.Logf("steady-state Render: %.1f allocs/frame", allocs)
96	}
97	before := r.copied
98	for i := range 100 {
99		root.Seq++
100		root.Children[tiles].Version++
101		contents[1] = root
102		if err := render(r, scene, contents); err != nil {
103			t.Fatal(err)
104		}
105		if delta := r.copied - before; delta != 8*8*4 {
106			t.Fatalf("publication %d copied %d bytes, want video only (%d)", i, delta, 8*8*4)
107		}
108		before = r.copied
109	}
110	// Reordering equal-sized children must not reuse another child's pixels.
111	root.Children[0], root.Children[1] = root.Children[1], root.Children[0]
112	root.Children[0].X, root.Children[1].X = 0, 8
113	root.Seq++
114	contents[1] = root
115	if err := render(r, scene, contents); err != nil {
116		t.Fatal(err)
117	}
118	if got := readPixels(t, r).RGBAAt(4, 4); got != (color.RGBA{R: 2, A: 255}) {
119		t.Fatalf("restacked tile has pixels %v, want second child's colour", got)
120	}
121}

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 26

Tags 10

↑↓ moveenter openesc close