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

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