ferroui_base/rendering/composition/server/server_composition_visual/
readback.rs1use super::ServerCompositionVisual;
33use crate::platform::LtrbRect;
34use crate::Matrix;
35use std::sync::atomic::{AtomicU64, Ordering};
36use std::sync::{Mutex, PoisonError};
37
38#[derive(Clone, Copy, Debug, PartialEq)]
40pub struct ReadbackData {
41 pub matrix: Matrix,
42 pub revision: u64,
43 pub target_id: i64,
44 pub visible: bool,
45 pub transformed_subtree_bounds: Option<LtrbRect>,
46}
47
48struct Slot {
49 revision: AtomicU64,
50 data: Mutex<ReadbackData>,
51}
52
53impl Slot {
54 fn new() -> Self {
55 Self {
56 revision: AtomicU64::new(u64::MAX),
57 data: Mutex::new(ReadbackData {
58 matrix: Matrix::IDENTITY,
59 revision: u64::MAX,
60 target_id: 0,
61 visible: false,
62 transformed_subtree_bounds: None,
63 }),
64 }
65 }
66
67 fn read(&self) -> ReadbackData {
68 *self.data.lock().unwrap_or_else(PoisonError::into_inner)
69 }
70}
71
72pub struct VisualReadback {
74 readback0: Slot,
75 readback1: Slot,
76}
77
78impl Default for VisualReadback {
79 fn default() -> Self {
80 Self::new()
81 }
82}
83
84impl VisualReadback {
85 pub fn new() -> Self {
86 Self { readback0: Slot::new(), readback1: Slot::new() }
87 }
88
89 pub fn get_readback(&self, reader_revision: u64) -> Option<ReadbackData> {
90 let slot0_revision = self.readback0.revision.load(Ordering::SeqCst);
91 let slot1_revision = self.readback1.revision.load(Ordering::SeqCst);
92
93 if slot0_revision <= reader_revision && slot1_revision <= reader_revision {
94 return Some(if slot1_revision > slot0_revision { self.readback1.read() } else { self.readback0.read() });
96 }
97
98 if slot0_revision <= reader_revision {
99 return Some(self.readback0.read());
100 }
101
102 if slot1_revision <= reader_revision {
103 return Some(self.readback1.read());
104 }
105
106 None
108 }
109
110 pub fn update_readback(&self, writer_revision: u64, reader_revision: u64, mut data: ReadbackData) {
111 let revision0 = self.readback0.revision.load(Ordering::SeqCst);
112 let revision1 = self.readback1.revision.load(Ordering::SeqCst);
113 let slot = if revision0 > reader_revision {
114 &self.readback0
116 } else if revision1 > reader_revision {
117 &self.readback1
119 } else if revision0 < revision1 {
120 &self.readback0
122 } else {
123 &self.readback1
124 };
125
126 let mut guard = slot.data.lock().unwrap_or_else(PoisonError::into_inner);
127 slot.revision.store(writer_revision, Ordering::SeqCst);
128 data.revision = writer_revision;
129 *guard = data;
130 }
131}
132
133impl ServerCompositionVisual {
134 pub(super) fn enqueue_for_readback_update(&self) {
135 if !self.enqueued_for_readback_update.get() {
136 if let (Some(compositor), Some(this)) = (self.compositor(), self.rc()) {
137 self.enqueued_for_readback_update.set(true);
138 compositor.enqueue_visual_for_readback_update_pass(this);
139 }
140 }
141 }
142
143 pub fn get_readback(&self, reader_revision: u64) -> Option<ReadbackData> {
144 self.readback.get_readback(reader_revision)
145 }
146
147 pub fn update_readback(&self, writer_revision: u64, reader_revision: u64) {
148 self.enqueued_for_readback_update.set(false);
149 self.readback.update_readback(
150 writer_revision,
151 reader_revision,
152 ReadbackData {
153 matrix: self.own_transform.get().unwrap_or(Matrix::IDENTITY),
154 revision: writer_revision,
155 target_id: self.root().map_or(-1, |root| root.id()),
156 transformed_subtree_bounds: self.transformed_sub_tree_bounds.get(),
157 visible: self.visible(),
158 },
159 );
160 }
161}