main f2d166b

state_schedule_test.go RawHistoryFolder

1package drm
2
3import (
4	"testing"
5	"time"
6
7	"github.com/bnema/neferwl/internal/ports"
8)
9
10func TestStateDelay(t *testing.T) {
11	o, _, _ := testOutput(t) // 60 Hz
12	p := o.nominalPeriod()
13	lead := stateLead(p)
14	last := 10 * time.Second
15	for _, tc := range []struct {
16		name string
17		vrr  bool
18		last time.Duration
19		now  time.Duration
20		want time.Duration
21	}{
22		{"no vblank yet", false, 0, last, 0},
23		{"right after a vblank", false, last, last + time.Millisecond, p - lead - time.Millisecond},
24		{"inside the lead", false, last, last + p - lead/2, 0},
25		{"periods later", false, last, last + 3*p + time.Millisecond, p - lead - time.Millisecond},
26		{"stale vblank", false, last, last + vblankStale + time.Millisecond, 0},
27		{"VRR", true, last, last + time.Millisecond, 0},
28	} {
29		o.vrrOn, o.lastVblankAt = tc.vrr, tc.last
30		if got := o.stateDelay(tc.now); got != tc.want {
31			t.Errorf("%s: delay %v, want %v", tc.name, got, tc.want)
32		}
33	}
34}
35
36// A cursor move right after a vblank waits: the frame that comes before
37// the deadline carries it, in a single commit.
38func TestDeferredCursorRidesOnFrame(t *testing.T) {
39	o, _, commits := testOutput(t)
40	o.cursor.image = true
41	o.stateAt = time.Now().Add(time.Hour) // the vblank is far
42	o.cursor.Move(7, 7)
43	if err := o.commitState(false); err != nil {
44		t.Fatal(err)
45	}
46	if len(*commits) != 0 || o.stateAt.IsZero() || o.frame.pendingCommit() {
47		t.Fatalf("cursor committed at once: %d commits, due %v", len(*commits), o.stateAt)
48	}
49	if err := o.commitFrame(70, nil, false, false, pendingFrame{}); err != nil {
50		t.Fatal(err)
51	}
52	if v, _ := (*commits)[0].req.value(tCursor, 14); v != 7 || !o.stateAt.IsZero() {
53		t.Fatalf("frame cursor x %d, due %v", v, o.stateAt)
54	}
55	if s := o.takeFlipStats(); s.stateCarried != 1 || s.stateCommits != 0 {
56		t.Fatalf("carried %d, state commits %d, want 1, 0", s.stateCarried, s.stateCommits)
57	}
58}
59
60// With no frame, the deferred move commits alone once due, and a late
61// timer does not push it by another period.
62func TestDeferredCursorCommitsWhenDue(t *testing.T) {
63	o, _, commits := testOutput(t)
64	o.cursor.image = true
65	o.stateAt = time.Now().Add(time.Hour)
66	o.cursor.Move(4, 4)
67	if err := o.commitState(false); err != nil || len(*commits) != 0 {
68		t.Fatalf("err %v, %d commits", err, len(*commits))
69	}
70	o.stateAt = time.Now().Add(-time.Millisecond) // the timer fired late
71	if err := o.commitState(false); err != nil || len(*commits) != 1 {
72		t.Fatalf("due commit: %v, %d commits", err, len(*commits))
73	}
74	if v, _ := (*commits)[0].req.value(tCursor, 14); v != 4 || !o.stateAt.IsZero() {
75		t.Fatalf("cursor x %d, due %v", v, o.stateAt)
76	}
77	if s := o.takeFlipStats(); s.stateCommits != 1 || s.stateCarried != 0 {
78		t.Fatalf("state commits %d, carried %d, want 1, 0", s.stateCommits, s.stateCarried)
79	}
80}
81
82// A move undone before its deadline commits nothing and clears the wait.
83func TestDeferredCursorMovedBack(t *testing.T) {
84	o, _, commits := testOutput(t)
85	o.cursor.image = true
86	o.cursor.Move(0, 0)
87	o.cursor.applied = o.cursor.desired()
88	o.stateAt = time.Now().Add(time.Hour)
89	o.cursor.Move(9, 9)
90	if err := o.commitState(false); err != nil || o.stateAt.IsZero() {
91		t.Fatalf("err %v, due %v", err, o.stateAt)
92	}
93	o.cursor.Move(0, 0)
94	if err := o.commitState(false); err != nil || !o.stateAt.IsZero() || len(*commits) != 0 {
95		t.Fatalf("err %v, due %v, %d commits", err, o.stateAt, len(*commits))
96	}
97}
98
99// Powering off drops a deferred state change: an off output has no vblank,
100// and an armed deadline would wake Run forever.
101func TestPowerOffDropsDeferredState(t *testing.T) {
102	o, _, _ := testOutput(t)
103	o.stateAt, o.lastVblankAt = time.Now().Add(time.Hour), time.Second
104	if err := o.powerOff(); err != nil {
105		t.Fatal(err)
106	}
107	if !o.stateAt.IsZero() || o.lastVblankAt != 0 {
108		t.Fatalf("due %v, vblank %v after power off", o.stateAt, o.lastVblankAt)
109	}
110}
111
112// Vsynced completions, state ones included, give the vblank; a tearing
113// flip does not.
114func TestCompletionRecordsVblank(t *testing.T) {
115	o, _, commits := testOutput(t)
116	o.cursor.image = true
117	o.cursor.Move(2, 2)
118	if err := o.commitState(false); err != nil || len(*commits) != 1 {
119		t.Fatalf("err %v, %d commits", err, len(*commits))
120	}
121	ev := eventOf((*commits)[0])
122	ev.when = 5 * time.Second
123	if !o.completed(ev, map[ports.WindowID]uint64{}) || o.lastVblankAt != ev.when {
124		t.Fatalf("vblank %v, want %v", o.lastVblankAt, ev.when)
125	}
126	o.noteVblank(pendingFrame{async: true}, 6*time.Second)
127	if o.lastVblankAt != ev.when {
128		t.Fatalf("tearing flip taken as a vblank: %v", o.lastVblankAt)
129	}
130}

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 25

Tags 10

↑↓ moveenter openesc close