1use api::units::{LayoutToPictureTransform, PicturePixel, PictureToLayoutTransform};
2use crate::{FastHashMap, frame_allocator::FrameMemory, gpu_types::VECS_PER_TRANSFORM};
3use crate::internal_types::FrameVec;
4use crate::spatial_tree::{SpatialNodeIndex, SpatialTree};
5use crate::util::{TransformedRectKind, MatrixHelpers};
6
7#[derive(Copy, Clone, PartialEq, MallocSizeOf)]
15#[cfg_attr(feature = "capture", derive(Serialize))]
16#[cfg_attr(feature = "replay", derive(Deserialize))]
17#[repr(C)]
18pub struct GpuTransformId(pub u32);
19
20impl GpuTransformId {
21 pub const IDENTITY: Self = GpuTransformId(0);
23 const INDEX_MASK: u32 = 0x003fffff;
24
25 const AXIS_ALIGNED_2D_BIT: u32 = 1 << 23;
31 const SCALE_OFFSET_2D_BIT: u32 = 1 << 22;
33
34 pub fn transform_kind(&self) -> TransformedRectKind {
36 if (self.0 & Self::AXIS_ALIGNED_2D_BIT) == 0 {
37 TransformedRectKind::AxisAligned
38 } else {
39 TransformedRectKind::Complex
40 }
41 }
42
43 pub fn is_2d_axis_aligned(&self) -> bool {
46 self.0 & Self::AXIS_ALIGNED_2D_BIT == 0
47 }
48
49 pub fn is_2d_scale_offset(&self) -> bool {
51 self.0 & Self::SCALE_OFFSET_2D_BIT == 0
52 }
53
54 pub fn metadata(&self) -> TransformMetadata {
55 TransformMetadata {
56 is_2d_axis_aligned: self.is_2d_axis_aligned(),
57 is_2d_scale_offset: self.is_2d_scale_offset(),
58 }
59 }
60
61 pub fn override_transform_kind(&self, kind: TransformedRectKind) -> Self {
66 GpuTransformId((self.0 & (1 << 23)) | ((kind as u32) << 23))
67 }
68}
69
70impl std::fmt::Debug for GpuTransformId {
71 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
72 if *self == Self::IDENTITY {
73 write!(f, "<identity>")
74 } else {
75 let index = self.0 & Self::INDEX_MASK;
76 write!(f, "#{index}")?;
77 let flag_bits = Self::AXIS_ALIGNED_2D_BIT | Self::SCALE_OFFSET_2D_BIT;
78 if self.0 & flag_bits != flag_bits {
79 let axis_aligned = if self.is_2d_axis_aligned() { "axis-aligned" } else { "" };
80 let scale_offset = if self.is_2d_scale_offset() { "scale-offset" } else { "" };
81 write!(f, "({axis_aligned} {scale_offset})")?;
82 }
83 Ok(())
84 }
85 }
86}
87
88
89#[derive(Debug, Clone)]
91#[cfg_attr(feature = "capture", derive(Serialize))]
92#[cfg_attr(feature = "replay", derive(Deserialize))]
93#[repr(C)]
94pub struct TransformData {
95 transform: LayoutToPictureTransform,
96 inv_transform: PictureToLayoutTransform,
97}
98
99impl TransformData {
100 fn invalid() -> Self {
101 TransformData {
102 transform: LayoutToPictureTransform::identity(),
103 inv_transform: PictureToLayoutTransform::identity(),
104 }
105 }
106}
107
108#[derive(Copy, Clone)]
110pub struct TransformMetadata {
111 pub is_2d_axis_aligned: bool,
112 pub is_2d_scale_offset: bool,
113}
114
115impl TransformMetadata {
116 pub fn invalid() -> Self {
117 TransformMetadata {
118 is_2d_axis_aligned: true,
119 is_2d_scale_offset: true,
120 }
121 }
122
123 pub fn flags(&self) -> u32 {
124 let mut flags = 0;
125 if !self.is_2d_axis_aligned {
126 flags |= GpuTransformId::AXIS_ALIGNED_2D_BIT
127 };
128 if !self.is_2d_scale_offset {
129 flags |= GpuTransformId::SCALE_OFFSET_2D_BIT
130 };
131
132 flags
133 }
134}
135
136#[derive(Debug, Hash, Eq, PartialEq)]
137struct RelativeTransformKey {
138 from_index: SpatialNodeIndex,
139 to_index: SpatialNodeIndex,
140 scale: u32,
141 pre_scale: bool,
142}
143
144pub struct TransformPalette {
145 pub gpu: GpuTransforms,
146}
147
148impl TransformPalette {
149 pub fn new(
150 count: usize,
151 memory: &FrameMemory,
152 ) -> Self {
153 TransformPalette {
154 gpu: GpuTransforms::new(count, memory),
155 }
156 }
157
158 pub fn finish(self) -> FrameVec<TransformData> {
159 self.gpu.finish()
160 }
161}
162
163pub struct GpuTransforms {
171 transforms: FrameVec<TransformData>,
172 metadata: Vec<TransformMetadata>,
173 map: FastHashMap<RelativeTransformKey, usize>,
174}
175
176impl GpuTransforms {
177 fn new(
178 count: usize,
179 memory: &FrameMemory,
180 ) -> Self {
181 let _ = VECS_PER_TRANSFORM;
182
183 let mut transforms = memory.new_vec_with_capacity(count);
184 let mut metadata = Vec::with_capacity(count);
185
186 transforms.push(TransformData::invalid());
187 metadata.push(TransformMetadata::invalid());
188
189 GpuTransforms {
190 transforms,
191 metadata,
192 map: FastHashMap::default(),
193 }
194 }
195
196 fn finish(self) -> FrameVec<TransformData> {
197 self.transforms
198 }
199
200 fn get_index(
201 &mut self,
202 child_index: SpatialNodeIndex,
203 parent_index: SpatialNodeIndex,
204 mut scale: Option<f32>,
205 pre_scale: bool,
206 spatial_tree: &SpatialTree,
207 ) -> usize {
208 if scale == Some(1.0) {
209 scale = None;
210 }
211
212 if child_index == parent_index && scale.is_none() {
214 return 0;
215 }
216
217 let scale_key = scale.map(|s| s.to_bits()).unwrap_or(0);
218
219 let key = RelativeTransformKey {
220 from_index: child_index,
221 to_index: parent_index,
222 scale: scale_key,
223 pre_scale,
224 };
225
226 let metadata = &mut self.metadata;
227 let transforms = &mut self.transforms;
228
229 *self.map.entry(key).or_insert_with(|| {
230 let transform = spatial_tree.get_relative_transform(
231 child_index,
232 parent_index,
233 );
234
235 let is_2d_axis_aligned = transform.is_2d_axis_aligned();
236 let is_2d_scale_offset = transform.is_2d_scale_translation();
237
238 let transform = transform
239 .into_transform()
240 .with_destination::<PicturePixel>();
241
242 register_gpu_transform(
243 metadata,
244 transforms,
245 transform,
246 scale,
247 pre_scale,
248 TransformMetadata {
249 is_2d_axis_aligned,
250 is_2d_scale_offset,
251 }
252 )
253 })
254 }
255
256 pub fn get_id(
261 &mut self,
262 from_index: SpatialNodeIndex,
263 to_index: SpatialNodeIndex,
264 spatial_tree: &SpatialTree,
265 ) -> GpuTransformId {
266 let index = self.get_index(
267 from_index,
268 to_index,
269 None,
270 false,
271 spatial_tree,
272 );
273
274 let flags = self.metadata[index].flags();
275
276 GpuTransformId((index as u32) | flags)
277 }
278
279 pub fn get_id_with_post_scale(
280 &mut self,
281 from_index: SpatialNodeIndex,
282 to_index: SpatialNodeIndex,
283 scale: f32,
284 spatial_tree: &SpatialTree,
285 ) -> GpuTransformId {
286 let index = self.get_index(
287 from_index,
288 to_index,
289 Some(scale),
290 false,
291 spatial_tree,
292 );
293
294 let flags = self.metadata[index].flags();
295
296 GpuTransformId((index as u32) | flags)
297 }
298
299 pub fn get_id_with_pre_scale(
300 &mut self,
301 scale: f32,
302 from_index: SpatialNodeIndex,
303 to_index: SpatialNodeIndex,
304 spatial_tree: &SpatialTree,
305 ) -> GpuTransformId {
306 let index = self.get_index(
307 from_index,
308 to_index,
309 Some(scale),
310 true,
311 spatial_tree,
312 );
313
314 let flags = self.metadata[index].flags();
315
316 GpuTransformId((index as u32) | flags)
317 }
318
319 pub fn get_custom(
320 &mut self,
321 transform: LayoutToPictureTransform,
322 ) -> GpuTransformId {
323 let is_2d_scale_offset = transform.is_2d_scale_translation();
324 let is_axis_aligned = transform.preserves_2d_axis_alignment();
325 let metadata = TransformMetadata {
326 is_2d_scale_offset,
327 is_2d_axis_aligned: is_axis_aligned,
328 };
329 let index = register_gpu_transform(
330 &mut self.metadata,
331 &mut self.transforms,
332 transform,
333 None,
334 false,
335 metadata,
336 );
337
338 GpuTransformId((index as u32) | metadata.flags())
339 }
340}
341
342fn register_gpu_transform(
345 metadatas: &mut Vec<TransformMetadata>,
346 transforms: &mut FrameVec<TransformData>,
347 mut transform: LayoutToPictureTransform,
348 scale: Option<f32>,
349 pre_scale: bool,
350 metadata: TransformMetadata,
351) -> usize {
352 if let Some(scale) = scale {
353 if pre_scale {
354 transform = transform.pre_scale(scale, scale, 1.0);
355 } else {
356 transform = transform.then_scale(scale, scale, 1.0);
357 }
358 }
359 let inv_transform = transform
362 .inverse()
363 .unwrap_or_else(PictureToLayoutTransform::identity);
364
365 let data = TransformData {
366 transform,
367 inv_transform,
368 };
369
370 let index = transforms.len();
371 metadatas.push(metadata);
372 transforms.push(data);
373
374 index
375}