dumb_device_test.go RawHistoryFolder

1package drm
2
3import (
4	"bytes"
5	"errors"
6	"os"
7	"path/filepath"
8	"testing"
9
10	"golang.org/x/sys/unix"
11)
12
13// Real-device check of the dumb buffer layer: no modeset, no atomic commit.
14// It skips when no card node can be opened or makes dumb buffers.
15func TestDumbBuffersOnRealDevice(t *testing.T) {
16	cards, _ := filepath.Glob("/dev/dri/card*")
17	if len(cards) == 0 {
18		t.Skip("no /dev/dri/card* node")
19	}
20	for _, path := range cards {
21		f, err := os.OpenFile(path, os.O_RDWR|unix.O_CLOEXEC, 0)
22		if err != nil {
23			t.Logf("%s: %v", path, err)
24			continue
25		}
26		done := func() bool {
27			defer f.Close()
28			return dumbDeviceRoundTrip(t, path, kmsDevice{fd: int(f.Fd())})
29		}()
30		if done {
31			return
32		}
33	}
34	t.Skip("no card node makes dumb buffers for this user")
35}
36
37// dumbDeviceRoundTrip runs the buffer life cycle on k and reports false
38// when the card cannot do it for a reason unrelated to the code under test
39// (the permission or the driver).
40func dumbDeviceRoundTrip(t *testing.T, path string, k kmsDevice) bool {
41	size := cursorSize(k.fd)
42	var imgs [2]dumbBuffer
43	var mems [2][]byte
44	var fbs [2]uint32
45	cleanup := func() {
46		for i := range imgs {
47			if fbs[i] != 0 {
48				if err := k.rmFB(fbs[i]); err != nil {
49					t.Errorf("rmfb: %v", err)
50				}
51			}
52			if mems[i] != nil {
53				if err := k.unmapDumb(mems[i]); err != nil {
54					t.Errorf("munmap: %v", err)
55				}
56			}
57			if imgs[i].handle != 0 {
58				if err := k.destroyDumb(imgs[i].handle); err != nil {
59					t.Errorf("destroy dumb: %v", err)
60				}
61			}
62		}
63	}
64	defer cleanup()
65	for i := range imgs {
66		b, err := k.createDumb(size, size)
67		if err != nil {
68			if errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM) || errors.Is(err, unix.ENOTSUP) || errors.Is(err, unix.ENOSYS) || errors.Is(err, unix.EINVAL) {
69				t.Logf("%s: create dumb: %v", path, err)
70				return false
71			}
72			t.Fatalf("%s: create dumb: %v", path, err)
73		}
74		imgs[i] = b
75		if int(b.pitch) < size*4 || b.size < uint64(int(b.pitch)*size) {
76			t.Fatalf("%s: dumb %dx%d pitch %d size %d", path, size, size, b.pitch, b.size)
77		}
78		if mems[i], err = k.mapDumb(b); err != nil {
79			t.Fatalf("%s: map dumb: %v", path, err)
80		}
81		if fbs[i], err = k.addFBHandle(b, size, size, fourccARGB); err != nil {
82			t.Fatalf("%s: add fb2 ARGB8888: %v", path, err)
83		}
84		t.Logf("%s: dumb buffer %d: %dx%d pitch %d size %d fb %d", path, i, size, size, b.pitch, b.size, fbs[i])
85	}
86	// Write a pattern through the shared mapping; each buffer keeps its own.
87	for i, mem := range mems {
88		d := &dumbCursor{k: k, size: size}
89		d.img[i] = dumbImage{pitch: int(imgs[i].pitch), mem: mem}
90		px := bytes.Repeat([]byte{byte(0x10 + i), 0x20, 0x30, 0xff}, 3*2)
91		if err := d.write(i, px, 3, 2, 0); err != nil {
92			t.Fatal(err)
93		}
94	}
95	for i, mem := range mems {
96		pitch := int(imgs[i].pitch)
97		want := []byte{byte(0x10 + i), 0x20, 0x30, 0xff}
98		for y := range 2 {
99			if got := mem[y*pitch : y*pitch+4]; !bytes.Equal(got, want) {
100				t.Fatalf("%s: buffer %d row %d read back %v, want %v", path, i, y, got, want)
101			}
102			if got := mem[y*pitch+3*4]; got != 0 {
103				t.Fatalf("%s: buffer %d row %d not cleared after the image", path, i, y)
104			}
105		}
106		if mem[2*pitch] != 0 || mem[(size-1)*pitch+(size-1)*4] != 0 {
107			t.Fatalf("%s: buffer %d not cleared below the image", path, i)
108		}
109	}
110	return true
111}

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