v0.4.0 b6be3a8

frame_submit_test.go RawHistoryFolder

1package drm
2
3import (
4	"context"
5	"errors"
6	"os"
7	"testing"
8
9	portsmocks "github.com/bnema/neferwl/internal/mocks/ports"
10	"github.com/bnema/neferwl/internal/ports"
11	"github.com/stretchr/testify/mock"
12	"golang.org/x/sys/unix"
13)
14
15// A fullscreen dmabuf the kernel takes is scanned out: nothing renders.
16func TestSubmitFrameScanout(t *testing.T) {
17	o, k, commits := testOutput(t)
18	o.cursor = nil
19	o.primary.formats = []ports.DMABufFormat{{Format: fourccXRGB}}
20	k.EXPECT().addFB(mock.Anything, uint32(fourccXRGB)).Return(88, nil).Once()
21	s, c := fullscreenScene()
22	r := portsmocks.NewMockRenderer(t)
23	direct, err := o.submitFrame(context.Background(), r, s, c, map[ports.WindowID]uint64{}, nil, nil)
24	if err != nil || !direct {
25		t.Fatalf("direct %v err %v", direct, err)
26	}
27	if v, _ := (*commits)[len(*commits)-1].req.value(tPrimary, pFB); v != 88 {
28		t.Fatalf("primary fb %d", v)
29	}
30	if o.queued != 9 {
31		t.Fatalf("queued %d", o.queued)
32	}
33}
34
35// A scanout flip the kernel refuses composes the same frame instead.
36func TestSubmitFrameScanoutRefusedComposes(t *testing.T) {
37	o, k, commits := testOutput(t, unix.EINVAL)
38	o.cursor, o.tearing, o.vrrProp = nil, false, 0
39	o.primary.formats = []ports.DMABufFormat{{Format: fourccXRGB}}
40	k.EXPECT().addFB(mock.Anything, uint32(fourccXRGB)).Return(88, nil).Once()
41	s, c := fullscreenScene()
42	r := portsmocks.NewMockRenderer(t)
43	r.EXPECT().UseTarget(0).Return().Once()
44	r.EXPECT().Render(s, c).Return(nil, nil).Once()
45	direct, err := o.submitFrame(context.Background(), r, s, c, map[ports.WindowID]uint64{}, nil, nil)
46	if err != nil || direct {
47		t.Fatalf("direct %v err %v", direct, err)
48	}
49	if v, _ := (*commits)[len(*commits)-1].req.value(tPrimary, pFB); v != 70 || o.back != 1 {
50		t.Fatalf("primary fb %d back %d", v, o.back)
51	}
52	if o.reason != "flip_refused" {
53		t.Fatalf("reason %q", o.reason)
54	}
55}
56
57// An overlay the kernel refuses in its test commit is composed too.
58func TestSubmitFrameOverlayRefusedComposesAll(t *testing.T) {
59	o, k, commits := overlayOutput(t, unix.EINVAL)
60	o.cursor = nil
61	k.EXPECT().addFB(mock.Anything, uint32(fourccXRGB)).Return(88, nil).Once()
62	o.overlay.formats = []ports.DMABufFormat{{Format: fourccXRGB}}
63	s, c := overlayScene()
64	r := portsmocks.NewMockRenderer(t)
65	r.EXPECT().UseTarget(0).Return().Once()
66	var drawn []int
67	r.EXPECT().Render(mock.Anything, mock.Anything).RunAndReturn(func(s ports.Scene, _ map[ports.WindowID]ports.SurfaceContent) (*os.File, error) {
68		drawn = append(drawn, len(s.Windows))
69		return nil, nil
70	}).Twice()
71	direct, err := o.submitFrame(context.Background(), r, s, c, map[ports.WindowID]uint64{}, nil, nil)
72	if err != nil || direct {
73		t.Fatalf("direct %v err %v", direct, err)
74	}
75	// First without the overlay window, then the whole scene.
76	if len(drawn) != 2 || drawn[0] != 1 || drawn[1] != 2 {
77		t.Fatalf("rendered windows %v", drawn)
78	}
79	if v, ok := (*commits)[len(*commits)-1].req.value(tOverlay, pFB); ok && v != 0 {
80		t.Fatalf("overlay committed: fb %d", v)
81	}
82}
83
84// An overlay commit the kernel refuses after its test passed drops the
85// overlay: the caller asks for a new, fully composed frame.
86func TestSubmitFrameOverlayCommitRefusedDropsOverlay(t *testing.T) {
87	o, k, _ := overlayOutput(t, nil, unix.EINVAL)
88	o.cursor, o.vrrProp = nil, 0
89	k.EXPECT().addFB(mock.Anything, uint32(fourccXRGB)).Return(88, nil).Once()
90	o.overlay.formats = []ports.DMABufFormat{{Format: fourccXRGB}}
91	s, c := overlayScene()
92	r := portsmocks.NewMockRenderer(t)
93	r.EXPECT().UseTarget(0).Return().Once()
94	r.EXPECT().Render(mock.Anything, mock.Anything).Return(nil, nil).Once()
95	if _, err := o.submitFrame(context.Background(), r, s, c, map[ports.WindowID]uint64{}, nil, nil); !errors.Is(err, errOverlayDropped) {
96		t.Fatalf("err %v", err)
97	}
98	if o.back != 0 || o.clientFBs[9].overlayFailed != "cursor_conflict" {
99		t.Fatalf("back %d reason %q", o.back, o.clientFBs[9].overlayFailed)
100	}
101}
102
103// A render failure stops the output and is not a commit error.
104func TestSubmitFrameRenderError(t *testing.T) {
105	o, _, commits := testOutput(t)
106	boom := errors.New("boom")
107	r := portsmocks.NewMockRenderer(t)
108	r.EXPECT().UseTarget(0).Return().Once()
109	r.EXPECT().Render(mock.Anything, mock.Anything).Return(nil, boom).Once()
110	_, err := o.submitFrame(context.Background(), r, ports.Scene{Seq: 1}, nil, map[ports.WindowID]uint64{}, nil, nil)
111	var fatal renderError
112	if !errors.As(err, &fatal) || !errors.Is(err, boom) {
113		t.Fatalf("err %v", err)
114	}
115	if len(*commits) != 0 || o.back != 0 {
116		t.Fatalf("committed %d back %d", len(*commits), o.back)
117	}
118}
119
120func fullscreenScene() (ports.Scene, map[ports.WindowID]ports.SurfaceContent) {
121	s := ports.Scene{Seq: 1, Scale: 1, OutputWidth: 200, OutputHeight: 100, Windows: []ports.SceneWindow{
122		{ID: 1, Rect: ports.Rect{W: 200, H: 100}, Fullscreen: true},
123	}}
124	return s, map[ports.WindowID]ports.SurfaceContent{
125		1: {ID: 1, Width: 200, Height: 100, LogicalW: 200, LogicalH: 100, Opaque: true, DMABuf: &ports.DMABuf{ID: 9, Width: 200, Height: 100, Format: fourccXRGB}},
126	}
127}

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