1use crate::internal_types::FastHashMap;
37use malloc_size_of::MallocSizeOf;
38use std::fmt::Debug;
39use std::hash::Hash;
40use std::marker::PhantomData;
41use std::{ops, u64};
42use crate::util::VecHelper;
43use crate::profiler::TransactionProfile;
44use peek_poke::PeekPoke;
45
46#[cfg_attr(feature = "capture", derive(Serialize))]
47#[cfg_attr(feature = "replay", derive(Deserialize))]
48#[derive(Debug, Copy, Clone, Hash, MallocSizeOf, PartialEq, Eq)]
49struct Epoch(u32);
50
51#[cfg_attr(feature = "capture", derive(Serialize))]
54#[cfg_attr(feature = "replay", derive(Deserialize))]
55#[derive(MallocSizeOf)]
56pub struct UpdateList<S> {
57 pub insertions: Vec<Insertion<S>>,
59
60 pub removals: Vec<Removal>,
62}
63
64#[cfg_attr(feature = "capture", derive(Serialize))]
65#[cfg_attr(feature = "replay", derive(Deserialize))]
66#[derive(MallocSizeOf)]
67pub struct Insertion<S> {
68 pub index: usize,
69 pub uid: ItemUid,
70 pub value: S,
71}
72
73#[cfg_attr(feature = "capture", derive(Serialize))]
74#[cfg_attr(feature = "replay", derive(Deserialize))]
75#[derive(MallocSizeOf)]
76pub struct Removal {
77 pub index: usize,
78 pub uid: ItemUid,
79}
80
81impl<S> UpdateList<S> {
82 fn new() -> UpdateList<S> {
83 UpdateList {
84 insertions: Vec::new(),
85 removals: Vec::new(),
86 }
87 }
88
89 fn take_and_preallocate(&mut self) -> UpdateList<S> {
90 UpdateList {
91 insertions: self.insertions.take_and_preallocate(),
92 removals: self.removals.take_and_preallocate(),
93 }
94 }
95}
96
97#[cfg_attr(feature = "capture", derive(Serialize))]
99#[cfg_attr(feature = "replay", derive(Deserialize))]
100#[derive(Copy, Clone, Eq, Hash, MallocSizeOf, PartialEq, PeekPoke, Default)]
101pub struct ItemUid {
102 uid: u64,
103}
104
105impl ItemUid {
106 pub fn get_uid(&self) -> u64 {
108 self.uid
109 }
110}
111
112impl std::fmt::Debug for ItemUid {
113 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
114 write!(f, "#{}", self.uid)
115 }
116}
117
118#[cfg_attr(feature = "capture", derive(Serialize))]
119#[cfg_attr(feature = "replay", derive(Deserialize))]
120#[derive(Hash, MallocSizeOf, PartialEq, Eq)]
121pub struct Handle<I> {
122 index: u32,
123 epoch: Epoch,
124 _marker: PhantomData<I>,
125}
126
127impl<I> std::fmt::Debug for Handle<I> {
128 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
129 if self.uid() == Self::INVALID.uid() {
131 write!(f, "<invalid>")
132 } else {
133 write!(f, "#{}:{}", self.index, self.epoch.0)
134 }
135 }
136}
137
138impl<I> Clone for Handle<I> {
139 fn clone(&self) -> Self {
140 Handle {
141 index: self.index,
142 epoch: self.epoch,
143 _marker: self._marker,
144 }
145 }
146}
147
148impl<I> Copy for Handle<I> {}
149
150impl<I> Handle<I> {
151 pub fn uid(&self) -> ItemUid {
152 ItemUid {
153 uid: ((self.index as u64) << 32) | self.epoch.0 as u64
156 }
157 }
158
159 pub const INVALID: Self = Handle { index: !0, epoch: Epoch(!0), _marker: PhantomData };
160}
161
162pub trait InternDebug {
163 fn on_interned(&self, _uid: ItemUid) {}
164}
165
166#[cfg_attr(feature = "capture", derive(Serialize))]
169#[cfg_attr(feature = "replay", derive(Deserialize))]
170#[derive(MallocSizeOf)]
171pub struct DataStore<I: Internable> {
172 items: Vec<Option<I::StoreData>>,
173}
174
175impl<I: Internable> Default for DataStore<I> {
176 fn default() -> Self {
177 DataStore {
178 items: Vec::new(),
179 }
180 }
181}
182
183impl<I: Internable> DataStore<I> {
184 pub fn apply_updates(
187 &mut self,
188 update_list: UpdateList<I::Key>,
189 profile: &mut TransactionProfile,
190 ) {
191 for insertion in update_list.insertions {
192 self.items
193 .entry(insertion.index)
194 .set(Some(insertion.value.into()));
195 }
196
197 for removal in update_list.removals {
198 self.items[removal.index] = None;
199 }
200
201 profile.set(I::PROFILE_COUNTER, self.items.len());
202 }
203}
204
205impl<I: Internable> ops::Index<Handle<I>> for DataStore<I> {
207 type Output = I::StoreData;
208 fn index(&self, handle: Handle<I>) -> &I::StoreData {
209 self.items[handle.index as usize].as_ref().expect("Bad datastore lookup")
210 }
211}
212
213impl<I: Internable> ops::IndexMut<Handle<I>> for DataStore<I> {
216 fn index_mut(&mut self, handle: Handle<I>) -> &mut I::StoreData {
217 self.items[handle.index as usize].as_mut().expect("Bad datastore lookup")
218 }
219}
220
221#[cfg_attr(feature = "capture", derive(Serialize))]
222#[cfg_attr(feature = "replay", derive(Deserialize))]
223#[derive(MallocSizeOf)]
224struct ItemDetails<I> {
225 interned_epoch: Epoch,
227 last_used_epoch: Epoch,
229 index: usize,
231 _marker: PhantomData<I>,
233}
234
235impl<I> ItemDetails<I> {
236 fn create_handle(&self) -> Handle<I> {
238 Handle {
239 index: self.index as u32,
240 epoch: self.interned_epoch,
241 _marker: PhantomData,
242 }
243 }
244}
245
246#[cfg_attr(feature = "capture", derive(Serialize))]
252#[cfg_attr(feature = "replay", derive(Deserialize))]
253#[derive(MallocSizeOf)]
254pub struct Interner<I: Internable> {
255 map: FastHashMap<I::Key, ItemDetails<I>>,
257 free_list: Vec<usize>,
259 update_list: UpdateList<I::Key>,
261 current_epoch: Epoch,
263 local_data: Vec<I::InternData>,
266}
267
268impl<I: Internable> Default for Interner<I> {
269 fn default() -> Self {
270 Interner {
271 map: FastHashMap::default(),
272 free_list: Vec::new(),
273 update_list: UpdateList::new(),
274 current_epoch: Epoch(1),
275 local_data: Vec::new(),
276 }
277 }
278}
279
280impl<I: Internable> Interner<I> {
281 pub fn intern<F>(
289 &mut self,
290 data: &I::Key,
291 fun: F,
292 ) -> Handle<I> where F: FnOnce() -> I::InternData {
293 if let Some(details) = self.map.get_mut(data) {
297 details.last_used_epoch = self.current_epoch;
299 return details.create_handle();
301 }
302
303 let index = match self.free_list.pop() {
307 Some(index) => index,
308 None => self.local_data.len(),
309 };
310
311 let handle = Handle {
313 index: index as u32,
314 epoch: self.current_epoch,
315 _marker: PhantomData,
316 };
317
318 let uid = handle.uid();
319
320 self.update_list.insertions.push(Insertion {
322 index,
323 uid,
324 value: data.clone(),
325 });
326
327 #[cfg(debug_assertions)]
328 data.on_interned(uid);
329
330 self.map.insert(data.clone(), ItemDetails {
333 interned_epoch: self.current_epoch,
334 last_used_epoch: self.current_epoch,
335 index,
336 _marker: PhantomData,
337 });
338
339 self.local_data.entry(index).set(fun());
342
343 handle
344 }
345
346 pub fn end_frame_and_get_pending_updates(&mut self) -> UpdateList<I::Key> {
350 let mut update_list = self.update_list.take_and_preallocate();
351
352 let free_list = &mut self.free_list;
353 let current_epoch = self.current_epoch.0;
354
355 self.map.retain(|_, details| {
363 if details.last_used_epoch.0 + 10 < current_epoch {
364 free_list.push(details.index);
369 update_list.removals.push(Removal {
370 index: details.index,
371 uid: details.create_handle().uid(),
372 });
373 return false;
374 }
375
376 true
377 });
378
379 self.current_epoch = Epoch(self.current_epoch.0 + 1);
381
382 update_list
383 }
384}
385
386impl<I: Internable> ops::Index<Handle<I>> for Interner<I> {
388 type Output = I::InternData;
389 fn index(&self, handle: Handle<I>) -> &I::InternData {
390 &self.local_data[handle.index as usize]
391 }
392}
393
394#[macro_export]
401macro_rules! enumerate_interners {
402 ($macro_name: ident) => {
403 $macro_name! {
404 clip: ClipIntern,
405 prim: RectanglePrim,
406 normal_border: NormalBorderPrim,
407 image_border: ImageBorder,
408 image: Image,
409 yuv_image: YuvImage,
410 line_decoration: LineDecoration,
411 linear_grad: LinearGradient,
412 radial_grad: RadialGradient,
413 conic_grad: ConicGradient,
414 picture: Picture,
415 text_run: TextRun,
416 filter_data: FilterDataIntern,
417 backdrop_capture: BackdropCapture,
418 backdrop_render: BackdropRender,
419 polygon: PolygonIntern,
420 box_shadow: BoxShadow,
421 }
422 }
423}
424
425macro_rules! declare_interning_memory_report {
426 ( $( $name:ident: $ty:ident, )+ ) => {
427 #[repr(C)]
429 #[derive(AddAssign, Clone, Debug, Default)]
430 pub struct InternerSubReport {
431 $(
432 pub $name: usize,
434 )+
435 }
436 }
437}
438
439enumerate_interners!(declare_interning_memory_report);
440
441#[repr(C)]
445#[derive(Clone, Debug, Default)]
446pub struct InterningMemoryReport {
447 pub interners: InternerSubReport,
449 pub data_stores: InternerSubReport,
451}
452
453impl ::std::ops::AddAssign for InterningMemoryReport {
454 fn add_assign(&mut self, other: InterningMemoryReport) {
455 self.interners += other.interners;
456 self.data_stores += other.data_stores;
457 }
458}
459
460mod dummy {
462 #[cfg(not(feature = "capture"))]
463 pub trait Serialize {}
464 #[cfg(not(feature = "capture"))]
465 impl<T> Serialize for T {}
466 #[cfg(not(feature = "replay"))]
467 pub trait Deserialize<'a> {}
468 #[cfg(not(feature = "replay"))]
469 impl<'a, T> Deserialize<'a> for T {}
470}
471#[cfg(feature = "capture")]
472use serde::Serialize as InternSerialize;
473#[cfg(not(feature = "capture"))]
474use self::dummy::Serialize as InternSerialize;
475#[cfg(feature = "replay")]
476use serde::Deserialize as InternDeserialize;
477#[cfg(not(feature = "replay"))]
478use self::dummy::Deserialize as InternDeserialize;
479
480pub trait Internable: MallocSizeOf {
482 type Key: Eq + Hash + Clone + Debug + MallocSizeOf + InternDebug + InternSerialize + for<'a> InternDeserialize<'a>;
483 type StoreData: From<Self::Key> + MallocSizeOf + InternSerialize + for<'a> InternDeserialize<'a>;
484 type InternData: MallocSizeOf + InternSerialize + for<'a> InternDeserialize<'a>;
485
486 const PROFILE_COUNTER: usize;
488}