webrender/invalidation/
compare.rs1use api::{ImageKey, PropertyBindingId, ColorU};
12use crate::invalidation::PrimitiveCompareResult;
13use crate::internal_types::FastHashMap;
14use crate::resource_cache::{ResourceCache, ImageGeneration};
15use crate::invalidation::cached_surface::{PrimitiveDependencyIndex, PrimitiveDescriptor, CachedSurfaceDescriptor};
16use crate::intern::ItemUid;
17use crate::invalidation::vert_buffer::VertRange;
18use peek_poke::{PeekPoke, peek_from_slice};
19
20
21#[derive(Debug)]
23pub struct BindingInfo<T> {
24 pub value: T,
26 pub changed: bool,
28}
29
30#[derive(Debug, PartialEq, Clone, Copy, PeekPoke)]
32#[cfg_attr(feature = "capture", derive(Serialize))]
33#[cfg_attr(feature = "replay", derive(Deserialize))]
34pub enum Binding<T> {
35 Value(T),
36 Binding(PropertyBindingId),
37}
38
39impl<T: Default> Default for Binding<T> {
40 fn default() -> Self {
41 Binding::Value(T::default())
42 }
43}
44
45impl<T> From<api::PropertyBinding<T>> for Binding<T> {
46 fn from(binding: api::PropertyBinding<T>) -> Binding<T> {
47 match binding {
48 api::PropertyBinding::Binding(key, _) => Binding::Binding(key.id),
49 api::PropertyBinding::Value(value) => Binding::Value(value),
50 }
51 }
52}
53
54pub type OpacityBinding = Binding<f32>;
55pub type OpacityBindingInfo = BindingInfo<f32>;
56
57pub type ColorBinding = Binding<ColorU>;
58pub type ColorBindingInfo = BindingInfo<ColorU>;
59
60#[derive(PeekPoke)]
62pub enum PrimitiveDependency {
63 OpacityBinding {
64 binding: OpacityBinding,
65 },
66 ColorBinding {
67 binding: ColorBinding,
68 },
69 Image {
70 image: ImageDependency,
71 },
72 Clip {
76 prim_uid: ItemUid,
77 vert_range: VertRange,
78 },
79}
80
81#[derive(Debug, Copy, Clone, PartialEq, PeekPoke, Default)]
83#[cfg_attr(feature = "capture", derive(Serialize))]
84#[cfg_attr(feature = "replay", derive(Deserialize))]
85pub struct ImageDependency {
86 pub key: ImageKey,
87 pub generation: ImageGeneration,
88}
89
90impl ImageDependency {
91 pub const INVALID: ImageDependency = ImageDependency {
92 key: ImageKey::DUMMY,
93 generation: ImageGeneration::INVALID,
94 };
95}
96
97#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
99pub struct PrimitiveComparisonKey {
100 pub prev_index: PrimitiveDependencyIndex,
101 pub curr_index: PrimitiveDependencyIndex,
102}
103
104pub struct PrimitiveComparer<'a> {
106 prev: &'a CachedSurfaceDescriptor,
107 curr: &'a CachedSurfaceDescriptor,
108 resource_cache: &'a ResourceCache,
109 opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
110 color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
111}
112
113impl<'a> PrimitiveComparer<'a> {
114 pub fn new(
115 prev: &'a CachedSurfaceDescriptor,
116 curr: &'a CachedSurfaceDescriptor,
117 resource_cache: &'a ResourceCache,
118 opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
119 color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
120 ) -> Self {
121 PrimitiveComparer {
122 prev,
123 curr,
124 resource_cache,
125 opacity_bindings,
126 color_bindings,
127 }
128 }
129
130 pub fn compare_prim(
134 &mut self,
135 prev_desc: &PrimitiveDescriptor,
136 curr_desc: &PrimitiveDescriptor,
137 ) -> PrimitiveCompareResult {
138 if prev_desc.prim_uid != curr_desc.prim_uid {
139 return PrimitiveCompareResult::Descriptor;
140 }
141
142 let prev_range = prev_desc.prim_corners;
144 let prev_end = (prev_range.offset + prev_range.count) as usize;
145 let prev_verts = &self.prev.vert_data[prev_range.offset as usize .. prev_end];
146
147 let curr_range = curr_desc.prim_corners;
148 let curr_end = (curr_range.offset + curr_range.count) as usize;
149 let curr_verts = &self.curr.vert_data[curr_range.offset as usize .. curr_end];
150
151 if prev_verts != curr_verts {
152 return PrimitiveCompareResult::Descriptor;
153 }
154
155 let prev_range = prev_desc.coverage_corners;
156 let prev_end = (prev_range.offset + prev_range.count) as usize;
157 let prev_verts = &self.prev.vert_data[prev_range.offset as usize .. prev_end];
158
159 let curr_range = curr_desc.coverage_corners;
160 let curr_end = (curr_range.offset + curr_range.count) as usize;
161 let curr_verts = &self.curr.vert_data[curr_range.offset as usize .. curr_end];
162
163 if prev_verts != curr_verts {
164 return PrimitiveCompareResult::Descriptor;
165 }
166
167 if prev_desc.dep_count != curr_desc.dep_count {
170 return PrimitiveCompareResult::Descriptor;
171 }
172
173 let mut prev_dep_data = &self.prev.dep_data[prev_desc.dep_offset as usize ..];
176 let mut curr_dep_data = &self.curr.dep_data[curr_desc.dep_offset as usize ..];
177
178 let mut prev_dep = PrimitiveDependency::Image { image: ImageDependency::INVALID };
179 let mut curr_dep = PrimitiveDependency::Image { image: ImageDependency::INVALID };
180
181 for _ in 0 .. prev_desc.dep_count {
182 prev_dep_data = peek_from_slice(prev_dep_data, &mut prev_dep);
183 curr_dep_data = peek_from_slice(curr_dep_data, &mut curr_dep);
184
185 match (&prev_dep, &curr_dep) {
186 (PrimitiveDependency::Clip { prim_uid: prev_uid, vert_range: prev_range }, PrimitiveDependency::Clip { prim_uid: curr_uid, vert_range: curr_range }) => {
187 if prev_uid != curr_uid {
188 return PrimitiveCompareResult::Clip;
189 }
190 let prev_end = (prev_range.offset + prev_range.count) as usize;
191 let prev_verts: &[i32] = if prev_range.is_valid() && prev_end <= self.prev.vert_data.len() {
192 &self.prev.vert_data[prev_range.offset as usize .. prev_end]
193 } else {
194 &[]
195 };
196 let curr_end = (curr_range.offset + curr_range.count) as usize;
197 let curr_verts: &[i32] = if curr_range.is_valid() && curr_end <= self.curr.vert_data.len() {
198 &self.curr.vert_data[curr_range.offset as usize .. curr_end]
199 } else {
200 &[]
201 };
202 if prev_verts != curr_verts {
203 return PrimitiveCompareResult::Clip;
204 }
205 }
206 (PrimitiveDependency::Image { image: prev }, PrimitiveDependency::Image { image: curr }) => {
207 if prev != curr {
208 return PrimitiveCompareResult::Image;
209 }
210 if self.resource_cache.get_image_generation(curr.key) != curr.generation {
211 return PrimitiveCompareResult::Image;
212 }
213 }
214 (PrimitiveDependency::OpacityBinding { binding: prev }, PrimitiveDependency::OpacityBinding { binding: curr }) => {
215 if prev != curr {
216 return PrimitiveCompareResult::OpacityBinding;
217 }
218 if let OpacityBinding::Binding(id) = curr {
219 if self.opacity_bindings.get(id).map_or(true, |info| info.changed) {
220 return PrimitiveCompareResult::OpacityBinding;
221 }
222 }
223 }
224 (PrimitiveDependency::ColorBinding { binding: prev }, PrimitiveDependency::ColorBinding { binding: curr }) => {
225 if prev != curr {
226 return PrimitiveCompareResult::ColorBinding;
227 }
228 if let ColorBinding::Binding(id) = curr {
229 if self.color_bindings.get(id).map_or(true, |info| info.changed) {
230 return PrimitiveCompareResult::ColorBinding;
231 }
232 }
233 }
234 _ => {
235 return PrimitiveCompareResult::Descriptor;
236 }
237 }
238 }
239
240 PrimitiveCompareResult::Equal
241 }
242}