1package wayland
2
3import (
4 "testing"
5 "time"
6
7 "github.com/bnema/go-wayland-bindings/server/wayland"
8 "github.com/bnema/go-wayland-bindings/server/xdgshell"
9 "github.com/bnema/neferwl/internal/ports"
10 "golang.org/x/sys/unix"
11)
12
13// Damage reaches the renderer in buffer pixels, per content, with the
14// window's recent history; a new buffer without damage is a full change.
15func TestDamageHistory(t *testing.T) {
16 s, events, _, contents, dir := contentServer(t)
17 c := protocolClient(t, s, dir)
18 comp := bindVersion(t, c, "wl_compositor", 4)
19 wm := bindProtocol(t, c, "xdg_wm_base")
20 shm := bindProtocol(t, c, "wl_shm")
21 registerProtocol(t, c, shm)
22 surf, xdg, top := c.AllocateID(), c.AllocateID(), c.AllocateID()
23 requestProtocol(t, c, comp, wayland.CompositorRequestCreateSurface, surf)
24 registerProtocol(t, c, surf)
25 requestProtocol(t, c, wm, xdgshell.WmBaseRequestGetXdgSurface, xdg, surf)
26 serials := make(chan uint32, 8)
27 xp := &configureProxy{serial: serials}
28 xp.SetID(xdg)
29 registerWireProxy(c, xp)
30 registerProtocol(t, c, top)
31 requestProtocol(t, c, xdg, xdgshell.SurfaceRequestGetToplevel, top)
32 requestProtocol(t, c, surf, wayland.SurfaceRequestCommit)
33 if err := c.Roundtrip(); err != nil {
34 t.Fatal(err)
35 }
36 requestProtocol(t, c, xdg, xdgshell.SurfaceRequestAckConfigure, <-serials)
37 fd, err := unix.MemfdCreate("damage", 0)
38 if err != nil {
39 t.Fatal(err)
40 }
41 defer unix.Close(fd)
42 if err := unix.Ftruncate(fd, 2*16*16*4); err != nil {
43 t.Fatal(err)
44 }
45 pool := c.AllocateID()
46 registerProtocol(t, c, pool)
47 if err := wireRequest(c, shm, uint16(wayland.ShmRequestCreatePool), []int{fd}, pool, int32(2*16*16*4)); err != nil {
48 t.Fatal(err)
49 }
50 bufs := [2]uint32{c.AllocateID(), c.AllocateID()}
51 for i, b := range bufs {
52 registerProtocol(t, c, b)
53 requestProtocol(t, c, pool, wayland.ShmPoolRequestCreateBuffer, b, int32(i*16*16*4), int32(16), int32(16), int32(64), uint32(0))
54 }
55 next := func() ports.SurfaceContent {
56 t.Helper()
57 if err := c.Roundtrip(); err != nil {
58 t.Fatal(err)
59 }
60 deadline := time.After(2 * time.Second)
61 for {
62 select {
63 case got := <-contents:
64 if got.Width == 16 {
65 return got
66 }
67 case <-deadline:
68 t.Fatal("no content")
69 }
70 }
71 }
72 // A new size: full.
73 requestProtocol(t, c, surf, wayland.SurfaceRequestAttach, bufs[0], int32(0), int32(0))
74 requestProtocol(t, c, surf, wayland.SurfaceRequestDamageBuffer, int32(0), int32(0), int32(4), int32(4))
75 requestProtocol(t, c, surf, wayland.SurfaceRequestCommit)
76 mapped(t, events, 2*time.Second)
77 first := next()
78 if h := first.DamageHistory; len(h) == 0 || h[len(h)-1].Seq != first.Seq || !h[len(h)-1].Full {
79 t.Fatalf("resize: %+v", h)
80 }
81 // Buffer and surface damage, clipped to the buffer.
82 requestProtocol(t, c, surf, wayland.SurfaceRequestAttach, bufs[1], int32(0), int32(0))
83 requestProtocol(t, c, surf, wayland.SurfaceRequestDamageBuffer, int32(2), int32(3), int32(4), int32(5))
84 requestProtocol(t, c, surf, wayland.SurfaceRequestDamage, int32(14), int32(14), int32(1<<30), int32(1<<30))
85 requestProtocol(t, c, surf, wayland.SurfaceRequestCommit)
86 second := next()
87 got, ok := second.DamageSince(first.Seq)
88 want := []ports.Rect{{X: 2, Y: 3, W: 4, H: 5}, {X: 14, Y: 14, W: 2, H: 2}}
89 if !ok || len(got) != 2 || got[0] != want[0] || got[1] != want[1] {
90 t.Fatalf("damage %v %v", got, ok)
91 }
92 // Same buffer size, new logical size (buffer scale): full.
93 requestProtocol(t, c, surf, wayland.SurfaceRequestAttach, bufs[0], int32(0), int32(0))
94 requestProtocol(t, c, surf, wayland.SurfaceRequestSetBufferScale, int32(2))
95 requestProtocol(t, c, surf, wayland.SurfaceRequestDamageBuffer, int32(0), int32(0), int32(1), int32(1))
96 requestProtocol(t, c, surf, wayland.SurfaceRequestCommit)
97 scaled := next()
98 if _, ok := scaled.DamageSince(second.Seq); ok {
99 t.Fatal("logical resize kept partial damage")
100 }
101 second = scaled
102 // No damage with a new buffer: full.
103 requestProtocol(t, c, surf, wayland.SurfaceRequestAttach, bufs[0], int32(0), int32(0))
104 requestProtocol(t, c, surf, wayland.SurfaceRequestCommit)
105 third := next()
106 if _, ok := third.DamageSince(second.Seq); ok {
107 t.Fatal("undamaged new buffer taken as unchanged")
108 }
109}