use super::ServerCompositionVisual;
use crate::platform::LtrbRect;
use crate::Matrix;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Mutex, PoisonError};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ReadbackData {
pub matrix: Matrix,
pub revision: u64,
pub target_id: i64,
pub visible: bool,
pub transformed_subtree_bounds: Option<LtrbRect>,
}
struct Slot {
revision: AtomicU64,
data: Mutex<ReadbackData>,
}
impl Slot {
fn new() -> Self {
Self {
revision: AtomicU64::new(u64::MAX),
data: Mutex::new(ReadbackData {
matrix: Matrix::IDENTITY,
revision: u64::MAX,
target_id: 0,
visible: false,
transformed_subtree_bounds: None,
}),
}
}
fn read(&self) -> ReadbackData {
*self.data.lock().unwrap_or_else(PoisonError::into_inner)
}
}
pub struct VisualReadback {
readback0: Slot,
readback1: Slot,
}
impl Default for VisualReadback {
fn default() -> Self {
Self::new()
}
}
impl VisualReadback {
pub fn new() -> Self {
Self { readback0: Slot::new(), readback1: Slot::new() }
}
pub fn get_readback(&self, reader_revision: u64) -> Option<ReadbackData> {
let slot0_revision = self.readback0.revision.load(Ordering::SeqCst);
let slot1_revision = self.readback1.revision.load(Ordering::SeqCst);
if slot0_revision <= reader_revision && slot1_revision <= reader_revision {
return Some(if slot1_revision > slot0_revision { self.readback1.read() } else { self.readback0.read() });
}
if slot0_revision <= reader_revision {
return Some(self.readback0.read());
}
if slot1_revision <= reader_revision {
return Some(self.readback1.read());
}
None
}
pub fn update_readback(&self, writer_revision: u64, reader_revision: u64, mut data: ReadbackData) {
let revision0 = self.readback0.revision.load(Ordering::SeqCst);
let revision1 = self.readback1.revision.load(Ordering::SeqCst);
let slot = if revision0 > reader_revision {
&self.readback0
} else if revision1 > reader_revision {
&self.readback1
} else if revision0 < revision1 {
&self.readback0
} else {
&self.readback1
};
let mut guard = slot.data.lock().unwrap_or_else(PoisonError::into_inner);
slot.revision.store(writer_revision, Ordering::SeqCst);
data.revision = writer_revision;
*guard = data;
}
}
impl ServerCompositionVisual {
pub(super) fn enqueue_for_readback_update(&self) {
if !self.enqueued_for_readback_update.get() {
if let (Some(compositor), Some(this)) = (self.compositor(), self.rc()) {
self.enqueued_for_readback_update.set(true);
compositor.enqueue_visual_for_readback_update_pass(this);
}
}
}
pub fn get_readback(&self, reader_revision: u64) -> Option<ReadbackData> {
self.readback.get_readback(reader_revision)
}
pub fn update_readback(&self, writer_revision: u64, reader_revision: u64) {
self.enqueued_for_readback_update.set(false);
self.readback.update_readback(
writer_revision,
reader_revision,
ReadbackData {
matrix: self.own_transform.get().unwrap_or(Matrix::IDENTITY),
revision: writer_revision,
target_id: self.root().map_or(-1, |root| root.id()),
transformed_subtree_bounds: self.transformed_sub_tree_bounds.get(),
visible: self.visible(),
},
);
}
}