1package surfaces
2
3import (
4 "os"
5 "testing"
6
7 "github.com/bnema/neferwl/internal/ports"
8)
9
10func shows(ids ...ports.WindowID) ports.Scene {
11 s := ports.Scene{OutputWidth: 100, OutputHeight: 100}
12 for _, id := range ids {
13 s.Windows = append(s.Windows, ports.SceneWindow{ID: id, Rect: ports.Rect{W: 10, H: 10}})
14 }
15 return s
16}
17
18// An empty content of a window the scene draws keeps the previous one with
19// its Acquire fence dropped; the content goes once a scene no longer lists
20// the window.
21func TestEmptyContentKeptWhileShown(t *testing.T) {
22 tb := New()
23 r, w, err := os.Pipe()
24 if err != nil {
25 t.Fatal(err)
26 }
27 defer r.Close()
28 defer w.Close()
29 full := ports.SurfaceContent{ID: 1, Seq: 4, Width: 10, Height: 10, DMABuf: &ports.DMABuf{ID: 7}, Acquire: r}
30 tb.Update(full, shows(1))
31 tb.Update(ports.SurfaceContent{ID: 1, Seq: 5}, shows(1))
32 kept, ok := tb.Map()[1]
33 if !ok || kept.DMABuf != full.DMABuf || kept.Seq != 4 {
34 t.Fatalf("kept %+v, want the previous content", kept)
35 }
36 if kept.Acquire != nil {
37 t.Fatal("the kept content keeps its Acquire fence")
38 }
39 if !tb.Kept(1) {
40 t.Fatal("Kept false for a content drawn after its empty one")
41 }
42 // A scene still listing it keeps it; one without it drops it.
43 tb.Prune(shows(1, 2))
44 if _, ok := tb.Map()[1]; !ok {
45 t.Fatal("dropped while still listed")
46 }
47 tb.Prune(shows(2))
48 if _, ok := tb.Map()[1]; ok || tb.Kept(1) {
49 t.Fatal("not dropped once unlisted")
50 }
51}
52
53// An empty content of a window the scene does not draw drops it at once.
54func TestEmptyContentOfUnshownWindowDropped(t *testing.T) {
55 tb := New()
56 tb.Update(ports.SurfaceContent{ID: 1, SHM: &ports.SHMBuffer{Pool: 1}}, shows(1))
57 tb.Update(ports.SurfaceContent{ID: 1}, shows(2))
58 if _, ok := tb.Map()[1]; ok || tb.Kept(1) {
59 t.Fatal("content of an unshown window kept")
60 }
61 // Hidden counts as not drawn.
62 tb.Update(ports.SurfaceContent{ID: 3, SHM: &ports.SHMBuffer{Pool: 3}}, shows())
63 hidden := ports.Scene{OutputWidth: 100, OutputHeight: 100, Windows: []ports.SceneWindow{{ID: 3, Hidden: true, Rect: ports.Rect{W: 10, H: 10}}}}
64 tb.Update(ports.SurfaceContent{ID: 3}, hidden)
65 if _, ok := tb.Map()[3]; ok {
66 t.Fatal("content of a hidden window kept")
67 }
68}
69
70// A new content replaces a kept one and the window is no longer kept (the
71// client mapped again).
72func TestNewContentReplacesKept(t *testing.T) {
73 tb := New()
74 tb.Update(ports.SurfaceContent{ID: 1, Seq: 1, SHM: &ports.SHMBuffer{Pool: 1}}, shows(1))
75 tb.Update(ports.SurfaceContent{ID: 1, Seq: 2}, shows(1))
76 tb.Update(ports.SurfaceContent{ID: 1, Seq: 3, SHM: &ports.SHMBuffer{Pool: 2}}, shows(1))
77 if c := tb.Map()[1]; c.Seq != 3 || c.SHM.Pool != 2 || tb.Kept(1) {
78 t.Fatalf("after a new content: %+v kept %t", c, tb.Kept(1))
79 }
80 // The map handed out is the table's own: the renderer sees updates.
81 m := tb.Map()
82 tb.Update(ports.SurfaceContent{ID: 2, Seq: 1, SHM: &ports.SHMBuffer{Pool: 9}}, shows(1, 2))
83 if _, ok := m[2]; !ok {
84 t.Fatal("Map is a copy")
85 }
86}
87
88// Update and Prune allocate nothing in steady state.
89func TestUpdateAllocations(t *testing.T) {
90 tb := New()
91 s := shows(1, 2)
92 c := ports.SurfaceContent{ID: 1, Seq: 1, SHM: &ports.SHMBuffer{Pool: 1}}
93 tb.Update(c, s)
94 if n := testing.AllocsPerRun(100, func() {
95 c.Seq++
96 tb.Update(c, s)
97 tb.Prune(s)
98 }); n != 0 {
99 t.Fatalf("%v allocations per update", n)
100 }
101}
102
103// The kept content's children lose their Acquire fences too, on a copy:
104// wayland's own slice (shared with its publication) is left alone.
105func TestKeptChildrenFencesDroppedOnACopy(t *testing.T) {
106 tb := New()
107 r, w, err := os.Pipe()
108 if err != nil {
109 t.Fatal(err)
110 }
111 defer r.Close()
112 defer w.Close()
113 children := []ports.Subsurface{{SurfaceContent: ports.SurfaceContent{DMABuf: &ports.DMABuf{ID: 2}, Acquire: r}}}
114 full := ports.SurfaceContent{ID: 1, Seq: 1, SHM: &ports.SHMBuffer{Pool: 1}, Children: children}
115 tb.Update(full, shows(1))
116 tb.Update(ports.SurfaceContent{ID: 1, Seq: 2}, shows(1))
117 kept := tb.Map()[1]
118 if len(kept.Children) != 1 || kept.Children[0].Acquire != nil || kept.Children[0].DMABuf != children[0].DMABuf {
119 t.Fatalf("kept children %+v", kept.Children)
120 }
121 if children[0].Acquire != r {
122 t.Fatal("wayland's slice was modified")
123 }
124}
125
126// Both backends report a window shown only when the scene draws it and its
127// content is not kept.
128func TestFillShown(t *testing.T) {
129 kept := func(id ports.WindowID) bool { return id == 2 }
130 dst := map[ports.WindowID]uint64{9: 9}
131 FillShown(dst, map[ports.WindowID]uint64{1: 3, 2: 4, 3: 5}, shows(1, 2), kept)
132 if len(dst) != 1 || dst[1] != 3 {
133 t.Fatalf("shown %v", dst)
134 }
135 if !Shown(shows(2), 2, nil) {
136 t.Fatal("nil kept counts nothing as kept")
137 }
138}