1
0
Fork 0
forked from wry/wry

it: add frame callback test

This commit is contained in:
Julian Orth 2025-09-03 12:15:05 +02:00
parent fbef86e928
commit 8a5f1e1e37
3 changed files with 111 additions and 2 deletions

View file

@ -3,14 +3,14 @@ use {
ifs::wl_surface::WlSurface,
it::{
test_error::{TestError, TestResult},
test_ifs::test_region::TestRegion,
test_ifs::{test_callback::TestCallback, test_region::TestRegion},
test_object::TestObject,
test_transport::TestTransport,
test_utils::test_expected_event::TEEH,
testrun::ParseFull,
},
utils::buffd::MsgParser,
wire::{WlBufferId, WlSurfaceId, wl_surface::*},
wire::{WlBufferId, WlCallbackId, WlSurfaceId, wl_surface::*},
},
std::{cell::Cell, rc::Rc},
};
@ -89,6 +89,22 @@ impl TestSurface {
Ok(())
}
pub fn frame(&self) -> Result<Rc<TestCallback>, TestError> {
let id: WlCallbackId = self.tran.id();
let callback = Rc::new(TestCallback {
id,
_tran: self.tran.clone(),
handler: Cell::new(None),
done: Cell::new(false),
});
self.tran.add_obj(callback.clone())?;
self.tran.send(Frame {
self_id: self.id,
callback: callback.id,
})?;
Ok(callback)
}
pub fn commit(&self) -> Result<(), TestError> {
self.tran.send(Commit { self_id: self.id })?;
Ok(())

View file

@ -78,6 +78,7 @@ mod t0044_stacked_focus;
mod t0045_content_type;
mod t0046_buffer_release;
mod t0047_surface_damage;
mod t0048_frame_callback;
pub trait TestCase: Sync {
fn name(&self) -> &'static str;
@ -144,5 +145,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> {
t0045_content_type,
t0046_buffer_release,
t0047_surface_damage,
t0048_frame_callback,
}
}

View file

@ -0,0 +1,91 @@
use {
crate::it::{test_error::TestResult, testrun::TestRun},
std::rc::Rc,
};
testcase!();
/// Test wl_surface.frame callbacks
/// This test verifies that the compositor sends wl_callback.done events after the vblank event.
/// According to the Wayland protocol, frame callbacks should be fired to indicate when
/// it's a good time to start drawing the next frame, and they should be posted after
/// the compositor has finished presenting the previous frame (i.e., after vblank).
async fn test(run: Rc<TestRun>) -> TestResult {
run.backend.install_default()?;
let client = run.create_client().await?;
// Create a visible window so frame callbacks can be triggered
let window = client.create_window().await?;
window.map().await?;
client.sync().await;
// Test 1: Basic frame callback functionality
let surface = &window.surface.surface;
let callback1 = surface.frame()?;
surface.commit()?;
client.sync().await;
// Manually trigger vblank event to simulate frame completion
let connector_id = run.backend.default_connector.id;
// Trigger vblank manually - this processes frame callbacks
run.state.vblank(connector_id);
client.sync().await;
// The frame callback should have been fired after vblank
tassert!(callback1.done.get());
// Test 2: Multiple frame callbacks
let callback2 = surface.frame()?;
let callback3 = surface.frame()?;
surface.commit()?;
client.sync().await;
// Before triggering vblank, callbacks should not be done yet
tassert!(!callback2.done.get());
tassert!(!callback3.done.get());
// Trigger vblank manually - this processes frame callbacks
run.state.vblank(connector_id);
client.sync().await;
// Both callbacks should be done after vblank
tassert!(callback2.done.get());
tassert!(callback3.done.get());
// Test 3: Frame callbacks on invisible surface should not be processed
// Create a new surface but don't make it visible
let invisible_surface = client.comp.create_surface().await?;
let buffer = client
.spbm
.create_buffer(crate::theme::Color::from_srgb(255, 0, 0))?;
invisible_surface.attach(buffer.id)?;
let callback_invisible = invisible_surface.frame()?;
invisible_surface.commit()?;
client.sync().await;
// Trigger vblank manually - this processes frame callbacks
run.state.vblank(connector_id);
client.sync().await;
// Frame callback on invisible surface should not be processed
tassert!(!callback_invisible.done.get());
// Test 4: Frame callback timing - verify they happen after vblank
let callback_timing = surface.frame()?;
surface.commit()?;
client.sync().await;
// The callback should not be done immediately after commit
tassert!(!callback_timing.done.get());
// Trigger vblank manually - this processes frame callbacks
run.state.vblank(connector_id);
client.sync().await;
// Now it should be done
tassert!(callback_timing.done.get());
Ok(())
}