1use api::ColorF;
6use api::PropertyBindingId;
7use api::units::*;
8use smallvec::SmallVec;
9use crate::composite::CompositeState;
10use crate::internal_types::{FastHashMap, FrameId};
11use crate::invalidation::compare::ImageDependency;
12use crate::invalidation::compare::{ColorBinding, OpacityBinding, OpacityBindingInfo, PrimitiveComparisonKey};
13use crate::invalidation::compare::{PrimitiveComparer, PrimitiveDependency, ColorBindingInfo};
14use crate::invalidation::{InvalidationReason, PrimitiveCompareResult, quadtree::TileNode};
15use crate::invalidation::vert_buffer::{CornersCache, VertRange};
16use crate::intern::ItemUid;
17use crate::picture::{PictureCompositeMode, SurfaceIndex, clampf};
18use crate::print_tree::PrintTreePrinter;
19use crate::resource_cache::ResourceCache;
20use crate::space::SpaceMapper;
21use crate::visibility::FrameVisibilityContext;
22use peek_poke::poke_into_vec;
23use std::mem;
24
25pub struct CachedSurface {
26 pub current_descriptor: CachedSurfaceDescriptor,
27 pub prev_descriptor: CachedSurfaceDescriptor,
28 pub is_valid: bool,
29 pub local_valid_rect: PictureBox2D,
30 pub local_dirty_rect: PictureRect,
31 pub local_rect: PictureRect,
32 pub root: TileNode,
33 pub background_color: Option<ColorF>,
34 pub invalidation_reason: Option<InvalidationReason>,
35 pub sub_graphs: Vec<(PictureRect, Vec<(PictureCompositeMode, SurfaceIndex)>)>,
36}
37
38impl CachedSurface {
39 pub fn new() -> Self {
40 CachedSurface {
41 current_descriptor: CachedSurfaceDescriptor::new(),
42 prev_descriptor: CachedSurfaceDescriptor::new(),
43 is_valid: false,
44 local_valid_rect: PictureBox2D::zero(),
45 local_dirty_rect: PictureRect::zero(),
46 local_rect: PictureRect::zero(),
47 root: TileNode::new_leaf(Vec::new()),
48 background_color: None,
49 invalidation_reason: None,
50 sub_graphs: Vec::new(),
51 }
52 }
53
54 pub fn print(&self, pt: &mut dyn PrintTreePrinter) {
55 pt.add_item(format!("background_color: {:?}", self.background_color));
56 pt.add_item(format!("invalidation_reason: {:?}", self.invalidation_reason));
57 self.current_descriptor.print(pt);
58 }
59
60 pub fn pre_update(
62 &mut self,
63 background_color: Option<ColorF>,
64 local_tile_rect: PictureRect,
65 frame_id: FrameId,
66 is_visible: bool,
67 ) {
68 self.local_valid_rect = PictureBox2D::new(
72 PicturePoint::new( 1.0e32, 1.0e32),
73 PicturePoint::new(-1.0e32, -1.0e32),
74 );
75 self.invalidation_reason = None;
76 self.sub_graphs.clear();
77
78 if !is_visible {
82 return;
83 }
84
85 if background_color != self.background_color {
86 self.invalidate(None, InvalidationReason::BackgroundColor);
87 self.background_color = background_color;
88 }
89
90 mem::swap(
93 &mut self.current_descriptor,
94 &mut self.prev_descriptor,
95 );
96 self.current_descriptor.clear();
97 self.root.clear(local_tile_rect);
98
99 self.current_descriptor.last_updated_frame_id = frame_id;
100 }
101
102 pub fn add_prim_dependency(
103 &mut self,
104 info: &PrimitiveDependencyInfo,
105 corners_cache: &CornersCache,
106 prim_clamp_to_tile: bool,
107 local_raster_rect: &RasterRect,
108 local_tile_rect: PictureRect,
109 ) {
110 self.local_valid_rect = self.local_valid_rect.union(&info.prim_clip_box);
114
115 let pmin = local_tile_rect.min;
129 let pmax = local_tile_rect.max;
130
131 let prim_clip_box = PictureBox2D::new(
132 PicturePoint::new(
133 clampf(info.prim_clip_box.min.x, pmin.x, pmax.x),
134 clampf(info.prim_clip_box.min.y, pmin.y, pmax.y),
135 ),
136 PicturePoint::new(
137 clampf(info.prim_clip_box.max.x, pmin.x, pmax.x),
138 clampf(info.prim_clip_box.max.y, pmin.y, pmax.y),
139 ),
140 );
141
142 let vert_data = &mut self.current_descriptor.vert_data;
144 let (prim_corners, coverage_corners) = if prim_clamp_to_tile {
145 (
146 corners_cache.push_verts_clamped(info.prim_scratch, local_raster_rect, vert_data),
147 corners_cache.push_verts_clamped(info.cov_scratch, local_raster_rect, vert_data),
148 )
149 } else {
150 (
151 corners_cache.push_verts(info.prim_scratch, vert_data),
152 corners_cache.push_verts(info.cov_scratch, vert_data),
153 )
154 };
155
156 let prim_index = PrimitiveDependencyIndex(self.current_descriptor.prims.len() as u32);
158
159 let dep_offset = self.current_descriptor.dep_data.len() as u32;
161 let mut dep_count = 0;
162
163 for &(clip_uid, clip_scratch) in info.clips.iter() {
164 dep_count += 1;
165 poke_into_vec(
166 &PrimitiveDependency::Clip { prim_uid: clip_uid, vert_range: corners_cache.push_verts(clip_scratch, vert_data) },
167 &mut self.current_descriptor.dep_data,
168 );
169 }
170
171 for image in &info.images {
172 dep_count += 1;
173 poke_into_vec(
174 &PrimitiveDependency::Image {
175 image: *image,
176 },
177 &mut self.current_descriptor.dep_data,
178 );
179 }
180
181 for binding in &info.opacity_bindings {
182 dep_count += 1;
183 poke_into_vec(
184 &PrimitiveDependency::OpacityBinding {
185 binding: *binding,
186 },
187 &mut self.current_descriptor.dep_data,
188 );
189 }
190
191 if let Some(ref binding) = info.color_binding {
192 dep_count += 1;
193 poke_into_vec(
194 &PrimitiveDependency::ColorBinding {
195 binding: *binding,
196 },
197 &mut self.current_descriptor.dep_data,
198 );
199 }
200
201 self.current_descriptor.prims.push(PrimitiveDescriptor {
202 prim_clip_box,
203 dep_offset,
204 dep_count,
205 prim_uid: info.prim_uid,
206 prim_corners,
207 coverage_corners,
208 });
209
210 self.root.add_prim(prim_index, &info.prim_clip_box);
212 }
213
214 fn update_dirty_rects(
216 &mut self,
217 ctx: &TileUpdateDirtyContext,
218 state: &mut TileUpdateDirtyState,
219 invalidation_reason: &mut Option<InvalidationReason>,
220 frame_context: &FrameVisibilityContext,
221 ) -> PictureRect {
222 let mut prim_comparer = PrimitiveComparer::new(
223 &self.prev_descriptor,
224 &self.current_descriptor,
225 state.resource_cache,
226 ctx.opacity_bindings,
227 ctx.color_bindings,
228 );
229
230 let mut dirty_rect = PictureBox2D::zero();
231 self.root.update_dirty_rects(
232 &self.prev_descriptor.prims,
233 &self.current_descriptor.prims,
234 &mut prim_comparer,
235 &mut dirty_rect,
236 state.compare_cache,
237 invalidation_reason,
238 frame_context,
239 );
240
241 dirty_rect
242 }
243
244 pub fn update_content_validity(
249 &mut self,
250 ctx: &TileUpdateDirtyContext,
251 state: &mut TileUpdateDirtyState,
252 frame_context: &FrameVisibilityContext,
253 ) {
254 state.compare_cache.clear();
257 let mut invalidation_reason = None;
258 let dirty_rect = self.update_dirty_rects(
259 ctx,
260 state,
261 &mut invalidation_reason,
262 frame_context,
263 );
264
265 if !dirty_rect.is_empty() {
266 self.invalidate(
267 Some(dirty_rect),
268 invalidation_reason.expect("bug: no invalidation_reason")
269 );
270 }
271 if ctx.invalidate_all {
272 self.invalidate(None, InvalidationReason::ScaleChanged);
273 }
274 if self.current_descriptor.local_valid_rect != self.prev_descriptor.local_valid_rect {
277 self.invalidate(None, InvalidationReason::ValidRectChanged);
278 state.composite_state.dirty_rects_are_valid = false;
279 }
280 }
281
282 pub fn invalidate(
285 &mut self,
286 invalidation_rect: Option<PictureRect>,
287 reason: InvalidationReason,
288 ) {
289 self.is_valid = false;
290
291 match invalidation_rect {
292 Some(rect) => {
293 self.local_dirty_rect = self.local_dirty_rect.union(&rect);
294 }
295 None => {
296 self.local_dirty_rect = self.local_rect;
297 }
298 }
299
300 if self.invalidation_reason.is_none() {
301 self.invalidation_reason = Some(reason);
302 }
303 }
304}
305
306pub struct TileUpdateDirtyContext<'a> {
308 pub pic_to_world_mapper: SpaceMapper<PicturePixel, WorldPixel>,
310
311 pub global_device_pixel_scale: DevicePixelScale,
313
314 pub opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
316
317 pub color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
319
320 pub local_rect: PictureRect,
322
323 pub invalidate_all: bool,
326}
327
328pub struct TileUpdateDirtyState<'a> {
330 pub resource_cache: &'a mut ResourceCache,
332
333 pub composite_state: &'a mut CompositeState,
335
336 pub compare_cache: &'a mut FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
338}
339
340pub struct PrimitiveDependencyInfo {
344 pub prim_clip_box: PictureBox2D,
347 pub images: SmallVec<[ImageDependency; 8]>,
349 pub opacity_bindings: SmallVec<[OpacityBinding; 4]>,
351 pub color_binding: Option<ColorBinding>,
353 pub prim_uid: ItemUid,
360 pub prim_scratch: VertRange,
363 pub cov_scratch: VertRange,
371 pub clips: SmallVec<[(ItemUid, VertRange); 4]>,
374}
375
376impl PrimitiveDependencyInfo {
377 pub fn new(prim_uid: ItemUid, prim_clip_box: PictureBox2D) -> Self {
378 PrimitiveDependencyInfo {
379 prim_clip_box,
380 images: smallvec::SmallVec::new(),
381 opacity_bindings: smallvec::SmallVec::new(),
382 color_binding: None,
383 prim_uid,
384 prim_scratch: VertRange::INVALID,
385 cov_scratch: VertRange::INVALID,
386 clips: smallvec::SmallVec::new(),
387 }
388 }
389}
390
391#[derive(Debug, Clone)]
393#[cfg_attr(feature = "capture", derive(Serialize))]
394#[cfg_attr(feature = "replay", derive(Deserialize))]
395pub struct PrimitiveDescriptor {
396 pub prim_clip_box: PictureBox2D,
399 pub dep_offset: u32,
401 pub dep_count: u32,
402 pub prim_uid: ItemUid,
405 pub prim_corners: VertRange,
407 pub coverage_corners: VertRange,
409}
410
411
412#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
414#[cfg_attr(feature = "capture", derive(Serialize))]
415#[cfg_attr(feature = "replay", derive(Deserialize))]
416pub struct PrimitiveDependencyIndex(pub u32);
417
418#[cfg_attr(any(feature="capture",feature="replay"), derive(Clone))]
421#[cfg_attr(feature = "capture", derive(Serialize))]
422#[cfg_attr(feature = "replay", derive(Deserialize))]
423pub struct CachedSurfaceDescriptor {
424 pub prims: Vec<PrimitiveDescriptor>,
428
429 pub local_valid_rect: PictureRect,
431
432 pub last_updated_frame_id: FrameId,
435
436 pub dep_data: Vec<u8>,
438
439 pub vert_data: Vec<i32>,
442}
443
444impl CachedSurfaceDescriptor {
445 pub fn new() -> Self {
446 CachedSurfaceDescriptor {
447 local_valid_rect: PictureRect::zero(),
448 dep_data: Vec::new(),
449 vert_data: Vec::new(),
450 prims: Vec::new(),
451 last_updated_frame_id: FrameId::INVALID,
452 }
453 }
454
455 pub fn print(&self, pt: &mut dyn crate::print_tree::PrintTreePrinter) {
457 pt.new_level("current_descriptor".to_string());
458
459 pt.new_level("prims".to_string());
460 for prim in &self.prims {
461 pt.new_level(format!("prim uid={}", prim.prim_uid.get_uid()));
462 pt.add_item(format!("clip: p0={},{} p1={},{}",
463 prim.prim_clip_box.min.x,
464 prim.prim_clip_box.min.y,
465 prim.prim_clip_box.max.x,
466 prim.prim_clip_box.max.y,
467 ));
468 pt.end_level();
469 }
470 pt.end_level();
471
472 pt.end_level();
473 }
474
475 pub fn clear(&mut self) {
478 self.local_valid_rect = PictureRect::zero();
479 self.prims.clear();
480 self.dep_data.clear();
481 self.vert_data.clear();
482 }
483}