it: add frame callback test
This commit is contained in:
parent
fbef86e928
commit
8a5f1e1e37
3 changed files with 111 additions and 2 deletions
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
91
src/it/tests/t0048_frame_callback.rs
Normal file
91
src/it/tests/t0048_frame_callback.rs
Normal 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(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue