1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use crate::it::test_client::TestClientExt;
use crate::it::test_error::TestError;
use crate::it::test_error::TestResult;
use crate::it::testrun::TestRun;
use crate::theme::Color;
use std::rc::Rc;
testcase!();
/// Test wp_fifo_v1 protocol implementation
/// This test verifies that the compositor correctly implements the fifo-v1 protocol
/// for synchronizing surface updates with display refresh cycles.
async fn test(run: Rc<TestRun>) -> TestResult {
run.backend.install_default().await?;
let client = run.create_client()?;
// Create a visible window so fifo constraints can be tested
let window = client.create_window().await?;
window.map().await?;
client.sync().await;
let surface = &window.surface.surface;
let connector_id = run.backend.default_connector.id;
// Get a fifo object for the surface
let fifo = client.get_fifo(surface);
client.sync().await;
// Test 1: Basic fifo barrier functionality without wait_barrier
// This should not block the commit - the old buffer should be released immediately
fifo.set_barrier();
let buffer1 = client.create_single_pixel_buffer(Color::from_srgb(255, 0, 0));
surface.attach(buffer1.id);
surface.commit();
client.sync().await;
// Test 1a: Critical test - without wait_barrier, commit should be applied immediately
let buffer1a = client.create_single_pixel_buffer(Color::from_srgb(255, 128, 0));
// Reset buffer tracking to detect when buffer1 gets released
buffer1.released.set(false);
// Attach new buffer and commit WITHOUT wait_barrier
surface.attach(buffer1a.id);
surface.commit();
client.sync().await;
// WITHOUT wait_barrier, the commit should be applied immediately even if barrier is set
// So buffer1 should be released immediately, without needing a vblank
if !buffer1.released.get() {
return Err(TestError::new(
"Without wait_barrier, commit should be applied immediately - buffer1 was not released",
));
}
// Test 2: Critical test - wait_barrier SHOULD block commit until next after_latch
// This contrasts with Test 1a above where commits were applied immediately
// Set the barrier and immediately test wait_barrier (without intermediate commits that might clear it)
fifo.set_barrier();
fifo.wait_barrier();
let buffer2_current = client.create_single_pixel_buffer(Color::from_srgb(0, 255, 0));
let buffer2_next = client.create_single_pixel_buffer(Color::from_srgb(0, 0, 255));
// First attach current buffer
surface.attach(buffer2_current.id);
surface.commit();
client.sync().await;
// Reset tracking for the buffer we want to monitor
buffer2_current.released.set(false);
// Now attach the new buffer - this should trigger the wait_barrier blocking
surface.attach(buffer2_next.id);
surface.commit();
client.sync().await;
// CRITICAL: The commit should be blocked, so buffer2_current should NOT be released yet
if buffer2_current.released.get() {
return Err(TestError::new(
"wait_barrier did not block the commit - buffer2_current was released immediately",
));
}
// The commit was successfully blocked! This proves wait_barrier works.
// Now trigger after_latch to clear the barrier and apply the queued commit
run.state.latch(connector_id);
client.sync().await;
// After after_latch, the barrier should be cleared and the commit applied
if !buffer2_current.released.get() {
return Err(TestError::new(
"after_latch should have cleared barrier and applied commit - buffer2_current was not released",
));
}
// Test 3: Test tearing mode - barrier should be cleared on vblank instead of immediately
fifo.set_barrier();
fifo.wait_barrier();
let buffer3_current = client.create_single_pixel_buffer(Color::from_srgb(128, 128, 0));
let buffer3_next = client.create_single_pixel_buffer(Color::from_srgb(0, 128, 128));
// First attach current buffer
surface.attach(buffer3_current.id);
surface.commit();
client.sync().await;
// Reset tracking for the buffer we want to monitor
buffer3_current.released.set(false);
// Now attach the new buffer - this should trigger the wait_barrier blocking
surface.attach(buffer3_next.id);
surface.commit();
client.sync().await;
// Verify the commit is blocked
if buffer3_current.released.get() {
return Err(TestError::new(
"wait_barrier did not block the commit in tearing test - buffer3_current was released immediately",
));
}
// Trigger latch with tearing=true - this should defer clearing to vblank
run.state.latch_tearing(connector_id);
client.sync().await;
// With tearing=true, the barrier should NOT be cleared yet, commit should still be blocked
if buffer3_current.released.get() {
return Err(TestError::new(
"In tearing mode, latch should not clear barrier immediately - buffer3_current was released",
));
}
// Now trigger vblank - this should clear the barrier and apply the commit
run.state.vblank(connector_id);
client.sync().await;
// After vblank, the commit should be applied
if !buffer3_current.released.get() {
return Err(TestError::new(
"vblank should have cleared barrier and applied commit - buffer3_current was not released",
));
}
Ok(())
}