1use alloc::{collections::BTreeMap, vec::Vec};
22use core::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
23
24use azul_css::props::{basic::LayoutSize, style::StyleTransformOrigin};
25
26use crate::{
27 dom::{DomId, NodeId},
28 id::NodeDataContainerRef,
29 resources::{OpacityKey, TransformKey},
30 styled_dom::StyledDom,
31 transform::{ComputedTransform3D, RotationMode, INITIALIZED, USE_AVX, USE_SSE},
32};
33
34#[derive(Default, Debug, Clone, PartialEq, PartialOrd)]
51pub struct GpuValueCache {
52 pub transform_keys: BTreeMap<NodeId, TransformKey>,
53 pub current_transform_values: BTreeMap<NodeId, ComputedTransform3D>,
54 pub opacity_keys: BTreeMap<NodeId, OpacityKey>,
55 pub current_opacity_values: BTreeMap<NodeId, f32>,
56 pub scrollbar_v_opacity_keys: BTreeMap<(DomId, NodeId), OpacityKey>,
57 pub scrollbar_h_opacity_keys: BTreeMap<(DomId, NodeId), OpacityKey>,
58 pub scrollbar_v_opacity_values: BTreeMap<(DomId, NodeId), f32>,
59 pub scrollbar_h_opacity_values: BTreeMap<(DomId, NodeId), f32>,
60}
61
62#[derive(Debug, Clone, PartialEq, PartialOrd)]
67pub enum GpuTransformKeyEvent {
68 Added(NodeId, TransformKey, ComputedTransform3D),
70 Changed(
72 NodeId,
73 TransformKey,
74 ComputedTransform3D,
75 ComputedTransform3D,
76 ),
77 Removed(NodeId, TransformKey),
79}
80
81impl GpuValueCache {
82 pub fn empty() -> Self {
84 Self::default()
85 }
86
87 #[must_use]
104 pub fn synchronize<'a>(&mut self, styled_dom: &StyledDom) -> GpuEventChanges {
105 let css_property_cache = styled_dom.get_css_property_cache();
106 let node_data = styled_dom.node_data.as_container();
107 let node_states = styled_dom.styled_nodes.as_container();
108
109 let default_transform_origin = StyleTransformOrigin::default();
110
111 #[cfg(target_arch = "x86_64")]
112 unsafe {
113 if !INITIALIZED.load(AtomicOrdering::SeqCst) {
114 use core::arch::x86_64::__cpuid;
115
116 let mut cpuid = __cpuid(0);
117 let n_ids = cpuid.eax;
118
119 if n_ids > 0 {
120 cpuid = __cpuid(1);
122 USE_SSE.store((cpuid.edx & (1_u32 << 25)) != 0, AtomicOrdering::SeqCst);
123 USE_AVX.store((cpuid.ecx & (1_u32 << 28)) != 0, AtomicOrdering::SeqCst);
124 }
125 INITIALIZED.store(true, AtomicOrdering::SeqCst);
126 }
127 }
128
129 let all_current_transform_events = (0..styled_dom.node_data.len())
131 .into_iter()
132 .filter_map(|node_id| {
133 let node_id = NodeId::new(node_id);
134 let styled_node_state = &node_states[node_id].styled_node_state;
135 let node_data = &node_data[node_id];
136 let current_transform = css_property_cache
137 .get_transform(node_data, &node_id, styled_node_state)?
138 .get_property()
139 .map(|t| {
140 let parent_size_width = 0.0;
143 let parent_size_height = 0.0;
144 let transform_origin = css_property_cache.get_transform_origin(
145 node_data,
146 &node_id,
147 styled_node_state,
148 );
149 let transform_origin = transform_origin
150 .as_ref()
151 .and_then(|o| o.get_property())
152 .unwrap_or(&default_transform_origin);
153
154 ComputedTransform3D::from_style_transform_vec(
155 t.as_ref(),
156 transform_origin,
157 parent_size_width,
158 parent_size_height,
159 RotationMode::ForWebRender,
160 )
161 });
162
163 let existing_transform = self.current_transform_values.get(&node_id);
164
165 match (existing_transform, current_transform) {
166 (None, None) => None, (None, Some(new)) => Some(GpuTransformKeyEvent::Added(
168 node_id,
169 TransformKey::unique(),
170 new,
171 )),
172 (Some(old), Some(new)) => Some(GpuTransformKeyEvent::Changed(
173 node_id,
174 self.transform_keys.get(&node_id).copied()?,
175 *old,
176 new,
177 )),
178 (Some(_old), None) => Some(GpuTransformKeyEvent::Removed(
179 node_id,
180 self.transform_keys.get(&node_id).copied()?,
181 )),
182 }
183 })
184 .collect::<Vec<GpuTransformKeyEvent>>();
185
186 for event in all_current_transform_events.iter() {
188 match &event {
189 GpuTransformKeyEvent::Added(node_id, key, matrix) => {
190 self.transform_keys.insert(*node_id, *key);
191 self.current_transform_values.insert(*node_id, *matrix);
192 }
193 GpuTransformKeyEvent::Changed(node_id, _key, _old_state, new_state) => {
194 self.current_transform_values.insert(*node_id, *new_state);
195 }
196 GpuTransformKeyEvent::Removed(node_id, _key) => {
197 self.transform_keys.remove(node_id);
198 self.current_transform_values.remove(node_id);
199 }
200 }
201 }
202
203 let all_current_opacity_events = (0..styled_dom.node_data.len())
205 .into_iter()
206 .filter_map(|node_id| {
207 let node_id = NodeId::new(node_id);
208 let styled_node_state = &node_states[node_id].styled_node_state;
209 let node_data = &node_data[node_id];
210 let current_opacity =
211 css_property_cache.get_opacity(node_data, &node_id, styled_node_state)?;
212 let current_opacity = current_opacity.get_property();
213 let existing_opacity = self.current_opacity_values.get(&node_id);
214
215 match (existing_opacity, current_opacity) {
216 (None, None) => None, (None, Some(new)) => Some(GpuOpacityKeyEvent::Added(
218 node_id,
219 OpacityKey::unique(),
220 new.inner.normalized(),
221 )),
222 (Some(old), Some(new)) => Some(GpuOpacityKeyEvent::Changed(
223 node_id,
224 self.opacity_keys.get(&node_id).copied()?,
225 *old,
226 new.inner.normalized(),
227 )),
228 (Some(_old), None) => Some(GpuOpacityKeyEvent::Removed(
229 node_id,
230 self.opacity_keys.get(&node_id).copied()?,
231 )),
232 }
233 })
234 .collect::<Vec<GpuOpacityKeyEvent>>();
235
236 for event in all_current_opacity_events.iter() {
238 match &event {
239 GpuOpacityKeyEvent::Added(node_id, key, opacity) => {
240 self.opacity_keys.insert(*node_id, *key);
241 self.current_opacity_values.insert(*node_id, *opacity);
242 }
243 GpuOpacityKeyEvent::Changed(node_id, _key, _old_state, new_state) => {
244 self.current_opacity_values.insert(*node_id, *new_state);
245 }
246 GpuOpacityKeyEvent::Removed(node_id, _key) => {
247 self.opacity_keys.remove(node_id);
248 self.current_opacity_values.remove(node_id);
249 }
250 }
251 }
252
253 GpuEventChanges {
254 transform_key_changes: all_current_transform_events,
255 opacity_key_changes: all_current_opacity_events,
256 scrollbar_opacity_changes: Vec::new(), }
258 }
259}
260
261#[derive(Debug, Clone, PartialEq, PartialOrd)]
266pub enum GpuScrollbarOpacityEvent {
267 VerticalAdded(DomId, NodeId, OpacityKey, f32),
269 VerticalChanged(DomId, NodeId, OpacityKey, f32, f32),
271 VerticalRemoved(DomId, NodeId, OpacityKey),
273 HorizontalAdded(DomId, NodeId, OpacityKey, f32),
275 HorizontalChanged(DomId, NodeId, OpacityKey, f32, f32),
277 HorizontalRemoved(DomId, NodeId, OpacityKey),
279}
280
281#[derive(Default, Debug, Clone, PartialEq, PartialOrd)]
286pub struct GpuEventChanges {
287 pub transform_key_changes: Vec<GpuTransformKeyEvent>,
289 pub opacity_key_changes: Vec<GpuOpacityKeyEvent>,
291 pub scrollbar_opacity_changes: Vec<GpuScrollbarOpacityEvent>,
293}
294
295impl GpuEventChanges {
296 pub fn empty() -> Self {
298 Self::default()
299 }
300
301 pub fn is_empty(&self) -> bool {
303 self.transform_key_changes.is_empty()
304 && self.opacity_key_changes.is_empty()
305 && self.scrollbar_opacity_changes.is_empty()
306 }
307
308 pub fn merge(&mut self, other: &mut Self) {
312 self.transform_key_changes
313 .extend(other.transform_key_changes.drain(..));
314 self.opacity_key_changes
315 .extend(other.opacity_key_changes.drain(..));
316 self.scrollbar_opacity_changes
317 .extend(other.scrollbar_opacity_changes.drain(..));
318 }
319}
320
321#[derive(Debug, Clone, PartialEq, PartialOrd)]
322pub enum GpuOpacityKeyEvent {
323 Added(NodeId, OpacityKey, f32),
324 Changed(NodeId, OpacityKey, f32, f32),
325 Removed(NodeId, OpacityKey),
326}