use {
crate::{
it::{test_error::TestResult, testrun::TestRun},
rect::Rect,
},
std::rc::Rc,
};
testcase!();
async fn test(run: Rc<TestRun>) -> TestResult {
run.backend.install_default()?;
let client = run.create_client().await?;
let connector_id = run.backend.default_connector.id;
let connector_data = run.state.connectors.get(&connector_id).unwrap();
let surface = client.comp.create_surface().await?;
let buffer = client
.spbm
.create_buffer(crate::theme::Color::from_srgb(255, 0, 0))?;
surface.attach(buffer.id)?;
surface.commit()?; client.sync().await;
surface.damage(10, 10, 50, 50)?;
client.sync().await;
{
let (surface_damage, buffer_damage, damage_full) = surface.server.get_pending_damage();
tassert_eq!(surface_damage.len(), 1);
tassert_eq!(surface_damage[0], Rect::new_sized(10, 10, 50, 50).unwrap());
tassert!(buffer_damage.is_empty());
tassert!(!damage_full);
}
surface.commit()?;
client.sync().await;
{
let (surface_damage, buffer_damage, damage_full) = surface.server.get_pending_damage();
tassert!(surface_damage.is_empty());
tassert!(buffer_damage.is_empty());
tassert!(!damage_full);
}
surface.damage_buffer(20, 20, 30, 30)?;
client.sync().await;
{
let (surface_damage, buffer_damage, damage_full) = surface.server.get_pending_damage();
tassert!(surface_damage.is_empty());
tassert_eq!(buffer_damage.len(), 1);
tassert_eq!(buffer_damage[0], Rect::new_sized(20, 20, 30, 30).unwrap());
tassert!(!damage_full);
}
surface.commit()?;
client.sync().await;
{
let (surface_damage, buffer_damage, damage_full) = surface.server.get_pending_damage();
tassert!(surface_damage.is_empty());
tassert!(buffer_damage.is_empty());
tassert!(!damage_full);
}
surface.damage(5, 5, 10, 10)?;
surface.damage_buffer(15, 15, 10, 10)?;
surface.damage(25, 25, 10, 10)?;
client.sync().await;
{
let (surface_damage, buffer_damage, damage_full) = surface.server.get_pending_damage();
tassert_eq!(surface_damage.len(), 2);
tassert_eq!(buffer_damage.len(), 1);
tassert!(!damage_full);
}
surface.commit()?;
client.sync().await;
{
let (surface_damage, buffer_damage, damage_full) = surface.server.get_pending_damage();
tassert!(surface_damage.is_empty());
tassert!(buffer_damage.is_empty());
tassert!(!damage_full);
}
for i in 0..40 {
surface.damage(i * 2, i * 2, 1, 1)?;
}
client.sync().await;
{
let (_surface_damage, _buffer_damage, damage_full) = surface.server.get_pending_damage();
tassert!(damage_full); }
surface.commit()?;
client.sync().await;
{
let (surface_damage, buffer_damage, damage_full) = surface.server.get_pending_damage();
tassert!(surface_damage.is_empty());
tassert!(buffer_damage.is_empty());
tassert!(!damage_full);
}
let window = client.create_window().await?;
window.surface.attach(buffer.id)?;
window.map().await?;
client.sync().await;
let surface_pos = window.surface.server.buffer_abs_pos.get();
connector_data.damage.borrow_mut().clear();
let client_damage = Rect::new_sized(10, 10, 20, 20).unwrap();
window.surface.damage(
client_damage.x1(),
client_damage.y1(),
client_damage.width(),
client_damage.height(),
)?;
window.surface.commit()?;
client.sync().await;
{
let output_damage = connector_data.damage.borrow();
tassert!(!output_damage.is_empty());
let expected_damage = client_damage.move_(surface_pos.x1(), surface_pos.y1());
let mut found_exact_damage = false;
for &actual_damage in output_damage.iter() {
if actual_damage.x1() == expected_damage.x1()
&& actual_damage.y1() == expected_damage.y1()
&& actual_damage.x2() == expected_damage.x2()
&& actual_damage.y2() == expected_damage.y2()
{
found_exact_damage = true;
break;
}
}
if !found_exact_damage {
run.errors.push(format!(
"Expected output damage: x1={}, y1={}, x2={}, y2={} ({}x{})",
expected_damage.x1(),
expected_damage.y1(),
expected_damage.x2(),
expected_damage.y2(),
expected_damage.width(),
expected_damage.height()
));
run.errors.push(format!(
"Surface position: x1={}, y1={}",
surface_pos.x1(),
surface_pos.y1()
));
run.errors.push(format!(
"Client damage: x1={}, y1={}, x2={}, y2={} ({}x{})",
client_damage.x1(),
client_damage.y1(),
client_damage.x2(),
client_damage.y2(),
client_damage.width(),
client_damage.height()
));
run.errors.push("Actual output damage:".to_string());
for (i, &actual_damage) in output_damage.iter().enumerate() {
run.errors.push(format!(
" [{}]: x1={}, y1={}, x2={}, y2={} ({}x{})",
i,
actual_damage.x1(),
actual_damage.y1(),
actual_damage.x2(),
actual_damage.y2(),
actual_damage.width(),
actual_damage.height()
));
}
}
tassert!(found_exact_damage);
}
connector_data.damage.borrow_mut().clear();
let damage1 = Rect::new_sized(5, 5, 10, 10).unwrap();
let damage2 = Rect::new_sized(20, 25, 15, 8).unwrap();
window.surface.damage(
damage1.x1(),
damage1.y1(),
damage1.width(),
damage1.height(),
)?;
window.surface.damage(
damage2.x1(),
damage2.y1(),
damage2.width(),
damage2.height(),
)?;
window.surface.commit()?;
client.sync().await;
{
let output_damage = connector_data.damage.borrow();
tassert!(!output_damage.is_empty());
let expected_damage1 = damage1.move_(surface_pos.x1(), surface_pos.y1());
let expected_damage2 = damage2.move_(surface_pos.x1(), surface_pos.y1());
let mut found_damage1 = false;
let mut found_damage2 = false;
for &actual_damage in output_damage.iter() {
if actual_damage.x1() == expected_damage1.x1()
&& actual_damage.y1() == expected_damage1.y1()
&& actual_damage.x2() == expected_damage1.x2()
&& actual_damage.y2() == expected_damage1.y2()
{
found_damage1 = true;
}
if actual_damage.x1() == expected_damage2.x1()
&& actual_damage.y1() == expected_damage2.y1()
&& actual_damage.x2() == expected_damage2.x2()
&& actual_damage.y2() == expected_damage2.y2()
{
found_damage2 = true;
}
}
if !found_damage1 || !found_damage2 {
run.errors.push(format!("Multiple damage test failed:"));
run.errors.push(format!(
"Expected damage1: x1={}, y1={}, x2={}, y2={}",
expected_damage1.x1(),
expected_damage1.y1(),
expected_damage1.x2(),
expected_damage1.y2()
));
run.errors.push(format!(
"Expected damage2: x1={}, y1={}, x2={}, y2={}",
expected_damage2.x1(),
expected_damage2.y1(),
expected_damage2.x2(),
expected_damage2.y2()
));
run.errors.push(format!(
"Found damage1: {}, Found damage2: {}",
found_damage1, found_damage2
));
}
tassert!(found_damage1);
tassert!(found_damage2);
}
connector_data.damage.borrow_mut().clear();
let buffer_damage = Rect::new_sized(0, 0, 1, 1).unwrap(); window.surface.damage_buffer(
buffer_damage.x1(),
buffer_damage.y1(),
buffer_damage.width(),
buffer_damage.height(),
)?;
window.surface.commit()?;
client.sync().await;
{
let output_damage = connector_data.damage.borrow();
tassert!(!output_damage.is_empty());
let expected_buffer_damage = buffer_damage.move_(surface_pos.x1(), surface_pos.y1());
let mut found_exact_buffer_damage = false;
for &actual_damage in output_damage.iter() {
if actual_damage.x1() == expected_buffer_damage.x1()
&& actual_damage.y1() == expected_buffer_damage.y1()
&& actual_damage.x2() == expected_buffer_damage.x2()
&& actual_damage.y2() == expected_buffer_damage.y2()
{
found_exact_buffer_damage = true;
break;
}
}
tassert!(found_exact_buffer_damage);
}
connector_data.damage.borrow_mut().clear();
window.surface.viewport.set_destination(150, 100)?;
window.surface.damage_buffer(0, 0, 1, 1)?; window.surface.commit()?;
client.sync().await;
{
let output_damage = connector_data.damage.borrow();
tassert!(!output_damage.is_empty());
let expected_scaled_damage = Rect::new_sized(0, 0, 150, 100).unwrap();
let expected_output_damage =
expected_scaled_damage.move_(surface_pos.x1(), surface_pos.y1());
let mut found_viewport_scaled_damage = false;
for &actual_damage in output_damage.iter() {
if actual_damage.x1() == expected_output_damage.x1()
&& actual_damage.y1() == expected_output_damage.y1()
&& actual_damage.x2() == expected_output_damage.x2()
&& actual_damage.y2() == expected_output_damage.y2()
{
found_viewport_scaled_damage = true;
break;
}
}
if !found_viewport_scaled_damage {
run.errors
.push("Viewport-scaled buffer damage verification failed:".to_string());
run.errors.push(format!(
"Expected output damage: x1={}, y1={}, x2={}, y2={} ({}x{})",
expected_output_damage.x1(),
expected_output_damage.y1(),
expected_output_damage.x2(),
expected_output_damage.y2(),
expected_output_damage.width(),
expected_output_damage.height()
));
run.errors.push("Actual output damage:".to_string());
for (i, &actual_damage) in output_damage.iter().enumerate() {
run.errors.push(format!(
" [{}]: x1={}, y1={}, x2={}, y2={} ({}x{})",
i,
actual_damage.x1(),
actual_damage.y1(),
actual_damage.x2(),
actual_damage.y2(),
actual_damage.width(),
actual_damage.height()
));
}
}
tassert!(found_viewport_scaled_damage);
}
let rotation_window = client.create_window().await?;
rotation_window.map().await?;
client.sync().await;
rotation_window.surface.viewport.set_destination(0, 0)?;
let rotation_buffer = client.shm.create_buffer(4, 2)?;
rotation_window.surface.attach(rotation_buffer.buffer.id)?;
rotation_window.surface.set_buffer_transform(1)?; rotation_window.surface.commit()?; client.sync().await;
let rotation_surface_pos = rotation_window.surface.server.buffer_abs_pos.get();
connector_data.damage.borrow_mut().clear();
rotation_window.surface.damage_buffer(0, 0, 4, 2)?; rotation_window.surface.commit()?;
client.sync().await;
{
let output_damage = connector_data.damage.borrow();
tassert!(!output_damage.is_empty());
let expected_rotated_damage = Rect::new_sized(0, 0, 2, 4).unwrap(); let expected_output_damage =
expected_rotated_damage.move_(rotation_surface_pos.x1(), rotation_surface_pos.y1());
let mut found_exact_rotation_damage = false;
for &actual_damage in output_damage.iter() {
if actual_damage.x1() == expected_output_damage.x1()
&& actual_damage.y1() == expected_output_damage.y1()
&& actual_damage.x2() == expected_output_damage.x2()
&& actual_damage.y2() == expected_output_damage.y2()
{
found_exact_rotation_damage = true;
break;
}
}
if !found_exact_rotation_damage {
run.errors
.push("Buffer transform rotation exact coordinate test failed:".to_string());
run.errors.push(format!(
"Expected exact output damage: x1={}, y1={}, x2={}, y2={} ({}x{})",
expected_output_damage.x1(),
expected_output_damage.y1(),
expected_output_damage.x2(),
expected_output_damage.y2(),
expected_output_damage.width(),
expected_output_damage.height()
));
run.errors.push(format!(
"Rotated surface position: x1={}, y1={}",
rotation_surface_pos.x1(),
rotation_surface_pos.y1()
));
run.errors
.push("Applied: 4x2 buffer + 90-degree rotation (no viewporter)".to_string());
run.errors
.push("Actual output damage from buffer transform rotation:".to_string());
for (i, &actual_damage) in output_damage.iter().enumerate() {
run.errors.push(format!(
" [{}]: x1={}, y1={}, x2={}, y2={} ({}x{})",
i,
actual_damage.x1(),
actual_damage.y1(),
actual_damage.x2(),
actual_damage.y2(),
actual_damage.width(),
actual_damage.height()
));
}
}
tassert!(found_exact_rotation_damage);
}
connector_data.damage.borrow_mut().clear();
window.surface.damage(0, 0, 0, 0)?; window.surface.commit()?;
client.sync().await;
Ok(())
}