1use api::{MixBlendMode, PremultipliedColorF, FilterPrimitiveKind};
98use api::{PropertyBinding, PropertyBindingId, FilterPrimitive};
99use api::{DebugFlags, ImageKey, ColorF, ColorU, PrimitiveFlags};
100use api::{ImageRendering, ColorDepth, YuvRangedColorSpace, YuvFormat, AlphaType};
101use api::units::*;
102use crate::batch::BatchFilter;
103use crate::box_shadow::BLUR_SAMPLE_SCALE;
104use crate::clip::{ClipStore, ClipChainInstance, ClipChainId, ClipInstance};
105use crate::spatial_tree::{ROOT_SPATIAL_NODE_INDEX,
106 SpatialTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace
107};
108use crate::composite::{CompositorKind, CompositeState, NativeSurfaceId, NativeTileId, CompositeTileSurface, tile_kind};
109use crate::composite::{ExternalSurfaceDescriptor, ExternalSurfaceDependency, CompositeTileDescriptor, CompositeTile};
110use crate::composite::{CompositorTransformIndex};
111use crate::debug_colors;
112use euclid::{vec2, vec3, Point2D, Scale, Vector2D, Box2D, Transform3D, SideOffsets2D};
113use euclid::approxeq::ApproxEq;
114use crate::filterdata::SFilterData;
115use crate::intern::ItemUid;
116use crate::internal_types::{FastHashMap, FastHashSet, PlaneSplitter, Filter, PlaneSplitAnchor, TextureSource};
117use crate::frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState, PictureContext};
118use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
119use crate::gpu_types::{UvRectKind, ZBufferId};
120use plane_split::{Clipper, Polygon, Splitter};
121use crate::prim_store::{PrimitiveTemplateKind, PictureIndex, PrimitiveInstance, PrimitiveInstanceKind};
122use crate::prim_store::{ColorBindingStorage, ColorBindingIndex, PrimitiveScratchBuffer};
123use crate::print_tree::{PrintTree, PrintTreePrinter};
124use crate::render_backend::{DataStores, FrameId};
125use crate::render_task_graph::RenderTaskId;
126use crate::render_target::RenderTargetKind;
127use crate::render_task::{BlurTask, RenderTask, RenderTaskLocation, BlurTaskCache};
128use crate::render_task::{StaticRenderTaskSurface, RenderTaskKind};
129use crate::renderer::BlendMode;
130use crate::resource_cache::{ResourceCache, ImageGeneration, ImageRequest};
131use crate::space::SpaceMapper;
132use crate::scene::SceneProperties;
133use smallvec::SmallVec;
134use std::{mem, u8, marker, u32};
135use std::sync::atomic::{AtomicUsize, Ordering};
136use std::collections::hash_map::Entry;
137use std::ops::Range;
138use crate::texture_cache::TextureCacheHandle;
139use crate::util::{MaxRect, VecHelper, MatrixHelpers, Recycler, raster_rect_to_device_pixels, ScaleOffset};
140use crate::filterdata::{FilterDataHandle};
141use crate::tile_cache::{SliceDebugInfo, TileDebugInfo, DirtyTileDebugInfo};
142use crate::visibility::{PrimitiveVisibilityFlags, FrameVisibilityContext};
143use crate::visibility::{VisibilityState, FrameVisibilityState};
144#[cfg(any(feature = "capture", feature = "replay"))]
145use ron;
146#[cfg(feature = "capture")]
147use crate::scene_builder_thread::InternerUpdates;
148#[cfg(any(feature = "capture", feature = "replay"))]
149use crate::intern::{Internable, UpdateList};
150#[cfg(any(feature = "capture", feature = "replay"))]
151use crate::clip::{ClipIntern, PolygonIntern};
152#[cfg(any(feature = "capture", feature = "replay"))]
153use crate::filterdata::FilterDataIntern;
154#[cfg(any(feature = "capture", feature = "replay"))]
155use api::PrimitiveKeyKind;
156#[cfg(any(feature = "capture", feature = "replay"))]
157use crate::prim_store::backdrop::Backdrop;
158#[cfg(any(feature = "capture", feature = "replay"))]
159use crate::prim_store::borders::{ImageBorder, NormalBorderPrim};
160#[cfg(any(feature = "capture", feature = "replay"))]
161use crate::prim_store::gradient::{LinearGradient, RadialGradient, ConicGradient};
162#[cfg(any(feature = "capture", feature = "replay"))]
163use crate::prim_store::image::{Image, YuvImage};
164#[cfg(any(feature = "capture", feature = "replay"))]
165use crate::prim_store::line_dec::LineDecoration;
166#[cfg(any(feature = "capture", feature = "replay"))]
167use crate::prim_store::picture::Picture;
168#[cfg(any(feature = "capture", feature = "replay"))]
169use crate::prim_store::text_run::TextRun;
170
171#[cfg(feature = "capture")]
172use std::fs::File;
173#[cfg(feature = "capture")]
174use std::io::prelude::*;
175#[cfg(feature = "capture")]
176use std::path::PathBuf;
177use crate::scene_building::{SliceFlags};
178
179#[cfg(feature = "replay")]
180use std::collections::HashMap;
182
183pub const MAX_BLUR_RADIUS: f32 = 100.;
186
187#[derive(Debug, Copy, Clone)]
189pub enum SubpixelMode {
190 Allow,
192 Deny,
194 Conditional {
197 allowed_rect: PictureRect,
198 },
199}
200
201#[derive(Debug, Clone)]
203struct MatrixKey {
204 m: [f32; 16],
205}
206
207impl PartialEq for MatrixKey {
208 fn eq(&self, other: &Self) -> bool {
209 const EPSILON: f32 = 0.001;
210
211 for (i, j) in self.m.iter().zip(other.m.iter()) {
215 if !i.approx_eq_eps(j, &EPSILON) {
216 return false;
217 }
218 }
219
220 true
221 }
222}
223
224#[derive(Debug, Clone)]
226struct ScaleOffsetKey {
227 sx: f32,
228 sy: f32,
229 tx: f32,
230 ty: f32,
231}
232
233impl PartialEq for ScaleOffsetKey {
234 fn eq(&self, other: &Self) -> bool {
235 const EPSILON: f32 = 0.001;
236
237 self.sx.approx_eq_eps(&other.sx, &EPSILON) &&
238 self.sy.approx_eq_eps(&other.sy, &EPSILON) &&
239 self.tx.approx_eq_eps(&other.tx, &EPSILON) &&
240 self.ty.approx_eq_eps(&other.ty, &EPSILON)
241 }
242}
243
244#[derive(Debug, PartialEq, Clone)]
247enum TransformKey {
248 Local,
249 ScaleOffset {
250 so: ScaleOffsetKey,
251 },
252 Transform {
253 m: MatrixKey,
254 }
255}
256
257impl<Src, Dst> From<CoordinateSpaceMapping<Src, Dst>> for TransformKey {
258 fn from(transform: CoordinateSpaceMapping<Src, Dst>) -> TransformKey {
259 match transform {
260 CoordinateSpaceMapping::Local => {
261 TransformKey::Local
262 }
263 CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
264 TransformKey::ScaleOffset {
265 so: ScaleOffsetKey {
266 sx: scale_offset.scale.x,
267 sy: scale_offset.scale.y,
268 tx: scale_offset.offset.x,
269 ty: scale_offset.offset.y,
270 }
271 }
272 }
273 CoordinateSpaceMapping::Transform(ref m) => {
274 TransformKey::Transform {
275 m: MatrixKey {
276 m: m.to_array(),
277 },
278 }
279 }
280 }
281 }
282}
283
284#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
286pub struct TileCoordinate;
287
288pub type TileOffset = Point2D<i32, TileCoordinate>;
290pub type TileRect = Box2D<i32, TileCoordinate>;
291
292const MAX_COMPOSITOR_SURFACES: usize = 4;
296
297pub const TILE_SIZE_DEFAULT: DeviceIntSize = DeviceIntSize {
299 width: 1024,
300 height: 512,
301 _unit: marker::PhantomData,
302};
303
304pub const TILE_SIZE_SCROLLBAR_HORIZONTAL: DeviceIntSize = DeviceIntSize {
306 width: 1024,
307 height: 32,
308 _unit: marker::PhantomData,
309};
310
311pub const TILE_SIZE_SCROLLBAR_VERTICAL: DeviceIntSize = DeviceIntSize {
313 width: 32,
314 height: 1024,
315 _unit: marker::PhantomData,
316};
317
318const MAX_SURFACE_SIZE: f32 = 4096.0;
321const MAX_COMPOSITOR_SURFACES_SIZE: f32 = 8192.0;
323
324const MAX_PRIM_SUB_DEPS: usize = u8::MAX as usize;
327
328static NEXT_TILE_ID: AtomicUsize = AtomicUsize::new(0);
331
332fn clamp(value: i32, low: i32, high: i32) -> i32 {
333 value.max(low).min(high)
334}
335
336fn clampf(value: f32, low: f32, high: f32) -> f32 {
337 value.max(low).min(high)
338}
339
340fn clamp_blur_radius(blur_radius: f32, scale_factors: (f32, f32)) -> f32 {
342 let largest_scale_factor = f32::max(scale_factors.0, scale_factors.1);
349 let scaled_blur_radius = blur_radius * largest_scale_factor;
350
351 if scaled_blur_radius > MAX_BLUR_RADIUS {
352 MAX_BLUR_RADIUS / largest_scale_factor
353 } else {
354 blur_radius
356 }
357}
358
359#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
361#[cfg_attr(feature = "capture", derive(Serialize))]
362#[cfg_attr(feature = "replay", derive(Deserialize))]
363pub struct PrimitiveDependencyIndex(pub u32);
364
365#[derive(Debug)]
367pub struct BindingInfo<T> {
368 value: T,
370 changed: bool,
372}
373
374#[derive(Debug, PartialEq, Clone, Copy)]
376#[cfg_attr(feature = "capture", derive(Serialize))]
377#[cfg_attr(feature = "replay", derive(Deserialize))]
378pub enum Binding<T> {
379 Value(T),
380 Binding(PropertyBindingId),
381}
382
383impl<T> From<PropertyBinding<T>> for Binding<T> {
384 fn from(binding: PropertyBinding<T>) -> Binding<T> {
385 match binding {
386 PropertyBinding::Binding(key, _) => Binding::Binding(key.id),
387 PropertyBinding::Value(value) => Binding::Value(value),
388 }
389 }
390}
391
392pub type OpacityBinding = Binding<f32>;
393pub type OpacityBindingInfo = BindingInfo<f32>;
394
395pub type ColorBinding = Binding<ColorU>;
396pub type ColorBindingInfo = BindingInfo<ColorU>;
397
398#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
400#[cfg_attr(feature = "capture", derive(Serialize))]
401#[cfg_attr(feature = "replay", derive(Deserialize))]
402pub struct SpatialNodeKey {
403 spatial_node_index: SpatialNodeIndex,
404 frame_id: FrameId,
405}
406
407struct SpatialNodeComparer {
412 ref_spatial_node_index: SpatialNodeIndex,
414 spatial_nodes: FastHashMap<SpatialNodeKey, TransformKey>,
416 compare_cache: FastHashMap<(SpatialNodeKey, SpatialNodeKey), bool>,
418 referenced_frames: FastHashSet<FrameId>,
420}
421
422impl SpatialNodeComparer {
423 fn new() -> Self {
425 SpatialNodeComparer {
426 ref_spatial_node_index: ROOT_SPATIAL_NODE_INDEX,
427 spatial_nodes: FastHashMap::default(),
428 compare_cache: FastHashMap::default(),
429 referenced_frames: FastHashSet::default(),
430 }
431 }
432
433 fn next_frame(
435 &mut self,
436 ref_spatial_node_index: SpatialNodeIndex,
437 ) {
438 let referenced_frames = &self.referenced_frames;
441 self.spatial_nodes.retain(|key, _| {
442 referenced_frames.contains(&key.frame_id)
443 });
444
445 self.ref_spatial_node_index = ref_spatial_node_index;
447 self.compare_cache.clear();
448 self.referenced_frames.clear();
449 }
450
451 fn register_used_transform(
453 &mut self,
454 spatial_node_index: SpatialNodeIndex,
455 frame_id: FrameId,
456 spatial_tree: &SpatialTree,
457 ) {
458 let key = SpatialNodeKey {
459 spatial_node_index,
460 frame_id,
461 };
462
463 if let Entry::Vacant(entry) = self.spatial_nodes.entry(key) {
464 entry.insert(
465 get_transform_key(
466 spatial_node_index,
467 self.ref_spatial_node_index,
468 spatial_tree,
469 )
470 );
471 }
472 }
473
474 fn are_transforms_equivalent(
476 &mut self,
477 prev_spatial_node_key: &SpatialNodeKey,
478 curr_spatial_node_key: &SpatialNodeKey,
479 ) -> bool {
480 let key = (*prev_spatial_node_key, *curr_spatial_node_key);
481 let spatial_nodes = &self.spatial_nodes;
482
483 *self.compare_cache
484 .entry(key)
485 .or_insert_with(|| {
486 let prev = &spatial_nodes[&prev_spatial_node_key];
487 let curr = &spatial_nodes[&curr_spatial_node_key];
488 curr == prev
489 })
490 }
491
492 fn retain_for_frame(&mut self, frame_id: FrameId) {
494 self.referenced_frames.insert(frame_id);
495 }
496}
497
498struct TilePreUpdateContext {
500 pic_to_world_mapper: SpaceMapper<PicturePixel, WorldPixel>,
502
503 background_color: Option<ColorF>,
505
506 global_screen_world_rect: WorldRect,
508
509 tile_size: PictureSize,
511
512 frame_id: FrameId,
514}
515
516struct TilePostUpdateContext<'a> {
518 pic_to_world_mapper: SpaceMapper<PicturePixel, WorldPixel>,
520
521 global_device_pixel_scale: DevicePixelScale,
523
524 local_clip_rect: PictureRect,
526
527 backdrop: Option<BackdropInfo>,
529
530 opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
532
533 color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
535
536 current_tile_size: DeviceIntSize,
538
539 local_rect: PictureRect,
541
542 z_id: ZBufferId,
544
545 invalidate_all: bool,
548}
549
550struct TilePostUpdateState<'a> {
552 resource_cache: &'a mut ResourceCache,
554
555 composite_state: &'a mut CompositeState,
557
558 compare_cache: &'a mut FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
560
561 spatial_node_comparer: &'a mut SpatialNodeComparer,
563}
564
565struct PrimitiveDependencyInfo {
567 prim_uid: ItemUid,
569
570 prim_clip_box: PictureBox2D,
572
573 images: SmallVec<[ImageDependency; 8]>,
575
576 opacity_bindings: SmallVec<[OpacityBinding; 4]>,
578
579 color_binding: Option<ColorBinding>,
581
582 clips: SmallVec<[ItemUid; 8]>,
584
585 spatial_nodes: SmallVec<[SpatialNodeIndex; 4]>,
587}
588
589impl PrimitiveDependencyInfo {
590 fn new(
592 prim_uid: ItemUid,
593 prim_clip_box: PictureBox2D,
594 ) -> Self {
595 PrimitiveDependencyInfo {
596 prim_uid,
597 images: SmallVec::new(),
598 opacity_bindings: SmallVec::new(),
599 color_binding: None,
600 prim_clip_box,
601 clips: SmallVec::new(),
602 spatial_nodes: SmallVec::new(),
603 }
604 }
605}
606
607#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
610#[cfg_attr(feature = "capture", derive(Serialize))]
611#[cfg_attr(feature = "replay", derive(Deserialize))]
612pub struct TileId(pub usize);
613
614#[derive(Debug)]
617pub enum SurfaceTextureDescriptor {
618 TextureCache {
621 handle: TextureCacheHandle
622 },
623 Native {
626 id: Option<NativeTileId>,
628 },
629}
630
631#[derive(Clone, Debug, Eq, PartialEq, Hash)]
635#[cfg_attr(feature = "capture", derive(Serialize))]
636#[cfg_attr(feature = "replay", derive(Deserialize))]
637pub enum ResolvedSurfaceTexture {
638 TextureCache {
639 texture: TextureSource,
641 },
642 Native {
643 id: NativeTileId,
645 size: DeviceIntSize,
647 }
648}
649
650impl SurfaceTextureDescriptor {
651 pub fn resolve(
653 &self,
654 resource_cache: &ResourceCache,
655 size: DeviceIntSize,
656 ) -> ResolvedSurfaceTexture {
657 match self {
658 SurfaceTextureDescriptor::TextureCache { handle } => {
659 let cache_item = resource_cache.texture_cache.get(handle);
660
661 ResolvedSurfaceTexture::TextureCache {
662 texture: cache_item.texture_id,
663 }
664 }
665 SurfaceTextureDescriptor::Native { id } => {
666 ResolvedSurfaceTexture::Native {
667 id: id.expect("bug: native surface not allocated"),
668 size,
669 }
670 }
671 }
672 }
673}
674
675#[derive(Debug)]
677pub enum TileSurface {
678 Texture {
679 descriptor: SurfaceTextureDescriptor,
681 },
682 Color {
683 color: ColorF,
684 },
685 Clear,
686}
687
688impl TileSurface {
689 fn kind(&self) -> &'static str {
690 match *self {
691 TileSurface::Color { .. } => "Color",
692 TileSurface::Texture { .. } => "Texture",
693 TileSurface::Clear => "Clear",
694 }
695 }
696}
697
698#[derive(Debug, Copy, Clone, PartialEq)]
701#[cfg_attr(feature = "capture", derive(Serialize))]
702#[cfg_attr(feature = "replay", derive(Deserialize))]
703pub enum CompareHelperResult<T> {
704 Equal,
706 Count {
708 prev_count: u8,
709 curr_count: u8,
710 },
711 Sentinel,
713 NotEqual {
715 prev: T,
716 curr: T,
717 },
718 PredicateTrue {
720 curr: T
721 },
722}
723
724#[derive(Debug, Copy, Clone, PartialEq)]
728#[cfg_attr(feature = "capture", derive(Serialize))]
729#[cfg_attr(feature = "replay", derive(Deserialize))]
730#[repr(u8)]
731pub enum PrimitiveCompareResult {
732 Equal,
734 Descriptor,
736 Clip,
738 Transform,
740 Image,
742 OpacityBinding,
744 ColorBinding,
746}
747
748#[derive(Debug, Copy, Clone, PartialEq)]
751#[cfg_attr(feature = "capture", derive(Serialize))]
752#[cfg_attr(feature = "replay", derive(Deserialize))]
753pub enum PrimitiveCompareResultDetail {
754 Equal,
756 Descriptor {
758 old: PrimitiveDescriptor,
759 new: PrimitiveDescriptor,
760 },
761 Clip {
763 detail: CompareHelperResult<ItemUid>,
764 },
765 Transform {
767 detail: CompareHelperResult<SpatialNodeKey>,
768 },
769 Image {
771 detail: CompareHelperResult<ImageDependency>,
772 },
773 OpacityBinding {
775 detail: CompareHelperResult<OpacityBinding>,
776 },
777 ColorBinding {
779 detail: CompareHelperResult<ColorBinding>,
780 },
781}
782
783#[derive(Debug,Clone)]
785#[cfg_attr(feature = "capture", derive(Serialize))]
786#[cfg_attr(feature = "replay", derive(Deserialize))]
787pub enum InvalidationReason {
788 BackgroundColor {
790 old: Option<ColorF>,
791 new: Option<ColorF>,
792 },
793 SurfaceOpacityChanged{
795 became_opaque: bool
796 },
797 NoTexture,
799 NoSurface,
801 PrimCount {
803 old: Option<Vec<ItemUid>>,
804 new: Option<Vec<ItemUid>>,
805 },
806 Content {
808 prim_compare_result: PrimitiveCompareResult,
810 prim_compare_result_detail: Option<PrimitiveCompareResultDetail>,
811 },
812 CompositorKindChanged,
814 ValidRectChanged,
816 ScaleChanged,
818}
819
820#[cfg_attr(feature = "capture", derive(Serialize))]
822#[cfg_attr(feature = "replay", derive(Deserialize))]
823pub struct TileSerializer {
824 pub rect: PictureRect,
825 pub current_descriptor: TileDescriptor,
826 pub id: TileId,
827 pub root: TileNode,
828 pub background_color: Option<ColorF>,
829 pub invalidation_reason: Option<InvalidationReason>
830}
831
832#[cfg_attr(feature = "capture", derive(Serialize))]
834#[cfg_attr(feature = "replay", derive(Deserialize))]
835pub struct TileCacheInstanceSerializer {
836 pub slice: usize,
837 pub tiles: FastHashMap<TileOffset, TileSerializer>,
838 pub background_color: Option<ColorF>,
839}
840
841pub struct Tile {
843 pub tile_offset: TileOffset,
845 pub world_tile_rect: WorldRect,
847 pub local_tile_rect: PictureRect,
849 pub local_dirty_rect: PictureRect,
851 pub device_dirty_rect: DeviceRect,
855 pub world_valid_rect: WorldRect,
857 pub device_valid_rect: DeviceRect,
859 pub current_descriptor: TileDescriptor,
862 pub prev_descriptor: TileDescriptor,
864 pub surface: Option<TileSurface>,
866 pub is_valid: bool,
870 pub is_visible: bool,
873 pub id: TileId,
876 pub is_opaque: bool,
879 root: TileNode,
881 background_color: Option<ColorF>,
883 invalidation_reason: Option<InvalidationReason>,
885 pub local_valid_rect: PictureBox2D,
887 pub z_id: ZBufferId,
889 pub last_updated_frame_id: FrameId,
892}
893
894impl Tile {
895 fn new(tile_offset: TileOffset) -> Self {
897 let id = TileId(NEXT_TILE_ID.fetch_add(1, Ordering::Relaxed));
898
899 Tile {
900 tile_offset,
901 local_tile_rect: PictureRect::zero(),
902 world_tile_rect: WorldRect::zero(),
903 world_valid_rect: WorldRect::zero(),
904 device_valid_rect: DeviceRect::zero(),
905 local_dirty_rect: PictureRect::zero(),
906 device_dirty_rect: DeviceRect::zero(),
907 surface: None,
908 current_descriptor: TileDescriptor::new(),
909 prev_descriptor: TileDescriptor::new(),
910 is_valid: false,
911 is_visible: false,
912 id,
913 is_opaque: false,
914 root: TileNode::new_leaf(Vec::new()),
915 background_color: None,
916 invalidation_reason: None,
917 local_valid_rect: PictureBox2D::zero(),
918 z_id: ZBufferId::invalid(),
919 last_updated_frame_id: FrameId::INVALID,
920 }
921 }
922
923 fn print(&self, pt: &mut dyn PrintTreePrinter) {
925 pt.new_level(format!("Tile {:?}", self.id));
926 pt.add_item(format!("local_tile_rect: {:?}", self.local_tile_rect));
927 pt.add_item(format!("background_color: {:?}", self.background_color));
928 pt.add_item(format!("invalidation_reason: {:?}", self.invalidation_reason));
929 self.current_descriptor.print(pt);
930 pt.end_level();
931 }
932
933 fn update_dirty_rects(
935 &mut self,
936 ctx: &TilePostUpdateContext,
937 state: &mut TilePostUpdateState,
938 invalidation_reason: &mut Option<InvalidationReason>,
939 frame_context: &FrameVisibilityContext,
940 ) -> PictureRect {
941 let mut prim_comparer = PrimitiveComparer::new(
942 &self.prev_descriptor,
943 &self.current_descriptor,
944 state.resource_cache,
945 state.spatial_node_comparer,
946 ctx.opacity_bindings,
947 ctx.color_bindings,
948 );
949
950 let mut dirty_rect = PictureBox2D::zero();
951 self.root.update_dirty_rects(
952 &self.prev_descriptor.prims,
953 &self.current_descriptor.prims,
954 &mut prim_comparer,
955 &mut dirty_rect,
956 state.compare_cache,
957 invalidation_reason,
958 frame_context,
959 );
960
961 dirty_rect
962 }
963
964 fn update_content_validity(
969 &mut self,
970 ctx: &TilePostUpdateContext,
971 state: &mut TilePostUpdateState,
972 frame_context: &FrameVisibilityContext,
973 ) {
974 state.compare_cache.clear();
977 let mut invalidation_reason = None;
978 let dirty_rect = self.update_dirty_rects(
979 ctx,
980 state,
981 &mut invalidation_reason,
982 frame_context,
983 );
984 if !dirty_rect.is_empty() {
985 self.invalidate(
986 Some(dirty_rect),
987 invalidation_reason.expect("bug: no invalidation_reason"),
988 );
989 }
990 if ctx.invalidate_all {
991 self.invalidate(None, InvalidationReason::ScaleChanged);
992 }
993 if self.current_descriptor.local_valid_rect != self.prev_descriptor.local_valid_rect {
996 self.invalidate(None, InvalidationReason::ValidRectChanged);
997 state.composite_state.dirty_rects_are_valid = false;
998 }
999 }
1000
1001 fn invalidate(
1004 &mut self,
1005 invalidation_rect: Option<PictureRect>,
1006 reason: InvalidationReason,
1007 ) {
1008 self.is_valid = false;
1009
1010 match invalidation_rect {
1011 Some(rect) => {
1012 self.local_dirty_rect = self.local_dirty_rect.union(&rect);
1013 }
1014 None => {
1015 self.local_dirty_rect = self.local_tile_rect;
1016 }
1017 }
1018
1019 if self.invalidation_reason.is_none() {
1020 self.invalidation_reason = Some(reason);
1021 }
1022 }
1023
1024 fn pre_update(
1027 &mut self,
1028 ctx: &TilePreUpdateContext,
1029 ) {
1030 self.local_tile_rect = PictureRect::from_origin_and_size(
1031 PicturePoint::new(
1032 self.tile_offset.x as f32 * ctx.tile_size.width,
1033 self.tile_offset.y as f32 * ctx.tile_size.height,
1034 ),
1035 ctx.tile_size,
1036 );
1037 self.local_valid_rect = PictureBox2D::new(
1041 PicturePoint::new( 1.0e32, 1.0e32),
1042 PicturePoint::new(-1.0e32, -1.0e32),
1043 );
1044 self.invalidation_reason = None;
1045
1046 self.world_tile_rect = ctx.pic_to_world_mapper
1047 .map(&self.local_tile_rect)
1048 .expect("bug: map local tile rect");
1049
1050 self.is_visible = self.world_tile_rect.intersects(&ctx.global_screen_world_rect);
1052
1053 if !self.is_visible {
1057 return;
1058 }
1059
1060 if ctx.background_color != self.background_color {
1061 self.invalidate(None, InvalidationReason::BackgroundColor {
1062 old: self.background_color,
1063 new: ctx.background_color });
1064 self.background_color = ctx.background_color;
1065 }
1066
1067 mem::swap(
1070 &mut self.current_descriptor,
1071 &mut self.prev_descriptor,
1072 );
1073 self.current_descriptor.clear();
1074 self.root.clear(self.local_tile_rect);
1075
1076 self.last_updated_frame_id = ctx.frame_id;
1079 }
1080
1081 fn add_prim_dependency(
1083 &mut self,
1084 info: &PrimitiveDependencyInfo,
1085 ) {
1086 if !self.is_visible {
1089 return;
1090 }
1091
1092 self.local_valid_rect = self.local_valid_rect.union(&info.prim_clip_box);
1096
1097 self.current_descriptor.images.extend_from_slice(&info.images);
1099
1100 self.current_descriptor.opacity_bindings.extend_from_slice(&info.opacity_bindings);
1102
1103 self.current_descriptor.clips.extend_from_slice(&info.clips);
1105
1106 for spatial_node_index in &info.spatial_nodes {
1108 self.current_descriptor.transforms.push(
1109 SpatialNodeKey {
1110 spatial_node_index: *spatial_node_index,
1111 frame_id: self.last_updated_frame_id,
1112 }
1113 );
1114 }
1115
1116 if info.color_binding.is_some() {
1118 self.current_descriptor.color_bindings.insert(
1119 self.current_descriptor.color_bindings.len(), info.color_binding.unwrap());
1120 }
1121
1122 let tile_p0 = self.local_tile_rect.min;
1136 let tile_p1 = self.local_tile_rect.max;
1137
1138 let prim_clip_box = PictureBox2D::new(
1139 PicturePoint::new(
1140 clampf(info.prim_clip_box.min.x, tile_p0.x, tile_p1.x),
1141 clampf(info.prim_clip_box.min.y, tile_p0.y, tile_p1.y),
1142 ),
1143 PicturePoint::new(
1144 clampf(info.prim_clip_box.max.x, tile_p0.x, tile_p1.x),
1145 clampf(info.prim_clip_box.max.y, tile_p0.y, tile_p1.y),
1146 ),
1147 );
1148
1149 let prim_index = PrimitiveDependencyIndex(self.current_descriptor.prims.len() as u32);
1151
1152 debug_assert!(info.spatial_nodes.len() <= MAX_PRIM_SUB_DEPS);
1155 debug_assert!(info.clips.len() <= MAX_PRIM_SUB_DEPS);
1156 debug_assert!(info.images.len() <= MAX_PRIM_SUB_DEPS);
1157 debug_assert!(info.opacity_bindings.len() <= MAX_PRIM_SUB_DEPS);
1158
1159 self.current_descriptor.prims.push(PrimitiveDescriptor {
1160 prim_uid: info.prim_uid,
1161 prim_clip_box,
1162 transform_dep_count: info.spatial_nodes.len() as u8,
1163 clip_dep_count: info.clips.len() as u8,
1164 image_dep_count: info.images.len() as u8,
1165 opacity_binding_dep_count: info.opacity_bindings.len() as u8,
1166 color_binding_dep_count: if info.color_binding.is_some() { 1 } else { 0 } as u8,
1167 });
1168
1169 self.root.add_prim(prim_index, &info.prim_clip_box);
1171 }
1172
1173 fn post_update(
1176 &mut self,
1177 ctx: &TilePostUpdateContext,
1178 state: &mut TilePostUpdateState,
1179 frame_context: &FrameVisibilityContext,
1180 ) -> bool {
1181 state.spatial_node_comparer.retain_for_frame(self.last_updated_frame_id);
1186
1187 if !self.is_visible {
1191 return false;
1192 }
1193
1194 self.current_descriptor.local_valid_rect = self.local_valid_rect;
1196
1197 self.current_descriptor.local_valid_rect = self.local_tile_rect
1208 .intersection(&ctx.local_rect)
1209 .and_then(|r| r.intersection(&self.current_descriptor.local_valid_rect))
1210 .unwrap_or_else(PictureRect::zero);
1211
1212 self.world_valid_rect = ctx.pic_to_world_mapper
1215 .map(&self.current_descriptor.local_valid_rect)
1216 .expect("bug: map local valid rect");
1217
1218 let device_rect = (self.world_tile_rect * ctx.global_device_pixel_scale).round();
1223 self.device_valid_rect = (self.world_valid_rect * ctx.global_device_pixel_scale)
1224 .round_out()
1225 .intersection(&device_rect)
1226 .unwrap_or_else(DeviceRect::zero);
1227
1228 self.update_content_validity(ctx, state, frame_context);
1230
1231 if self.current_descriptor.prims.is_empty() {
1233 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { mut id, .. }, .. }) = self.surface.take() {
1238 if let Some(id) = id.take() {
1239 state.resource_cache.destroy_compositor_tile(id);
1240 }
1241 }
1242
1243 self.is_visible = false;
1244 return false;
1245 }
1246
1247 let clipped_rect = self.current_descriptor.local_valid_rect
1251 .intersection(&ctx.local_clip_rect)
1252 .unwrap_or_else(PictureRect::zero);
1253
1254 let has_opaque_bg_color = self.background_color.map_or(false, |c| c.a >= 1.0);
1255 let has_opaque_backdrop = ctx.backdrop.map_or(false, |b| b.opaque_rect.contains_box(&clipped_rect));
1256 let is_opaque = has_opaque_bg_color || has_opaque_backdrop;
1257
1258 self.z_id = ctx.z_id;
1260
1261 if is_opaque != self.is_opaque {
1262 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = self.surface {
1270 if let Some(id) = id.take() {
1271 state.resource_cache.destroy_compositor_tile(id);
1272 }
1273 }
1274
1275 self.invalidate(None, InvalidationReason::SurfaceOpacityChanged { became_opaque: is_opaque });
1277 self.is_opaque = is_opaque;
1278 }
1279
1280 let (supports_dirty_rects, supports_simple_prims) = match state.composite_state.compositor_kind {
1285 CompositorKind::Draw { .. } => {
1286 (frame_context.config.gpu_supports_render_target_partial_update, true)
1287 }
1288 CompositorKind::Native { capabilities, .. } => {
1289 (capabilities.max_update_rects > 0, false)
1290 }
1291 };
1292
1293 if supports_dirty_rects {
1296 if ctx.current_tile_size == state.resource_cache.texture_cache.default_picture_tile_size() {
1298 let max_split_level = 3;
1299
1300 self.root.maybe_merge_or_split(
1302 0,
1303 &self.current_descriptor.prims,
1304 max_split_level,
1305 );
1306 }
1307 }
1308
1309 if !self.is_valid && !supports_dirty_rects {
1313 self.local_dirty_rect = self.local_tile_rect;
1314 }
1315
1316 let is_simple_prim =
1322 ctx.backdrop.map_or(false, |b| b.kind.is_some()) &&
1323 self.current_descriptor.prims.len() == 1 &&
1324 self.is_opaque &&
1325 supports_simple_prims;
1326
1327 let surface = if is_simple_prim {
1329 match ctx.backdrop.unwrap().kind {
1333 Some(BackdropKind::Color { color }) => {
1334 TileSurface::Color {
1335 color,
1336 }
1337 }
1338 Some(BackdropKind::Clear) => {
1339 TileSurface::Clear
1340 }
1341 None => {
1342 unreachable!();
1344 }
1345 }
1346 } else {
1347 match self.surface.take() {
1352 Some(TileSurface::Texture { descriptor }) => {
1353 TileSurface::Texture {
1355 descriptor,
1356 }
1357 }
1358 Some(TileSurface::Color { .. }) | Some(TileSurface::Clear) | None => {
1359 let descriptor = match state.composite_state.compositor_kind {
1364 CompositorKind::Draw { .. } => {
1365 SurfaceTextureDescriptor::TextureCache {
1368 handle: TextureCacheHandle::invalid(),
1369 }
1370 }
1371 CompositorKind::Native { .. } => {
1372 SurfaceTextureDescriptor::Native {
1376 id: None,
1377 }
1378 }
1379 };
1380
1381 TileSurface::Texture {
1382 descriptor,
1383 }
1384 }
1385 }
1386 };
1387
1388 self.surface = Some(surface);
1390
1391 true
1392 }
1393}
1394
1395#[derive(Debug, Copy, Clone)]
1397#[cfg_attr(feature = "capture", derive(Serialize))]
1398#[cfg_attr(feature = "replay", derive(Deserialize))]
1399pub struct PrimitiveDescriptor {
1400 pub prim_uid: ItemUid,
1402 pub prim_clip_box: PictureBox2D,
1406 transform_dep_count: u8,
1408 image_dep_count: u8,
1409 opacity_binding_dep_count: u8,
1410 clip_dep_count: u8,
1411 color_binding_dep_count: u8,
1412}
1413
1414impl PartialEq for PrimitiveDescriptor {
1415 fn eq(&self, other: &Self) -> bool {
1416 const EPSILON: f32 = 0.001;
1417
1418 if self.prim_uid != other.prim_uid {
1419 return false;
1420 }
1421
1422 if !self.prim_clip_box.min.x.approx_eq_eps(&other.prim_clip_box.min.x, &EPSILON) {
1423 return false;
1424 }
1425 if !self.prim_clip_box.min.y.approx_eq_eps(&other.prim_clip_box.min.y, &EPSILON) {
1426 return false;
1427 }
1428 if !self.prim_clip_box.max.x.approx_eq_eps(&other.prim_clip_box.max.x, &EPSILON) {
1429 return false;
1430 }
1431 if !self.prim_clip_box.max.y.approx_eq_eps(&other.prim_clip_box.max.y, &EPSILON) {
1432 return false;
1433 }
1434
1435 true
1436 }
1437}
1438
1439struct CompareHelper<'a, T> where T: Copy {
1441 offset_curr: usize,
1442 offset_prev: usize,
1443 curr_items: &'a [T],
1444 prev_items: &'a [T],
1445}
1446
1447impl<'a, T> CompareHelper<'a, T> where T: Copy + PartialEq {
1448 fn new(
1450 prev_items: &'a [T],
1451 curr_items: &'a [T],
1452 ) -> Self {
1453 CompareHelper {
1454 offset_curr: 0,
1455 offset_prev: 0,
1456 curr_items,
1457 prev_items,
1458 }
1459 }
1460
1461 fn reset(&mut self) {
1463 self.offset_prev = 0;
1464 self.offset_curr = 0;
1465 }
1466
1467 fn is_same<F>(
1470 &self,
1471 prev_count: u8,
1472 curr_count: u8,
1473 mut f: F,
1474 opt_detail: Option<&mut CompareHelperResult<T>>,
1475 ) -> bool where F: FnMut(&T, &T) -> bool {
1476 if prev_count != curr_count {
1478 if let Some(detail) = opt_detail { *detail = CompareHelperResult::Count{ prev_count, curr_count }; }
1479 return false;
1480 }
1481 if curr_count == 0 {
1483 if let Some(detail) = opt_detail { *detail = CompareHelperResult::Equal; }
1484 return true;
1485 }
1486 if curr_count as usize == MAX_PRIM_SUB_DEPS {
1489 if let Some(detail) = opt_detail { *detail = CompareHelperResult::Sentinel; }
1490 return false;
1491 }
1492
1493 let end_prev = self.offset_prev + prev_count as usize;
1494 let end_curr = self.offset_curr + curr_count as usize;
1495
1496 let curr_items = &self.curr_items[self.offset_curr .. end_curr];
1497 let prev_items = &self.prev_items[self.offset_prev .. end_prev];
1498
1499 for (curr, prev) in curr_items.iter().zip(prev_items.iter()) {
1500 if !f(prev, curr) {
1501 if let Some(detail) = opt_detail { *detail = CompareHelperResult::PredicateTrue{ curr: *curr }; }
1502 return false;
1503 }
1504 }
1505
1506 if let Some(detail) = opt_detail { *detail = CompareHelperResult::Equal; }
1507 true
1508 }
1509
1510 fn advance_prev(&mut self, count: u8) {
1512 self.offset_prev += count as usize;
1513 }
1514
1515 fn advance_curr(&mut self, count: u8) {
1517 self.offset_curr += count as usize;
1518 }
1519}
1520
1521#[cfg_attr(any(feature="capture",feature="replay"), derive(Clone))]
1524#[cfg_attr(feature = "capture", derive(Serialize))]
1525#[cfg_attr(feature = "replay", derive(Deserialize))]
1526pub struct TileDescriptor {
1527 pub prims: Vec<PrimitiveDescriptor>,
1531
1532 clips: Vec<ItemUid>,
1534
1535 images: Vec<ImageDependency>,
1537
1538 opacity_bindings: Vec<OpacityBinding>,
1541
1542 transforms: Vec<SpatialNodeKey>,
1545
1546 pub local_valid_rect: PictureRect,
1548
1549 color_bindings: Vec<ColorBinding>,
1552}
1553
1554impl TileDescriptor {
1555 fn new() -> Self {
1556 TileDescriptor {
1557 prims: Vec::new(),
1558 clips: Vec::new(),
1559 opacity_bindings: Vec::new(),
1560 images: Vec::new(),
1561 transforms: Vec::new(),
1562 local_valid_rect: PictureRect::zero(),
1563 color_bindings: Vec::new(),
1564 }
1565 }
1566
1567 fn print(&self, pt: &mut dyn PrintTreePrinter) {
1569 pt.new_level("current_descriptor".to_string());
1570
1571 pt.new_level("prims".to_string());
1572 for prim in &self.prims {
1573 pt.new_level(format!("prim uid={}", prim.prim_uid.get_uid()));
1574 pt.add_item(format!("clip: p0={},{} p1={},{}",
1575 prim.prim_clip_box.min.x,
1576 prim.prim_clip_box.min.y,
1577 prim.prim_clip_box.max.x,
1578 prim.prim_clip_box.max.y,
1579 ));
1580 pt.add_item(format!("deps: t={} i={} o={} c={} color={}",
1581 prim.transform_dep_count,
1582 prim.image_dep_count,
1583 prim.opacity_binding_dep_count,
1584 prim.clip_dep_count,
1585 prim.color_binding_dep_count,
1586 ));
1587 pt.end_level();
1588 }
1589 pt.end_level();
1590
1591 if !self.clips.is_empty() {
1592 pt.new_level("clips".to_string());
1593 for clip in &self.clips {
1594 pt.new_level(format!("clip uid={}", clip.get_uid()));
1595 pt.end_level();
1596 }
1597 pt.end_level();
1598 }
1599
1600 if !self.images.is_empty() {
1601 pt.new_level("images".to_string());
1602 for info in &self.images {
1603 pt.new_level(format!("key={:?}", info.key));
1604 pt.add_item(format!("generation={:?}", info.generation));
1605 pt.end_level();
1606 }
1607 pt.end_level();
1608 }
1609
1610 if !self.opacity_bindings.is_empty() {
1611 pt.new_level("opacity_bindings".to_string());
1612 for opacity_binding in &self.opacity_bindings {
1613 pt.new_level(format!("binding={:?}", opacity_binding));
1614 pt.end_level();
1615 }
1616 pt.end_level();
1617 }
1618
1619 if !self.transforms.is_empty() {
1620 pt.new_level("transforms".to_string());
1621 for transform in &self.transforms {
1622 pt.new_level(format!("spatial_node={:?}", transform));
1623 pt.end_level();
1624 }
1625 pt.end_level();
1626 }
1627
1628 if !self.color_bindings.is_empty() {
1629 pt.new_level("color_bindings".to_string());
1630 for color_binding in &self.color_bindings {
1631 pt.new_level(format!("binding={:?}", color_binding));
1632 pt.end_level();
1633 }
1634 pt.end_level();
1635 }
1636
1637 pt.end_level();
1638 }
1639
1640 fn clear(&mut self) {
1643 self.prims.clear();
1644 self.clips.clear();
1645 self.opacity_bindings.clear();
1646 self.images.clear();
1647 self.transforms.clear();
1648 self.local_valid_rect = PictureRect::zero();
1649 self.color_bindings.clear();
1650 }
1651}
1652
1653#[derive(Clone)]
1655pub struct DirtyRegion {
1656 pub filters: Vec<BatchFilter>,
1658
1659 pub combined: WorldRect,
1661
1662 spatial_node_index: SpatialNodeIndex,
1664}
1665
1666impl DirtyRegion {
1667 pub fn new(
1669 spatial_node_index: SpatialNodeIndex,
1670 ) -> Self {
1671 DirtyRegion {
1672 filters: Vec::with_capacity(16),
1673 combined: WorldRect::zero(),
1674 spatial_node_index,
1675 }
1676 }
1677
1678 pub fn reset(
1680 &mut self,
1681 spatial_node_index: SpatialNodeIndex,
1682 ) {
1683 self.filters.clear();
1684 self.combined = WorldRect::zero();
1685 self.spatial_node_index = spatial_node_index;
1686 }
1687
1688 pub fn add_dirty_region(
1691 &mut self,
1692 rect_in_pic_space: PictureRect,
1693 sub_slice_index: SubSliceIndex,
1694 spatial_tree: &SpatialTree,
1695 ) {
1696 let map_pic_to_world = SpaceMapper::new_with_target(
1697 ROOT_SPATIAL_NODE_INDEX,
1698 self.spatial_node_index,
1699 WorldRect::max_rect(),
1700 spatial_tree,
1701 );
1702
1703 let world_rect = map_pic_to_world
1704 .map(&rect_in_pic_space)
1705 .expect("bug");
1706
1707 self.combined = self.combined.union(&world_rect);
1709
1710 self.filters.push(BatchFilter {
1711 rect_in_pic_space,
1712 sub_slice_index,
1713 });
1714 }
1715
1716 pub fn inflate(
1719 &self,
1720 inflate_amount: f32,
1721 spatial_tree: &SpatialTree,
1722 ) -> DirtyRegion {
1723 let map_pic_to_world = SpaceMapper::new_with_target(
1724 ROOT_SPATIAL_NODE_INDEX,
1725 self.spatial_node_index,
1726 WorldRect::max_rect(),
1727 spatial_tree,
1728 );
1729
1730 let mut filters = Vec::with_capacity(self.filters.len());
1731 let mut combined = WorldRect::zero();
1732
1733 for filter in &self.filters {
1734 let rect_in_pic_space = filter.rect_in_pic_space.inflate(inflate_amount, inflate_amount);
1735
1736 let world_rect = map_pic_to_world
1737 .map(&rect_in_pic_space)
1738 .expect("bug");
1739
1740 combined = combined.union(&world_rect);
1741 filters.push(BatchFilter {
1742 rect_in_pic_space,
1743 sub_slice_index: filter.sub_slice_index,
1744 });
1745 }
1746
1747 DirtyRegion {
1748 filters,
1749 combined,
1750 spatial_node_index: self.spatial_node_index,
1751 }
1752 }
1753}
1754
1755#[derive(Debug, Copy, Clone)]
1756pub enum BackdropKind {
1757 Color {
1758 color: ColorF,
1759 },
1760 Clear,
1761}
1762
1763#[derive(Debug, Copy, Clone)]
1765pub struct BackdropInfo {
1766 pub opaque_rect: PictureRect,
1770 pub kind: Option<BackdropKind>,
1772}
1773
1774impl BackdropInfo {
1775 fn empty() -> Self {
1776 BackdropInfo {
1777 opaque_rect: PictureRect::zero(),
1778 kind: None,
1779 }
1780 }
1781}
1782
1783#[derive(Clone)]
1784pub struct TileCacheLoggerSlice {
1785 pub serialized_slice: String,
1786 pub local_to_world_transform: Transform3D<f32, PicturePixel, WorldPixel>,
1787}
1788
1789#[cfg(any(feature = "capture", feature = "replay"))]
1790macro_rules! declare_tile_cache_logger_updatelists {
1791 ( $( $name:ident : $ty:ty, )+ ) => {
1792 #[cfg_attr(feature = "capture", derive(Serialize))]
1793 #[cfg_attr(feature = "replay", derive(Deserialize))]
1794 struct TileCacheLoggerUpdateListsSerializer {
1795 pub ron_string: Vec<String>,
1796 }
1797
1798 pub struct TileCacheLoggerUpdateLists {
1799 $(
1800 pub $name: (Vec<String>, Vec<UpdateList<<$ty as Internable>::Key>>),
1808 )+
1809 }
1810
1811 impl TileCacheLoggerUpdateLists {
1812 pub fn new() -> Self {
1813 TileCacheLoggerUpdateLists {
1814 $(
1815 $name : ( Vec::new(), Vec::new() ),
1816 )+
1817 }
1818 }
1819
1820 #[cfg(feature = "capture")]
1822 fn serialize_updates(
1823 &mut self,
1824 updates: &InternerUpdates
1825 ) {
1826 $(
1827 self.$name.0.push(ron::ser::to_string_pretty(&updates.$name, Default::default()).unwrap());
1828 )+
1829 }
1830
1831 fn is_empty(&self) -> bool {
1832 $(
1833 if !self.$name.0.is_empty() { return false; }
1834 )+
1835 true
1836 }
1837
1838 #[cfg(feature = "capture")]
1839 fn to_ron(&self) -> String {
1840 let mut serializer =
1841 TileCacheLoggerUpdateListsSerializer { ron_string: Vec::new() };
1842 $(
1843 serializer.ron_string.push(
1844 ron::ser::to_string_pretty(&self.$name.0, Default::default()).unwrap());
1845 )+
1846 ron::ser::to_string_pretty(&serializer, Default::default()).unwrap()
1847 }
1848
1849 #[cfg(feature = "replay")]
1850 pub fn from_ron(&mut self, text: &str) {
1851 let serializer : TileCacheLoggerUpdateListsSerializer =
1852 match ron::de::from_str(&text) {
1853 Ok(data) => { data }
1854 Err(e) => {
1855 println!("ERROR: failed to deserialize updatelist: {:?}\n{:?}", &text, e);
1856 return;
1857 }
1858 };
1859 let mut index = 0;
1860 $(
1861 let ron_lists : Vec<String> = ron::de::from_str(&serializer.ron_string[index]).unwrap();
1862 self.$name.1 = ron_lists.iter()
1863 .map( |list| ron::de::from_str(&list).unwrap() )
1864 .collect();
1865 index = index + 1;
1866 )+
1867 let _ = index;
1869 }
1870
1871 #[cfg(feature = "replay")]
1878 pub fn insert_in_lookup(
1879 &mut self,
1880 itemuid_to_string: &mut HashMap<ItemUid, String>)
1881 {
1882 $(
1883 {
1884 for list in &self.$name.1 {
1885 for insertion in &list.insertions {
1886 itemuid_to_string.insert(
1887 insertion.uid,
1888 format!("{:?}", insertion.value));
1889 }
1890 }
1891 }
1892 )+
1893 }
1894 }
1895 }
1896}
1897
1898#[cfg(any(feature = "capture", feature = "replay"))]
1899crate::enumerate_interners!(declare_tile_cache_logger_updatelists);
1900
1901#[cfg(not(any(feature = "capture", feature = "replay")))]
1902pub struct TileCacheLoggerUpdateLists {
1903}
1904
1905#[cfg(not(any(feature = "capture", feature = "replay")))]
1906impl TileCacheLoggerUpdateLists {
1907 pub fn new() -> Self { TileCacheLoggerUpdateLists {} }
1908 fn is_empty(&self) -> bool { true }
1909}
1910
1911pub struct TileCacheLoggerFrame {
1916 pub slices: Vec<TileCacheLoggerSlice>,
1918 pub update_lists: TileCacheLoggerUpdateLists
1920}
1921
1922impl TileCacheLoggerFrame {
1923 pub fn new() -> Self {
1924 TileCacheLoggerFrame {
1925 slices: Vec::new(),
1926 update_lists: TileCacheLoggerUpdateLists::new()
1927 }
1928 }
1929
1930 pub fn is_empty(&self) -> bool {
1931 self.slices.is_empty() && self.update_lists.is_empty()
1932 }
1933}
1934
1935pub struct TileCacheLogger {
1937 pub write_index : usize,
1939 pub frames: Vec<TileCacheLoggerFrame>
1941}
1942
1943impl TileCacheLogger {
1944 pub fn new(
1945 num_frames: usize
1946 ) -> Self {
1947 let mut frames = Vec::with_capacity(num_frames);
1948 for _i in 0..num_frames { frames.push(TileCacheLoggerFrame::new());
1950 }
1951 TileCacheLogger {
1952 write_index: 0,
1953 frames
1954 }
1955 }
1956
1957 pub fn is_enabled(&self) -> bool {
1958 !self.frames.is_empty()
1959 }
1960
1961 #[cfg(feature = "capture")]
1962 pub fn add(
1963 &mut self,
1964 serialized_slice: String,
1965 local_to_world_transform: Transform3D<f32, PicturePixel, WorldPixel>
1966 ) {
1967 if !self.is_enabled() {
1968 return;
1969 }
1970 self.frames[self.write_index].slices.push(
1971 TileCacheLoggerSlice {
1972 serialized_slice,
1973 local_to_world_transform });
1974 }
1975
1976 #[cfg(feature = "capture")]
1977 pub fn serialize_updates(&mut self, updates: &InternerUpdates) {
1978 if !self.is_enabled() {
1979 return;
1980 }
1981 self.frames[self.write_index].update_lists.serialize_updates(updates);
1982 }
1983
1984 pub fn advance(&mut self) {
1988 if !self.is_enabled() || self.frames[self.write_index].is_empty() {
1989 return;
1990 }
1991 self.write_index = self.write_index + 1;
1992 if self.write_index >= self.frames.len() {
1993 self.write_index = 0;
1994 }
1995 self.frames[self.write_index] = TileCacheLoggerFrame::new();
1996 }
1997
1998 #[cfg(feature = "capture")]
1999 pub fn save_capture(
2000 &self, root: &PathBuf
2001 ) {
2002 if !self.is_enabled() {
2003 return;
2004 }
2005 use std::fs;
2006
2007 info!("saving tile cache log");
2008 let path_tile_cache = root.join("tile_cache");
2009 if !path_tile_cache.is_dir() {
2010 fs::create_dir(&path_tile_cache).unwrap();
2011 }
2012
2013 let mut files_written = 0;
2014 for ix in 0..self.frames.len() {
2015 let index = (self.write_index + 1 + ix) % self.frames.len();
2020 if self.frames[index].is_empty() {
2021 continue;
2022 }
2023
2024 let filename = path_tile_cache.join(format!("frame{:05}.ron", files_written));
2025 let mut output = File::create(filename).unwrap();
2026 output.write_all(b"// slice data\n").unwrap();
2027 output.write_all(b"[\n").unwrap();
2028 for item in &self.frames[index].slices {
2029 output.write_all(b"( transform:\n").unwrap();
2030 let transform =
2031 ron::ser::to_string_pretty(
2032 &item.local_to_world_transform, Default::default()).unwrap();
2033 output.write_all(transform.as_bytes()).unwrap();
2034 output.write_all(b",\n tile_cache:\n").unwrap();
2035 output.write_all(item.serialized_slice.as_bytes()).unwrap();
2036 output.write_all(b"\n),\n").unwrap();
2037 }
2038 output.write_all(b"]\n\n").unwrap();
2039
2040 output.write_all(b"// @@@ chunk @@@\n\n").unwrap();
2041
2042 output.write_all(b"// interning data\n").unwrap();
2043 output.write_all(self.frames[index].update_lists.to_ron().as_bytes()).unwrap();
2044
2045 files_written = files_written + 1;
2046 }
2047 }
2048}
2049
2050pub struct NativeSurface {
2062 pub opaque: NativeSurfaceId,
2064 pub alpha: NativeSurfaceId,
2066}
2067
2068#[derive(PartialEq, Eq, Hash)]
2070pub struct ExternalNativeSurfaceKey {
2071 pub image_keys: [ImageKey; 3],
2073 pub size: DeviceIntSize,
2075 pub is_external_surface: bool,
2078}
2079
2080pub struct ExternalNativeSurface {
2082 pub used_this_frame: bool,
2085 pub native_surface_id: NativeSurfaceId,
2087 pub image_dependencies: [ImageDependency; 3],
2091}
2092
2093#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2096#[cfg_attr(feature = "capture", derive(Serialize))]
2097#[cfg_attr(feature = "replay", derive(Deserialize))]
2098pub struct SliceId(usize);
2099
2100impl SliceId {
2101 pub fn new(index: usize) -> Self {
2102 SliceId(index)
2103 }
2104}
2105
2106pub struct TileCacheParams {
2109 pub slice: usize,
2111 pub slice_flags: SliceFlags,
2113 pub spatial_node_index: SpatialNodeIndex,
2115 pub background_color: Option<ColorF>,
2118 pub shared_clips: Vec<ClipInstance>,
2120 pub shared_clip_chain: ClipChainId,
2122 pub virtual_surface_size: i32,
2124 pub compositor_surface_count: usize,
2128}
2129
2130#[cfg_attr(feature = "capture", derive(Serialize))]
2133#[cfg_attr(feature = "replay", derive(Deserialize))]
2134#[derive(Debug, Copy, Clone, PartialEq)]
2135pub struct SubSliceIndex(u8);
2136
2137impl SubSliceIndex {
2138 pub const DEFAULT: SubSliceIndex = SubSliceIndex(0);
2139
2140 pub fn new(index: usize) -> Self {
2141 SubSliceIndex(index as u8)
2142 }
2143
2144 pub fn is_primary(&self) -> bool {
2147 self.0 == 0
2148 }
2149}
2150
2151pub struct CompositorSurface {
2154 pub descriptor: ExternalSurfaceDescriptor,
2156 prohibited_rect: PictureRect,
2159 pub is_opaque: bool,
2161}
2162
2163pub struct SubSlice {
2168 pub tiles: FastHashMap<TileOffset, Box<Tile>>,
2170 pub native_surface: Option<NativeSurface>,
2174 pub compositor_surfaces: Vec<CompositorSurface>,
2177 pub composite_tiles: Vec<CompositeTile>,
2179 pub opaque_tile_descriptors: Vec<CompositeTileDescriptor>,
2181 pub alpha_tile_descriptors: Vec<CompositeTileDescriptor>,
2183}
2184
2185impl SubSlice {
2186 fn new() -> Self {
2188 SubSlice {
2189 tiles: FastHashMap::default(),
2190 native_surface: None,
2191 compositor_surfaces: Vec::new(),
2192 composite_tiles: Vec::new(),
2193 opaque_tile_descriptors: Vec::new(),
2194 alpha_tile_descriptors: Vec::new(),
2195 }
2196 }
2197
2198 fn reset(&mut self) {
2201 self.compositor_surfaces.clear();
2202 self.composite_tiles.clear();
2203 self.opaque_tile_descriptors.clear();
2204 self.alpha_tile_descriptors.clear();
2205 }
2206
2207 fn resize(&mut self, new_tile_rect: TileRect) -> FastHashMap<TileOffset, Box<Tile>> {
2209 let mut old_tiles = mem::replace(&mut self.tiles, FastHashMap::default());
2210 self.tiles.reserve(new_tile_rect.area() as usize);
2211
2212 for y in new_tile_rect.min.y .. new_tile_rect.max.y {
2213 for x in new_tile_rect.min.x .. new_tile_rect.max.x {
2214 let key = TileOffset::new(x, y);
2215 let tile = old_tiles
2216 .remove(&key)
2217 .unwrap_or_else(|| {
2218 Box::new(Tile::new(key))
2219 });
2220 self.tiles.insert(key, tile);
2221 }
2222 }
2223
2224 old_tiles
2225 }
2226}
2227
2228pub struct TileCacheInstance {
2230 pub slice: usize,
2237 pub slice_flags: SliceFlags,
2239 pub current_tile_size: DeviceIntSize,
2241 pub sub_slices: Vec<SubSlice>,
2243 pub spatial_node_index: SpatialNodeIndex,
2245 opacity_bindings: FastHashMap<PropertyBindingId, OpacityBindingInfo>,
2248 old_opacity_bindings: FastHashMap<PropertyBindingId, OpacityBindingInfo>,
2250 spatial_node_comparer: SpatialNodeComparer,
2252 color_bindings: FastHashMap<PropertyBindingId, ColorBindingInfo>,
2255 old_color_bindings: FastHashMap<PropertyBindingId, ColorBindingInfo>,
2257 pub dirty_region: DirtyRegion,
2259 tile_size: PictureSize,
2261 tile_rect: TileRect,
2263 tile_bounds_p0: TileOffset,
2266 tile_bounds_p1: TileOffset,
2267 pub local_rect: PictureRect,
2269 pub local_clip_rect: PictureRect,
2271 surface_index: SurfaceIndex,
2273 pub background_color: Option<ColorF>,
2276 pub backdrop: BackdropInfo,
2278 pub subpixel_mode: SubpixelMode,
2281 pub shared_clips: Vec<ClipInstance>,
2286 shared_clip_chain: ClipChainId,
2289 frames_until_size_eval: usize,
2294 virtual_offset: DeviceIntPoint,
2301 compare_cache: FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
2304 tile_size_override: Option<DeviceIntSize>,
2307 pub external_native_surface_cache: FastHashMap<ExternalNativeSurfaceKey, ExternalNativeSurface>,
2309 frame_id: FrameId,
2311 pub transform_index: CompositorTransformIndex,
2313 local_to_surface: ScaleOffset,
2315 invalidate_all_tiles: bool,
2317 surface_to_device: ScaleOffset,
2319 current_raster_scale: f32,
2321 current_surface_traversal_depth: usize,
2323}
2324
2325enum SurfacePromotionResult {
2326 Failed,
2327 Success,
2328}
2329
2330impl TileCacheInstance {
2331 pub fn new(params: TileCacheParams) -> Self {
2332 let sub_slice_count = params.compositor_surface_count.min(MAX_COMPOSITOR_SURFACES) + 1;
2335
2336 let mut sub_slices = Vec::with_capacity(sub_slice_count);
2337 for _ in 0 .. sub_slice_count {
2338 sub_slices.push(SubSlice::new());
2339 }
2340
2341 TileCacheInstance {
2342 slice: params.slice,
2343 slice_flags: params.slice_flags,
2344 spatial_node_index: params.spatial_node_index,
2345 sub_slices,
2346 opacity_bindings: FastHashMap::default(),
2347 old_opacity_bindings: FastHashMap::default(),
2348 spatial_node_comparer: SpatialNodeComparer::new(),
2349 color_bindings: FastHashMap::default(),
2350 old_color_bindings: FastHashMap::default(),
2351 dirty_region: DirtyRegion::new(params.spatial_node_index),
2352 tile_size: PictureSize::zero(),
2353 tile_rect: TileRect::zero(),
2354 tile_bounds_p0: TileOffset::zero(),
2355 tile_bounds_p1: TileOffset::zero(),
2356 local_rect: PictureRect::zero(),
2357 local_clip_rect: PictureRect::zero(),
2358 surface_index: SurfaceIndex(0),
2359 background_color: params.background_color,
2360 backdrop: BackdropInfo::empty(),
2361 subpixel_mode: SubpixelMode::Allow,
2362 shared_clips: params.shared_clips,
2363 shared_clip_chain: params.shared_clip_chain,
2364 current_tile_size: DeviceIntSize::zero(),
2365 frames_until_size_eval: 0,
2366 virtual_offset: DeviceIntPoint::new(
2368 params.virtual_surface_size / 2,
2369 params.virtual_surface_size / 2,
2370 ),
2371 compare_cache: FastHashMap::default(),
2372 tile_size_override: None,
2373 external_native_surface_cache: FastHashMap::default(),
2374 frame_id: FrameId::INVALID,
2375 transform_index: CompositorTransformIndex::INVALID,
2376 surface_to_device: ScaleOffset::identity(),
2377 local_to_surface: ScaleOffset::identity(),
2378 invalidate_all_tiles: true,
2379 current_raster_scale: 1.0,
2380 current_surface_traversal_depth: 0,
2381 }
2382 }
2383
2384 pub fn tile_count(&self) -> usize {
2386 self.tile_rect.area() as usize * self.sub_slices.len()
2387 }
2388
2389 pub fn prepare_for_new_scene(
2393 &mut self,
2394 params: TileCacheParams,
2395 resource_cache: &mut ResourceCache,
2396 ) {
2397 assert_eq!(self.slice, params.slice);
2399
2400 let required_sub_slice_count = params.compositor_surface_count.min(MAX_COMPOSITOR_SURFACES) + 1;
2403
2404 if self.sub_slices.len() != required_sub_slice_count {
2405 self.tile_rect = TileRect::zero();
2406
2407 if self.sub_slices.len() > required_sub_slice_count {
2408 let old_sub_slices = self.sub_slices.split_off(required_sub_slice_count);
2409
2410 for mut sub_slice in old_sub_slices {
2411 for tile in sub_slice.tiles.values_mut() {
2412 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2413 if let Some(id) = id.take() {
2414 resource_cache.destroy_compositor_tile(id);
2415 }
2416 }
2417 }
2418
2419 if let Some(native_surface) = sub_slice.native_surface {
2420 resource_cache.destroy_compositor_surface(native_surface.opaque);
2421 resource_cache.destroy_compositor_surface(native_surface.alpha);
2422 }
2423 }
2424 } else {
2425 while self.sub_slices.len() < required_sub_slice_count {
2426 self.sub_slices.push(SubSlice::new());
2427 }
2428 }
2429 }
2430
2431 self.slice_flags = params.slice_flags;
2435 self.spatial_node_index = params.spatial_node_index;
2436 self.background_color = params.background_color;
2437 self.shared_clips = params.shared_clips;
2438 self.shared_clip_chain = params.shared_clip_chain;
2439
2440 self.frames_until_size_eval = 0;
2443 }
2444
2445 pub fn destroy(
2448 self,
2449 resource_cache: &mut ResourceCache,
2450 ) {
2451 for sub_slice in self.sub_slices {
2452 if let Some(native_surface) = sub_slice.native_surface {
2453 resource_cache.destroy_compositor_surface(native_surface.opaque);
2454 resource_cache.destroy_compositor_surface(native_surface.alpha);
2455 }
2456 }
2457
2458 for (_, external_surface) in self.external_native_surface_cache {
2459 resource_cache.destroy_compositor_surface(external_surface.native_surface_id)
2460 }
2461 }
2462
2463 fn get_tile_coords_for_rect(
2465 &self,
2466 rect: &PictureRect,
2467 ) -> (TileOffset, TileOffset) {
2468 let mut p0 = TileOffset::new(
2470 (rect.min.x / self.tile_size.width).floor() as i32,
2471 (rect.min.y / self.tile_size.height).floor() as i32,
2472 );
2473
2474 let mut p1 = TileOffset::new(
2475 (rect.max.x / self.tile_size.width).ceil() as i32,
2476 (rect.max.y / self.tile_size.height).ceil() as i32,
2477 );
2478
2479 p0.x = clamp(p0.x, self.tile_bounds_p0.x, self.tile_bounds_p1.x);
2481 p0.y = clamp(p0.y, self.tile_bounds_p0.y, self.tile_bounds_p1.y);
2482 p1.x = clamp(p1.x, self.tile_bounds_p0.x, self.tile_bounds_p1.x);
2483 p1.y = clamp(p1.y, self.tile_bounds_p0.y, self.tile_bounds_p1.y);
2484
2485 (p0, p1)
2486 }
2487
2488 pub fn pre_update(
2490 &mut self,
2491 pic_rect: PictureRect,
2492 surface_index: SurfaceIndex,
2493 frame_context: &FrameVisibilityContext,
2494 frame_state: &mut FrameVisibilityState,
2495 ) -> WorldRect {
2496 self.surface_index = surface_index;
2497 self.local_rect = pic_rect;
2498 self.local_clip_rect = PictureRect::max_rect();
2499
2500 for sub_slice in &mut self.sub_slices {
2501 sub_slice.reset();
2502 }
2503
2504 self.backdrop = BackdropInfo::empty();
2507
2508 let pic_to_world_mapper = SpaceMapper::new_with_target(
2509 ROOT_SPATIAL_NODE_INDEX,
2510 self.spatial_node_index,
2511 frame_context.global_screen_world_rect,
2512 frame_context.spatial_tree,
2513 );
2514
2515 if self.shared_clip_chain != ClipChainId::NONE {
2519 let shared_clips = &mut frame_state.scratch.picture.clip_chain_ids;
2520 shared_clips.clear();
2521
2522 let map_local_to_surface = SpaceMapper::new(
2523 self.spatial_node_index,
2524 pic_rect,
2525 );
2526
2527 let mut current_clip_chain_id = self.shared_clip_chain;
2528 while current_clip_chain_id != ClipChainId::NONE {
2529 shared_clips.push(current_clip_chain_id);
2530 let clip_chain_node = &frame_state.clip_store.clip_chain_nodes[current_clip_chain_id.0 as usize];
2531 current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
2532 }
2533
2534 frame_state.clip_store.set_active_clips(
2535 LayoutRect::max_rect(),
2536 self.spatial_node_index,
2537 map_local_to_surface.ref_spatial_node_index,
2538 &shared_clips,
2539 frame_context.spatial_tree,
2540 &mut frame_state.data_stores.clip,
2541 );
2542
2543 let clip_chain_instance = frame_state.clip_store.build_clip_chain_instance(
2544 pic_rect.cast_unit(),
2545 &map_local_to_surface,
2546 &pic_to_world_mapper,
2547 frame_context.spatial_tree,
2548 frame_state.gpu_cache,
2549 frame_state.resource_cache,
2550 frame_context.global_device_pixel_scale,
2551 &frame_context.global_screen_world_rect,
2552 &mut frame_state.data_stores.clip,
2553 true,
2554 false,
2555 );
2556
2557 self.local_clip_rect = clip_chain_instance.map_or(PictureRect::zero(), |clip_chain_instance| {
2561 clip_chain_instance.pic_clip_rect
2562 });
2563 }
2564
2565 self.frame_id.advance();
2568
2569 self.spatial_node_comparer.next_frame(self.spatial_node_index);
2572
2573 for external_native_surface in self.external_native_surface_cache.values_mut() {
2579 external_native_surface.used_this_frame = false;
2580 }
2581
2582 if self.frames_until_size_eval == 0 ||
2586 self.tile_size_override != frame_context.config.tile_size_override {
2587
2588 let desired_tile_size = match frame_context.config.tile_size_override {
2590 Some(tile_size_override) => {
2591 tile_size_override
2592 }
2593 None => {
2594 if self.slice_flags.contains(SliceFlags::IS_SCROLLBAR) {
2595 if pic_rect.width() <= pic_rect.height() {
2596 TILE_SIZE_SCROLLBAR_VERTICAL
2597 } else {
2598 TILE_SIZE_SCROLLBAR_HORIZONTAL
2599 }
2600 } else {
2601 frame_state.resource_cache.texture_cache.default_picture_tile_size()
2602 }
2603 }
2604 };
2605
2606 if desired_tile_size != self.current_tile_size {
2609 for sub_slice in &mut self.sub_slices {
2610 if let Some(native_surface) = sub_slice.native_surface.take() {
2613 frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
2614 frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
2615 }
2616 sub_slice.tiles.clear();
2617 }
2618 self.tile_rect = TileRect::zero();
2619 self.current_tile_size = desired_tile_size;
2620 }
2621
2622 self.frames_until_size_eval = 120;
2625 self.tile_size_override = frame_context.config.tile_size_override;
2626 }
2627
2628 let local_to_device = get_relative_scale_offset(
2630 self.spatial_node_index,
2631 ROOT_SPATIAL_NODE_INDEX,
2632 frame_context.spatial_tree,
2633 );
2634
2635 let mut surface_to_device = local_to_device;
2637
2638 if frame_context.config.low_quality_pinch_zoom {
2639 surface_to_device.scale.x /= self.current_raster_scale;
2640 surface_to_device.scale.y /= self.current_raster_scale;
2641 } else {
2642 surface_to_device.scale.x = 1.0;
2643 surface_to_device.scale.y = 1.0;
2644 }
2645
2646 let local_to_surface = local_to_device.accumulate(&surface_to_device.inverse());
2648
2649 const EPSILON: f32 = 0.001;
2650 let compositor_translation_changed =
2651 !surface_to_device.offset.x.approx_eq_eps(&self.surface_to_device.offset.x, &EPSILON) ||
2652 !surface_to_device.offset.y.approx_eq_eps(&self.surface_to_device.offset.y, &EPSILON);
2653 let compositor_scale_changed =
2654 !surface_to_device.scale.x.approx_eq_eps(&self.surface_to_device.scale.x, &EPSILON) ||
2655 !surface_to_device.scale.y.approx_eq_eps(&self.surface_to_device.scale.y, &EPSILON);
2656 let surface_scale_changed =
2657 !local_to_surface.scale.x.approx_eq_eps(&self.local_to_surface.scale.x, &EPSILON) ||
2658 !local_to_surface.scale.y.approx_eq_eps(&self.local_to_surface.scale.y, &EPSILON);
2659
2660 if compositor_translation_changed ||
2661 compositor_scale_changed ||
2662 surface_scale_changed ||
2663 frame_context.config.force_invalidation {
2664 frame_state.composite_state.dirty_rects_are_valid = false;
2665 }
2666
2667 self.surface_to_device = surface_to_device;
2668 self.local_to_surface = local_to_surface;
2669 self.invalidate_all_tiles = surface_scale_changed || frame_context.config.force_invalidation;
2670
2671 let current_properties = frame_context.scene_properties.float_properties();
2674 mem::swap(&mut self.opacity_bindings, &mut self.old_opacity_bindings);
2675
2676 self.opacity_bindings.clear();
2677 for (id, value) in current_properties {
2678 let changed = match self.old_opacity_bindings.get(id) {
2679 Some(old_property) => !old_property.value.approx_eq(value),
2680 None => true,
2681 };
2682 self.opacity_bindings.insert(*id, OpacityBindingInfo {
2683 value: *value,
2684 changed,
2685 });
2686 }
2687
2688 let current_properties = frame_context.scene_properties.color_properties();
2691 mem::swap(&mut self.color_bindings, &mut self.old_color_bindings);
2692
2693 self.color_bindings.clear();
2694 for (id, value) in current_properties {
2695 let changed = match self.old_color_bindings.get(id) {
2696 Some(old_property) => old_property.value != (*value).into(),
2697 None => true,
2698 };
2699 self.color_bindings.insert(*id, ColorBindingInfo {
2700 value: (*value).into(),
2701 changed,
2702 });
2703 }
2704
2705 let world_tile_size = WorldSize::new(
2706 self.current_tile_size.width as f32 / frame_context.global_device_pixel_scale.0,
2707 self.current_tile_size.height as f32 / frame_context.global_device_pixel_scale.0,
2708 );
2709
2710 self.tile_size = PictureSize::new(
2711 world_tile_size.width / self.local_to_surface.scale.x,
2712 world_tile_size.height / self.local_to_surface.scale.y,
2713 );
2714
2715 let screen_rect_in_pic_space = pic_to_world_mapper
2716 .unmap(&frame_context.global_screen_world_rect)
2717 .expect("unable to unmap screen rect");
2718
2719 let desired_rect_in_pic_space = screen_rect_in_pic_space
2724 .inflate(0.0, 1.0 * self.tile_size.height);
2725
2726 let needed_rect_in_pic_space = desired_rect_in_pic_space
2727 .intersection(&pic_rect)
2728 .unwrap_or_else(Box2D::zero);
2729
2730 let p0 = needed_rect_in_pic_space.min;
2731 let p1 = needed_rect_in_pic_space.max;
2732
2733 let x0 = (p0.x / self.tile_size.width).floor() as i32;
2734 let x1 = (p1.x / self.tile_size.width).ceil() as i32;
2735
2736 let y0 = (p0.y / self.tile_size.height).floor() as i32;
2737 let y1 = (p1.y / self.tile_size.height).ceil() as i32;
2738
2739 let new_tile_rect = TileRect {
2740 min: TileOffset::new(x0, y0),
2741 max: TileOffset::new(x1, y1),
2742 };
2743
2744 let virtual_surface_size = frame_context.config.compositor_kind.get_virtual_surface_size();
2750 if virtual_surface_size > 0 {
2753 let tx0 = self.virtual_offset.x + x0 * self.current_tile_size.width;
2755 let ty0 = self.virtual_offset.y + y0 * self.current_tile_size.height;
2756 let tx1 = self.virtual_offset.x + (x1+1) * self.current_tile_size.width;
2757 let ty1 = self.virtual_offset.y + (y1+1) * self.current_tile_size.height;
2758
2759 let need_new_virtual_offset = tx0 < 0 ||
2760 ty0 < 0 ||
2761 tx1 >= virtual_surface_size ||
2762 ty1 >= virtual_surface_size;
2763
2764 if need_new_virtual_offset {
2765 self.virtual_offset = DeviceIntPoint::new(
2769 (virtual_surface_size/2) - ((x0 + x1) / 2) * self.current_tile_size.width,
2770 (virtual_surface_size/2) - ((y0 + y1) / 2) * self.current_tile_size.height,
2771 );
2772
2773 for sub_slice in &mut self.sub_slices {
2776 for tile in sub_slice.tiles.values_mut() {
2777 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2778 if let Some(id) = id.take() {
2779 frame_state.resource_cache.destroy_compositor_tile(id);
2780 tile.surface = None;
2781 tile.invalidate(None, InvalidationReason::CompositorKindChanged);
2784 }
2785 }
2786 }
2787
2788 if let Some(native_surface) = sub_slice.native_surface.take() {
2791 frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
2792 frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
2793 }
2794 }
2795 }
2796 }
2797
2798 if new_tile_rect != self.tile_rect {
2800 for sub_slice in &mut self.sub_slices {
2801 let mut old_tiles = sub_slice.resize(new_tile_rect);
2802
2803 if !old_tiles.is_empty() {
2805 frame_state.composite_state.dirty_rects_are_valid = false;
2806 }
2807
2808 frame_state.composite_state.destroy_native_tiles(
2813 old_tiles.values_mut(),
2814 frame_state.resource_cache,
2815 );
2816 }
2817 }
2818
2819 self.tile_bounds_p0 = TileOffset::new(x0, y0);
2822 self.tile_bounds_p1 = TileOffset::new(x1, y1);
2823 self.tile_rect = new_tile_rect;
2824
2825 let mut world_culling_rect = WorldRect::zero();
2826
2827 let mut ctx = TilePreUpdateContext {
2828 pic_to_world_mapper,
2829 background_color: self.background_color,
2830 global_screen_world_rect: frame_context.global_screen_world_rect,
2831 tile_size: self.tile_size,
2832 frame_id: self.frame_id,
2833 };
2834
2835 for sub_slice in &mut self.sub_slices {
2837 for tile in sub_slice.tiles.values_mut() {
2838 tile.pre_update(&ctx);
2839
2840 if tile.is_visible {
2853 world_culling_rect = world_culling_rect.union(&tile.world_tile_rect);
2854 }
2855 }
2856
2857 ctx.background_color = None;
2859 }
2860
2861 match frame_context.config.compositor_kind {
2863 CompositorKind::Draw { .. } => {
2864 for sub_slice in &mut self.sub_slices {
2865 for tile in sub_slice.tiles.values_mut() {
2866 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2867 if let Some(id) = id.take() {
2868 frame_state.resource_cache.destroy_compositor_tile(id);
2869 }
2870 tile.surface = None;
2871 tile.invalidate(None, InvalidationReason::CompositorKindChanged);
2873 }
2874 }
2875
2876 if let Some(native_surface) = sub_slice.native_surface.take() {
2877 frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
2878 frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
2879 }
2880 }
2881
2882 for (_, external_surface) in self.external_native_surface_cache.drain() {
2883 frame_state.resource_cache.destroy_compositor_surface(external_surface.native_surface_id)
2884 }
2885 }
2886 CompositorKind::Native { .. } => {
2887 for sub_slice in &mut self.sub_slices {
2890 for tile in sub_slice.tiles.values_mut() {
2891 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::TextureCache { .. }, .. }) = tile.surface {
2892 tile.surface = None;
2893 tile.invalidate(None, InvalidationReason::CompositorKindChanged);
2895 }
2896 }
2897 }
2898 }
2899 }
2900
2901 world_culling_rect
2902 }
2903
2904 fn can_promote_to_surface(
2905 &mut self,
2906 flags: PrimitiveFlags,
2907 prim_clip_chain: &ClipChainInstance,
2908 prim_spatial_node_index: SpatialNodeIndex,
2909 is_root_tile_cache: bool,
2910 sub_slice_index: usize,
2911 frame_context: &FrameVisibilityContext,
2912 ) -> SurfacePromotionResult {
2913 if !flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
2915 return SurfacePromotionResult::Failed;
2916 }
2917
2918 if sub_slice_index == MAX_COMPOSITOR_SURFACES {
2920 return SurfacePromotionResult::Failed;
2921 }
2922
2923 if prim_clip_chain.needs_mask {
2928 return SurfacePromotionResult::Failed;
2929 }
2930
2931 if !is_root_tile_cache {
2934 return SurfacePromotionResult::Failed;
2935 }
2936
2937 let mapper : SpaceMapper<PicturePixel, WorldPixel> = SpaceMapper::new_with_target(
2938 ROOT_SPATIAL_NODE_INDEX,
2939 prim_spatial_node_index,
2940 frame_context.global_screen_world_rect,
2941 &frame_context.spatial_tree);
2942 let transform = mapper.get_transform();
2943 if !transform.is_2d_scale_translation() {
2944 return SurfacePromotionResult::Failed;
2945 }
2946 if transform.m11 < 0.0 {
2947 return SurfacePromotionResult::Failed;
2948 }
2949
2950 if self.slice_flags.contains(SliceFlags::IS_BLEND_CONTAINER) {
2951 return SurfacePromotionResult::Failed;
2952 }
2953
2954 SurfacePromotionResult::Success
2955 }
2956
2957 fn setup_compositor_surfaces_yuv(
2958 &mut self,
2959 sub_slice_index: usize,
2960 prim_info: &mut PrimitiveDependencyInfo,
2961 flags: PrimitiveFlags,
2962 local_prim_rect: LayoutRect,
2963 prim_spatial_node_index: SpatialNodeIndex,
2964 pic_clip_rect: PictureRect,
2965 frame_context: &FrameVisibilityContext,
2966 image_dependencies: &[ImageDependency;3],
2967 api_keys: &[ImageKey; 3],
2968 resource_cache: &mut ResourceCache,
2969 composite_state: &mut CompositeState,
2970 gpu_cache: &mut GpuCache,
2971 image_rendering: ImageRendering,
2972 color_depth: ColorDepth,
2973 color_space: YuvRangedColorSpace,
2974 format: YuvFormat,
2975 ) -> bool {
2976 for &key in api_keys {
2977 if key != ImageKey::DUMMY {
2978 resource_cache.request_image(ImageRequest {
2980 key,
2981 rendering: image_rendering,
2982 tile: None,
2983 },
2984 gpu_cache,
2985 );
2986 }
2987 }
2988
2989 self.setup_compositor_surfaces_impl(
2990 sub_slice_index,
2991 prim_info,
2992 flags,
2993 local_prim_rect,
2994 prim_spatial_node_index,
2995 pic_clip_rect,
2996 frame_context,
2997 ExternalSurfaceDependency::Yuv {
2998 image_dependencies: *image_dependencies,
2999 color_space,
3000 format,
3001 channel_bit_depth: color_depth.bit_depth(),
3002 },
3003 api_keys,
3004 resource_cache,
3005 composite_state,
3006 image_rendering,
3007 true,
3008 )
3009 }
3010
3011 fn setup_compositor_surfaces_rgb(
3012 &mut self,
3013 sub_slice_index: usize,
3014 prim_info: &mut PrimitiveDependencyInfo,
3015 flags: PrimitiveFlags,
3016 local_prim_rect: LayoutRect,
3017 prim_spatial_node_index: SpatialNodeIndex,
3018 pic_clip_rect: PictureRect,
3019 frame_context: &FrameVisibilityContext,
3020 image_dependency: ImageDependency,
3021 api_key: ImageKey,
3022 resource_cache: &mut ResourceCache,
3023 composite_state: &mut CompositeState,
3024 gpu_cache: &mut GpuCache,
3025 image_rendering: ImageRendering,
3026 ) -> bool {
3027 let mut api_keys = [ImageKey::DUMMY; 3];
3028 api_keys[0] = api_key;
3029
3030 resource_cache.request_image(ImageRequest {
3037 key: api_key,
3038 rendering: image_rendering,
3039 tile: None,
3040 },
3041 gpu_cache,
3042 );
3043
3044 let is_opaque = resource_cache.get_image_properties(api_key)
3045 .map_or(false, |properties| properties.descriptor.is_opaque());
3046
3047 self.setup_compositor_surfaces_impl(
3048 sub_slice_index,
3049 prim_info,
3050 flags,
3051 local_prim_rect,
3052 prim_spatial_node_index,
3053 pic_clip_rect,
3054 frame_context,
3055 ExternalSurfaceDependency::Rgb {
3056 image_dependency,
3057 },
3058 &api_keys,
3059 resource_cache,
3060 composite_state,
3061 image_rendering,
3062 is_opaque,
3063 )
3064 }
3065
3066 fn setup_compositor_surfaces_impl(
3069 &mut self,
3070 sub_slice_index: usize,
3071 prim_info: &mut PrimitiveDependencyInfo,
3072 flags: PrimitiveFlags,
3073 local_prim_rect: LayoutRect,
3074 prim_spatial_node_index: SpatialNodeIndex,
3075 pic_clip_rect: PictureRect,
3076 frame_context: &FrameVisibilityContext,
3077 dependency: ExternalSurfaceDependency,
3078 api_keys: &[ImageKey; 3],
3079 resource_cache: &mut ResourceCache,
3080 composite_state: &mut CompositeState,
3081 image_rendering: ImageRendering,
3082 is_opaque: bool,
3083 ) -> bool {
3084 let map_local_to_surface = SpaceMapper::new_with_target(
3085 self.spatial_node_index,
3086 prim_spatial_node_index,
3087 self.local_rect,
3088 frame_context.spatial_tree,
3089 );
3090
3091 let prim_rect = match map_local_to_surface.map(&local_prim_rect) {
3093 Some(rect) => rect,
3094 None => return true,
3095 };
3096
3097 if prim_rect.is_empty() {
3099 return true;
3100 }
3101
3102 let pic_to_world_mapper = SpaceMapper::new_with_target(
3103 ROOT_SPATIAL_NODE_INDEX,
3104 self.spatial_node_index,
3105 frame_context.global_screen_world_rect,
3106 frame_context.spatial_tree,
3107 );
3108
3109 let world_clip_rect = pic_to_world_mapper
3110 .map(&prim_info.prim_clip_box)
3111 .expect("bug: unable to map clip to world space");
3112
3113 let is_visible = world_clip_rect.intersects(&frame_context.global_screen_world_rect);
3114 if !is_visible {
3115 return true;
3116 }
3117
3118 let prim_offset = ScaleOffset::from_offset(local_prim_rect.min.to_vector().cast_unit());
3119
3120 let local_prim_to_device = get_relative_scale_offset(
3121 prim_spatial_node_index,
3122 ROOT_SPATIAL_NODE_INDEX,
3123 frame_context.spatial_tree,
3124 );
3125
3126 let normalized_prim_to_device = prim_offset.accumulate(&local_prim_to_device);
3127
3128 let local_to_surface = ScaleOffset::identity();
3129 let surface_to_device = normalized_prim_to_device;
3130
3131 let compositor_transform_index = composite_state.register_transform(
3132 local_to_surface,
3133 surface_to_device,
3134 );
3135
3136 let surface_size = composite_state.get_surface_rect(
3137 &local_prim_rect,
3138 &local_prim_rect,
3139 compositor_transform_index,
3140 ).size();
3141
3142 let clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round();
3143
3144 if surface_size.width >= MAX_COMPOSITOR_SURFACES_SIZE ||
3145 surface_size.height >= MAX_COMPOSITOR_SURFACES_SIZE {
3146 return false;
3147 }
3148
3149 let external_image_id = if flags.contains(PrimitiveFlags::SUPPORTS_EXTERNAL_COMPOSITOR_SURFACE) {
3153 resource_cache.get_image_properties(api_keys[0])
3154 .and_then(|properties| properties.external_image)
3155 .and_then(|image| Some(image.id))
3156 } else {
3157 None
3158 };
3159
3160 let (native_surface_id, update_params) = match composite_state.compositor_kind {
3165 CompositorKind::Draw { .. } => {
3166 (None, None)
3167 }
3168 CompositorKind::Native { .. } => {
3169 let native_surface_size = surface_size.to_i32();
3170
3171 let key = ExternalNativeSurfaceKey {
3172 image_keys: *api_keys,
3173 size: native_surface_size,
3174 is_external_surface: external_image_id.is_some(),
3175 };
3176
3177 let native_surface = self.external_native_surface_cache
3178 .entry(key)
3179 .or_insert_with(|| {
3180 let native_surface_id = match external_image_id {
3182 Some(_external_image) => {
3183 resource_cache.create_compositor_external_surface(is_opaque)
3186 }
3187 None => {
3188 let native_surface_id =
3191 resource_cache.create_compositor_surface(
3192 DeviceIntPoint::zero(),
3193 native_surface_size,
3194 is_opaque,
3195 );
3196
3197 let tile_id = NativeTileId {
3198 surface_id: native_surface_id,
3199 x: 0,
3200 y: 0,
3201 };
3202 resource_cache.create_compositor_tile(tile_id);
3203
3204 native_surface_id
3205 }
3206 };
3207
3208 ExternalNativeSurface {
3209 used_this_frame: true,
3210 native_surface_id,
3211 image_dependencies: [ImageDependency::INVALID; 3],
3212 }
3213 });
3214
3215 native_surface.used_this_frame = true;
3218
3219 let update_params = match external_image_id {
3220 Some(external_image) => {
3221 resource_cache.attach_compositor_external_image(
3225 native_surface.native_surface_id,
3226 external_image,
3227 );
3228 None
3229 }
3230 None => {
3231 match dependency {
3234 ExternalSurfaceDependency::Yuv{ image_dependencies, .. } => {
3235 if image_dependencies == native_surface.image_dependencies {
3236 None
3237 } else {
3238 Some(native_surface_size)
3239 }
3240 },
3241 ExternalSurfaceDependency::Rgb{ image_dependency, .. } => {
3242 if image_dependency == native_surface.image_dependencies[0] {
3243 None
3244 } else {
3245 Some(native_surface_size)
3246 }
3247 },
3248 }
3249 }
3250 };
3251
3252 (Some(native_surface.native_surface_id), update_params)
3253 }
3254 };
3255
3256 assert!(sub_slice_index < self.sub_slices.len() - 1);
3259 let sub_slice = &mut self.sub_slices[sub_slice_index];
3260
3261 sub_slice.compositor_surfaces.push(CompositorSurface {
3263 prohibited_rect: pic_clip_rect,
3264 is_opaque,
3265 descriptor: ExternalSurfaceDescriptor {
3266 local_surface_size: local_prim_rect.size(),
3267 local_rect: prim_rect,
3268 local_clip_rect: prim_info.prim_clip_box,
3269 dependency,
3270 image_rendering,
3271 clip_rect,
3272 transform_index: compositor_transform_index,
3273 z_id: ZBufferId::invalid(),
3274 native_surface_id,
3275 update_params,
3276 },
3277 });
3278
3279 true
3280 }
3281
3282 pub fn push_surface(
3288 &mut self,
3289 estimated_local_rect: LayoutRect,
3290 surface_spatial_node_index: SpatialNodeIndex,
3291 spatial_tree: &SpatialTree,
3292 ) {
3293 if self.current_surface_traversal_depth == 0 && self.sub_slices.len() > 1 {
3295 let map_local_to_surface = SpaceMapper::new_with_target(
3296 self.spatial_node_index,
3297 surface_spatial_node_index,
3298 self.local_rect,
3299 spatial_tree,
3300 );
3301
3302 if let Some(pic_rect) = map_local_to_surface.map(&estimated_local_rect) {
3303 for sub_slice in &mut self.sub_slices {
3306 let mut intersects_prohibited_region = false;
3307
3308 for surface in &mut sub_slice.compositor_surfaces {
3309 if pic_rect.intersects(&surface.prohibited_rect) {
3310 surface.prohibited_rect = surface.prohibited_rect.union(&pic_rect);
3311
3312 intersects_prohibited_region = true;
3313 }
3314 }
3315
3316 if !intersects_prohibited_region {
3317 break;
3318 }
3319 }
3320 }
3321 }
3322
3323 self.current_surface_traversal_depth += 1;
3324 }
3325
3326 pub fn pop_surface(&mut self) {
3328 self.current_surface_traversal_depth -= 1;
3329 }
3330
3331 pub fn update_prim_dependencies(
3333 &mut self,
3334 prim_instance: &mut PrimitiveInstance,
3335 prim_spatial_node_index: SpatialNodeIndex,
3336 local_prim_rect: LayoutRect,
3337 frame_context: &FrameVisibilityContext,
3338 data_stores: &DataStores,
3339 clip_store: &ClipStore,
3340 pictures: &[PicturePrimitive],
3341 resource_cache: &mut ResourceCache,
3342 color_bindings: &ColorBindingStorage,
3343 surface_stack: &[SurfaceIndex],
3344 composite_state: &mut CompositeState,
3345 gpu_cache: &mut GpuCache,
3346 is_root_tile_cache: bool,
3347 ) {
3348 profile_scope!("update_prim_dependencies");
3350 let prim_surface_index = *surface_stack.last().unwrap();
3351 let prim_clip_chain = &prim_instance.vis.clip_chain;
3352
3353 let on_picture_surface = prim_surface_index == self.surface_index;
3357 let pic_clip_rect = if on_picture_surface {
3358 prim_clip_chain.pic_clip_rect
3359 } else {
3360 let mut current_pic_clip_rect = prim_clip_chain.pic_clip_rect;
3368 let mut current_spatial_node_index = frame_context
3369 .surfaces[prim_surface_index.0]
3370 .surface_spatial_node_index;
3371
3372 for surface_index in surface_stack.iter().rev() {
3373 let surface = &frame_context.surfaces[surface_index.0];
3374
3375 let map_local_to_surface = SpaceMapper::new_with_target(
3376 surface.surface_spatial_node_index,
3377 current_spatial_node_index,
3378 surface.rect,
3379 frame_context.spatial_tree,
3380 );
3381
3382 current_pic_clip_rect = match map_local_to_surface.map(¤t_pic_clip_rect) {
3386 Some(rect) => {
3387 rect.inflate(surface.inflation_factor, surface.inflation_factor)
3388 }
3389 None => {
3390 return;
3391 }
3392 };
3393
3394 current_spatial_node_index = surface.surface_spatial_node_index;
3395 }
3396
3397 current_pic_clip_rect
3398 };
3399
3400 let (p0, p1) = self.get_tile_coords_for_rect(&pic_clip_rect);
3402
3403 if p0.x == p1.x || p0.y == p1.y {
3406 return;
3407 }
3408
3409 let mut prim_info = PrimitiveDependencyInfo::new(
3411 prim_instance.uid(),
3412 pic_clip_rect,
3413 );
3414
3415 let mut sub_slice_index = self.sub_slices.len() - 1;
3416
3417 if sub_slice_index > 0 {
3419 for (i, sub_slice) in self.sub_slices.iter_mut().enumerate() {
3422 let mut intersects_prohibited_region = false;
3423
3424 for surface in &mut sub_slice.compositor_surfaces {
3425 if pic_clip_rect.intersects(&surface.prohibited_rect) {
3426 surface.prohibited_rect = surface.prohibited_rect.union(&pic_clip_rect);
3427
3428 intersects_prohibited_region = true;
3429 }
3430 }
3431
3432 if !intersects_prohibited_region {
3433 sub_slice_index = i;
3434 break;
3435 }
3436 }
3437 }
3438
3439 if prim_spatial_node_index != self.spatial_node_index {
3441 prim_info.spatial_nodes.push(prim_spatial_node_index);
3442 }
3443
3444 let clip_instances = &clip_store
3446 .clip_node_instances[prim_clip_chain.clips_range.to_range()];
3447 for clip_instance in clip_instances {
3448 prim_info.clips.push(clip_instance.handle.uid());
3449
3450 if clip_instance.spatial_node_index != self.spatial_node_index
3453 && !prim_info.spatial_nodes.contains(&clip_instance.spatial_node_index) {
3454 prim_info.spatial_nodes.push(clip_instance.spatial_node_index);
3455 }
3456 }
3457
3458 let mut backdrop_candidate = None;
3461
3462 match prim_instance.kind {
3474 PrimitiveInstanceKind::Picture { pic_index,.. } => {
3475 let pic = &pictures[pic_index.0];
3477 if let Some(PictureCompositeMode::Filter(Filter::Opacity(binding, _))) = pic.requested_composite_mode {
3478 prim_info.opacity_bindings.push(binding.into());
3479 }
3480 }
3481 PrimitiveInstanceKind::Rectangle { data_handle, color_binding_index, .. } => {
3482 let color = match data_stores.prim[data_handle].kind {
3486 PrimitiveTemplateKind::Rectangle { color, .. } => {
3487 frame_context.scene_properties.resolve_color(&color)
3488 }
3489 _ => unreachable!(),
3490 };
3491 if color.a >= 1.0 {
3492 backdrop_candidate = Some(BackdropInfo {
3493 opaque_rect: pic_clip_rect,
3494 kind: Some(BackdropKind::Color { color }),
3495 });
3496 }
3497
3498 if color_binding_index != ColorBindingIndex::INVALID {
3499 prim_info.color_binding = Some(color_bindings[color_binding_index].into());
3500 }
3501 }
3502 PrimitiveInstanceKind::Image { data_handle, ref mut is_compositor_surface, .. } => {
3503 let image_key = &data_stores.image[data_handle];
3504 let image_data = &image_key.kind;
3505
3506 let mut promote_to_surface = false;
3507 match self.can_promote_to_surface(image_key.common.flags,
3508 prim_clip_chain,
3509 prim_spatial_node_index,
3510 is_root_tile_cache,
3511 sub_slice_index,
3512 frame_context) {
3513 SurfacePromotionResult::Failed => {
3514 }
3515 SurfacePromotionResult::Success => {
3516 promote_to_surface = true;
3517 }
3518 }
3519
3520 if image_data.alpha_type == AlphaType::Alpha {
3523 promote_to_surface = false;
3524 }
3525
3526 if let Some(image_properties) = resource_cache.get_image_properties(image_data.key) {
3527 if image_properties.descriptor.is_opaque() &&
3533 image_properties.tiling.is_none() &&
3534 image_data.tile_spacing == LayoutSize::zero() &&
3535 image_data.color.a >= 1.0 {
3536 backdrop_candidate = Some(BackdropInfo {
3537 opaque_rect: pic_clip_rect,
3538 kind: None,
3539 });
3540 }
3541 }
3542
3543 if promote_to_surface {
3544 promote_to_surface = self.setup_compositor_surfaces_rgb(
3545 sub_slice_index,
3546 &mut prim_info,
3547 image_key.common.flags,
3548 local_prim_rect,
3549 prim_spatial_node_index,
3550 pic_clip_rect,
3551 frame_context,
3552 ImageDependency {
3553 key: image_data.key,
3554 generation: resource_cache.get_image_generation(image_data.key),
3555 },
3556 image_data.key,
3557 resource_cache,
3558 composite_state,
3559 gpu_cache,
3560 image_data.image_rendering,
3561 );
3562 }
3563
3564 *is_compositor_surface = promote_to_surface;
3565
3566 if promote_to_surface {
3567 prim_instance.vis.state = VisibilityState::Culled;
3568 return;
3569 } else {
3570 prim_info.images.push(ImageDependency {
3571 key: image_data.key,
3572 generation: resource_cache.get_image_generation(image_data.key),
3573 });
3574 }
3575 }
3576 PrimitiveInstanceKind::YuvImage { data_handle, ref mut is_compositor_surface, .. } => {
3577 let prim_data = &data_stores.yuv_image[data_handle];
3578 let mut promote_to_surface = match self.can_promote_to_surface(
3579 prim_data.common.flags,
3580 prim_clip_chain,
3581 prim_spatial_node_index,
3582 is_root_tile_cache,
3583 sub_slice_index,
3584 frame_context) {
3585 SurfacePromotionResult::Failed => false,
3586 SurfacePromotionResult::Success => true,
3587 };
3588
3589 if promote_to_surface {
3598 let mut image_dependencies = [ImageDependency::INVALID; 3];
3601 for (key, dep) in prim_data.kind.yuv_key.iter().cloned().zip(image_dependencies.iter_mut()) {
3602 *dep = ImageDependency {
3603 key,
3604 generation: resource_cache.get_image_generation(key),
3605 }
3606 }
3607
3608 promote_to_surface = self.setup_compositor_surfaces_yuv(
3609 sub_slice_index,
3610 &mut prim_info,
3611 prim_data.common.flags,
3612 local_prim_rect,
3613 prim_spatial_node_index,
3614 pic_clip_rect,
3615 frame_context,
3616 &image_dependencies,
3617 &prim_data.kind.yuv_key,
3618 resource_cache,
3619 composite_state,
3620 gpu_cache,
3621 prim_data.kind.image_rendering,
3622 prim_data.kind.color_depth,
3623 prim_data.kind.color_space.with_range(prim_data.kind.color_range),
3624 prim_data.kind.format,
3625 );
3626 }
3627
3628 *is_compositor_surface = promote_to_surface;
3632
3633 if promote_to_surface {
3634 prim_instance.vis.state = VisibilityState::Culled;
3635 return;
3636 } else {
3637 prim_info.images.extend(
3638 prim_data.kind.yuv_key.iter().map(|key| {
3639 ImageDependency {
3640 key: *key,
3641 generation: resource_cache.get_image_generation(*key),
3642 }
3643 })
3644 );
3645 }
3646 }
3647 PrimitiveInstanceKind::ImageBorder { data_handle, .. } => {
3648 let border_data = &data_stores.image_border[data_handle].kind;
3649 prim_info.images.push(ImageDependency {
3650 key: border_data.request.key,
3651 generation: resource_cache.get_image_generation(border_data.request.key),
3652 });
3653 }
3654 PrimitiveInstanceKind::Clear { .. } => {
3655 backdrop_candidate = Some(BackdropInfo {
3656 opaque_rect: pic_clip_rect,
3657 kind: Some(BackdropKind::Clear),
3658 });
3659 }
3660 PrimitiveInstanceKind::LinearGradient { data_handle, .. }
3661 | PrimitiveInstanceKind::CachedLinearGradient { data_handle, .. } => {
3662 let gradient_data = &data_stores.linear_grad[data_handle];
3663 if gradient_data.stops_opacity.is_opaque
3664 && gradient_data.tile_spacing == LayoutSize::zero()
3665 {
3666 backdrop_candidate = Some(BackdropInfo {
3667 opaque_rect: pic_clip_rect,
3668 kind: None,
3669 });
3670 }
3671 }
3672 PrimitiveInstanceKind::ConicGradient { data_handle, .. } => {
3673 let gradient_data = &data_stores.conic_grad[data_handle];
3674 if gradient_data.stops_opacity.is_opaque
3675 && gradient_data.tile_spacing == LayoutSize::zero()
3676 {
3677 backdrop_candidate = Some(BackdropInfo {
3678 opaque_rect: pic_clip_rect,
3679 kind: None,
3680 });
3681 }
3682 }
3683 PrimitiveInstanceKind::RadialGradient { data_handle, .. } => {
3684 let gradient_data = &data_stores.radial_grad[data_handle];
3685 if gradient_data.stops_opacity.is_opaque
3686 && gradient_data.tile_spacing == LayoutSize::zero()
3687 {
3688 backdrop_candidate = Some(BackdropInfo {
3689 opaque_rect: pic_clip_rect,
3690 kind: None,
3691 });
3692 }
3693 }
3694 PrimitiveInstanceKind::LineDecoration { .. } |
3695 PrimitiveInstanceKind::NormalBorder { .. } |
3696 PrimitiveInstanceKind::TextRun { .. } |
3697 PrimitiveInstanceKind::Backdrop { .. } => {
3698 }
3700 };
3701
3702 let mut vis_flags = PrimitiveVisibilityFlags::empty();
3705
3706 let sub_slice = &mut self.sub_slices[sub_slice_index];
3707
3708 if let Some(backdrop_candidate) = backdrop_candidate {
3709 let is_suitable_backdrop = match backdrop_candidate.kind {
3710 Some(BackdropKind::Clear) => {
3711 true
3716 }
3717 Some(BackdropKind::Color { .. }) | None => {
3718 let same_coord_system = {
3727 let prim_spatial_node = &frame_context.spatial_tree
3728 .spatial_nodes[prim_spatial_node_index.0 as usize];
3729 let surface_spatial_node = &frame_context.spatial_tree
3730 .spatial_nodes[self.spatial_node_index.0 as usize];
3731
3732 prim_spatial_node.coordinate_system_id == surface_spatial_node.coordinate_system_id
3733 };
3734
3735 same_coord_system && on_picture_surface
3736 }
3737 };
3738
3739 if sub_slice_index == 0 &&
3740 is_suitable_backdrop &&
3741 sub_slice.compositor_surfaces.is_empty() &&
3742 !prim_clip_chain.needs_mask {
3743
3744 if backdrop_candidate.opaque_rect.contains_box(&self.backdrop.opaque_rect) {
3745 self.backdrop.opaque_rect = backdrop_candidate.opaque_rect;
3746 }
3747
3748 if let Some(kind) = backdrop_candidate.kind {
3749 if backdrop_candidate.opaque_rect.contains_box(&self.local_rect) {
3750 if let BackdropKind::Color { .. } = kind {
3754 vis_flags |= PrimitiveVisibilityFlags::IS_BACKDROP;
3755 }
3756
3757 self.backdrop.kind = Some(kind);
3758 }
3759 }
3760 }
3761 }
3762
3763 for spatial_node_index in &prim_info.spatial_nodes {
3765 self.spatial_node_comparer.register_used_transform(
3766 *spatial_node_index,
3767 self.frame_id,
3768 frame_context.spatial_tree,
3769 );
3770 }
3771
3772 prim_info.clips.truncate(MAX_PRIM_SUB_DEPS);
3775 prim_info.opacity_bindings.truncate(MAX_PRIM_SUB_DEPS);
3776 prim_info.spatial_nodes.truncate(MAX_PRIM_SUB_DEPS);
3777 prim_info.images.truncate(MAX_PRIM_SUB_DEPS);
3778
3779 for y in p0.y .. p1.y {
3782 for x in p0.x .. p1.x {
3783 let key = TileOffset::new(x, y);
3785 let tile = sub_slice.tiles.get_mut(&key).expect("bug: no tile");
3786
3787 tile.add_prim_dependency(&prim_info);
3788 }
3789 }
3790
3791 prim_instance.vis.state = VisibilityState::Coarse {
3792 filter: BatchFilter {
3793 rect_in_pic_space: pic_clip_rect,
3794 sub_slice_index: SubSliceIndex::new(sub_slice_index),
3795 },
3796 vis_flags,
3797 };
3798 }
3799
3800 fn print(&self) {
3802 let mut pt = PrintTree::new("Picture Cache");
3808
3809 pt.new_level(format!("Slice {:?}", self.slice));
3810
3811 pt.add_item(format!("background_color: {:?}", self.background_color));
3812
3813 for (sub_slice_index, sub_slice) in self.sub_slices.iter().enumerate() {
3814 pt.new_level(format!("SubSlice {:?}", sub_slice_index));
3815
3816 for y in self.tile_bounds_p0.y .. self.tile_bounds_p1.y {
3817 for x in self.tile_bounds_p0.x .. self.tile_bounds_p1.x {
3818 let key = TileOffset::new(x, y);
3819 let tile = &sub_slice.tiles[&key];
3820 tile.print(&mut pt);
3821 }
3822 }
3823
3824 pt.end_level();
3825 }
3826
3827 pt.end_level();
3828 }
3829
3830 fn calculate_subpixel_mode(&self) -> SubpixelMode {
3831 let has_opaque_bg_color = self.background_color.map_or(false, |c| c.a >= 1.0);
3832
3833 if has_opaque_bg_color {
3835 return SubpixelMode::Allow;
3836 }
3837
3838 if self.backdrop.opaque_rect.is_empty() {
3840 return SubpixelMode::Deny;
3841 }
3842
3843 if self.backdrop.opaque_rect.contains_box(&self.local_rect) {
3847 return SubpixelMode::Allow;
3848 }
3849
3850 SubpixelMode::Conditional {
3858 allowed_rect: self.backdrop.opaque_rect,
3859 }
3860 }
3861
3862 pub fn post_update(
3866 &mut self,
3867 frame_context: &FrameVisibilityContext,
3868 frame_state: &mut FrameVisibilityState,
3869 ) {
3870 assert!(self.current_surface_traversal_depth == 0);
3871
3872 self.dirty_region.reset(self.spatial_node_index);
3873 self.subpixel_mode = self.calculate_subpixel_mode();
3874
3875 self.transform_index = frame_state.composite_state.register_transform(
3876 self.local_to_surface,
3877 self.surface_to_device,
3880 );
3881
3882 let map_pic_to_world = SpaceMapper::new_with_target(
3883 ROOT_SPATIAL_NODE_INDEX,
3884 self.spatial_node_index,
3885 frame_context.global_screen_world_rect,
3886 frame_context.spatial_tree,
3887 );
3888
3889 self.external_native_surface_cache.retain(|_, surface| {
3892 if !surface.used_this_frame {
3893 frame_state.composite_state.dirty_rects_are_valid = false;
3896
3897 frame_state.resource_cache.destroy_compositor_surface(surface.native_surface_id);
3898 }
3899
3900 surface.used_this_frame
3901 });
3902
3903 let pic_to_world_mapper = SpaceMapper::new_with_target(
3904 ROOT_SPATIAL_NODE_INDEX,
3905 self.spatial_node_index,
3906 frame_context.global_screen_world_rect,
3907 frame_context.spatial_tree,
3908 );
3909
3910 let mut ctx = TilePostUpdateContext {
3911 pic_to_world_mapper,
3912 global_device_pixel_scale: frame_context.global_device_pixel_scale,
3913 local_clip_rect: self.local_clip_rect,
3914 backdrop: None,
3915 opacity_bindings: &self.opacity_bindings,
3916 color_bindings: &self.color_bindings,
3917 current_tile_size: self.current_tile_size,
3918 local_rect: self.local_rect,
3919 z_id: ZBufferId::invalid(),
3920 invalidate_all: self.invalidate_all_tiles,
3921 };
3922
3923 let mut state = TilePostUpdateState {
3924 resource_cache: frame_state.resource_cache,
3925 composite_state: frame_state.composite_state,
3926 compare_cache: &mut self.compare_cache,
3927 spatial_node_comparer: &mut self.spatial_node_comparer,
3928 };
3929
3930 for (i, sub_slice) in self.sub_slices.iter_mut().enumerate().rev() {
3933 if i == 0 {
3935 ctx.backdrop = Some(self.backdrop);
3936 }
3937
3938 for compositor_surface in sub_slice.compositor_surfaces.iter_mut().rev() {
3939 compositor_surface.descriptor.z_id = state.composite_state.z_generator.next();
3940 }
3941
3942 ctx.z_id = state.composite_state.z_generator.next();
3943
3944 for tile in sub_slice.tiles.values_mut() {
3945 tile.post_update(&ctx, &mut state, frame_context);
3946 }
3947 }
3948
3949 for sub_slice in &self.sub_slices {
3955 for compositor_surface in &sub_slice.compositor_surfaces {
3956 if compositor_surface.is_opaque {
3957 let local_surface_rect = compositor_surface
3958 .descriptor
3959 .local_rect
3960 .intersection(&compositor_surface.descriptor.local_clip_rect)
3961 .and_then(|r| {
3962 r.intersection(&self.local_clip_rect)
3963 });
3964
3965 if let Some(local_surface_rect) = local_surface_rect {
3966 let world_surface_rect = map_pic_to_world
3967 .map(&local_surface_rect)
3968 .expect("bug: unable to map external surface to world space");
3969
3970 frame_state.composite_state.register_occluder(
3971 compositor_surface.descriptor.z_id,
3972 world_surface_rect,
3973 );
3974 }
3975 }
3976 }
3977 }
3978
3979 if !self.backdrop.opaque_rect.is_empty() {
3982 let z_id_backdrop = frame_state.composite_state.z_generator.next();
3983
3984 let backdrop_rect = self.backdrop.opaque_rect
3985 .intersection(&self.local_rect)
3986 .and_then(|r| {
3987 r.intersection(&self.local_clip_rect)
3988 });
3989
3990 if let Some(backdrop_rect) = backdrop_rect {
3991 let world_backdrop_rect = map_pic_to_world
3992 .map(&backdrop_rect)
3993 .expect("bug: unable to map backdrop to world space");
3994
3995 frame_state.composite_state.register_occluder(
3998 z_id_backdrop,
3999 world_backdrop_rect,
4000 );
4001 }
4002 }
4003 }
4004}
4005
4006pub struct PictureScratchBuffer {
4007 surface_stack: Vec<SurfaceIndex>,
4008 clip_chain_ids: Vec<ClipChainId>,
4009}
4010
4011impl Default for PictureScratchBuffer {
4012 fn default() -> Self {
4013 PictureScratchBuffer {
4014 surface_stack: Vec::new(),
4015 clip_chain_ids: Vec::new(),
4016 }
4017 }
4018}
4019
4020impl PictureScratchBuffer {
4021 pub fn begin_frame(&mut self) {
4022 self.surface_stack.clear();
4023 self.clip_chain_ids.clear();
4024 }
4025
4026 pub fn recycle(&mut self, recycler: &mut Recycler) {
4027 recycler.recycle_vec(&mut self.surface_stack);
4028 }
4029 }
4030
4031pub struct PictureUpdateState<'a> {
4034 surfaces: &'a mut Vec<SurfaceInfo>,
4035 surface_stack: Vec<SurfaceIndex>,
4036}
4037
4038impl<'a> PictureUpdateState<'a> {
4039 pub fn update_all(
4040 buffers: &mut PictureScratchBuffer,
4041 surfaces: &'a mut Vec<SurfaceInfo>,
4042 pic_index: PictureIndex,
4043 picture_primitives: &mut [PicturePrimitive],
4044 frame_context: &FrameBuildingContext,
4045 gpu_cache: &mut GpuCache,
4046 clip_store: &ClipStore,
4047 data_stores: &mut DataStores,
4048 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
4049 ) {
4050 profile_scope!("UpdatePictures");
4051 profile_marker!("UpdatePictures");
4052
4053 let mut state = PictureUpdateState {
4054 surfaces,
4055 surface_stack: buffers.surface_stack.take().cleared(),
4056 };
4057
4058 state.surface_stack.push(SurfaceIndex(0));
4059
4060 state.update(
4061 pic_index,
4062 picture_primitives,
4063 frame_context,
4064 gpu_cache,
4065 clip_store,
4066 data_stores,
4067 tile_caches,
4068 );
4069
4070 buffers.surface_stack = state.surface_stack.take();
4071 }
4072
4073 fn current_surface(&self) -> &SurfaceInfo {
4075 &self.surfaces[self.surface_stack.last().unwrap().0]
4076 }
4077
4078 fn current_surface_mut(&mut self) -> &mut SurfaceInfo {
4080 &mut self.surfaces[self.surface_stack.last().unwrap().0]
4081 }
4082
4083 fn push_surface(
4085 &mut self,
4086 surface: SurfaceInfo,
4087 ) -> SurfaceIndex {
4088 let surface_index = SurfaceIndex(self.surfaces.len());
4089 self.surfaces.push(surface);
4090 self.surface_stack.push(surface_index);
4091 surface_index
4092 }
4093
4094 fn pop_surface(&mut self) -> SurfaceIndex{
4096 self.surface_stack.pop().unwrap()
4097 }
4098
4099 fn update(
4103 &mut self,
4104 pic_index: PictureIndex,
4105 picture_primitives: &mut [PicturePrimitive],
4106 frame_context: &FrameBuildingContext,
4107 gpu_cache: &mut GpuCache,
4108 clip_store: &ClipStore,
4109 data_stores: &mut DataStores,
4110 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
4111 ) {
4112 if let Some(prim_list) = picture_primitives[pic_index.0].pre_update(
4113 self,
4114 frame_context,
4115 tile_caches,
4116 ) {
4117 for child_pic_index in &prim_list.child_pictures {
4118 self.update(
4119 *child_pic_index,
4120 picture_primitives,
4121 frame_context,
4122 gpu_cache,
4123 clip_store,
4124 data_stores,
4125 tile_caches,
4126 );
4127 }
4128
4129 picture_primitives[pic_index.0].post_update(
4130 prim_list,
4131 self,
4132 frame_context,
4133 data_stores,
4134 );
4135 }
4136 }
4137}
4138
4139#[derive(Debug, Copy, Clone, PartialEq)]
4140#[cfg_attr(feature = "capture", derive(Serialize))]
4141pub struct SurfaceIndex(pub usize);
4142
4143pub const ROOT_SURFACE_INDEX: SurfaceIndex = SurfaceIndex(0);
4144
4145#[derive(Debug)]
4147pub enum SurfaceRenderTasks {
4148 Simple(RenderTaskId),
4150 Chained { root_task_id: RenderTaskId, port_task_id: RenderTaskId },
4155 Tiled(Vec<RenderTaskId>),
4158}
4159
4160#[derive(Debug)]
4167pub struct SurfaceInfo {
4168 pub rect: PictureRect,
4171 pub opaque_rect: PictureRect,
4173 pub map_local_to_surface: SpaceMapper<LayoutPixel, PicturePixel>,
4176 pub raster_spatial_node_index: SpatialNodeIndex,
4179 pub surface_spatial_node_index: SpatialNodeIndex,
4180 pub render_tasks: Option<SurfaceRenderTasks>,
4182 pub inflation_factor: f32,
4184 pub device_pixel_scale: DevicePixelScale,
4186 pub scale_factors: (f32, f32),
4188 pub raster_rect: Option<DeviceRect>,
4190}
4191
4192impl SurfaceInfo {
4193 pub fn new(
4194 surface_spatial_node_index: SpatialNodeIndex,
4195 raster_spatial_node_index: SpatialNodeIndex,
4196 inflation_factor: f32,
4197 world_rect: WorldRect,
4198 spatial_tree: &SpatialTree,
4199 device_pixel_scale: DevicePixelScale,
4200 scale_factors: (f32, f32),
4201 ) -> Self {
4202 let map_surface_to_world = SpaceMapper::new_with_target(
4203 ROOT_SPATIAL_NODE_INDEX,
4204 surface_spatial_node_index,
4205 world_rect,
4206 spatial_tree,
4207 );
4208
4209 let pic_bounds = map_surface_to_world
4210 .unmap(&map_surface_to_world.bounds)
4211 .unwrap_or_else(PictureRect::max_rect);
4212
4213 let map_local_to_surface = SpaceMapper::new(
4214 surface_spatial_node_index,
4215 pic_bounds,
4216 );
4217
4218 SurfaceInfo {
4219 rect: PictureRect::zero(),
4220 opaque_rect: PictureRect::zero(),
4221 map_local_to_surface,
4222 render_tasks: None,
4223 raster_spatial_node_index,
4224 surface_spatial_node_index,
4225 inflation_factor,
4226 device_pixel_scale,
4227 scale_factors,
4228 raster_rect: None,
4229 }
4230 }
4231
4232 pub fn get_raster_rect(&self) -> DeviceRect {
4233 self.raster_rect.expect("bug: queried before surface was initialized")
4234 }
4235}
4236
4237#[derive(Debug)]
4238#[cfg_attr(feature = "capture", derive(Serialize))]
4239pub struct RasterConfig {
4240 pub composite_mode: PictureCompositeMode,
4243 pub surface_index: SurfaceIndex,
4246 pub establishes_raster_root: bool,
4248 pub root_scaling_factor: f32,
4255 pub clipped_bounding_rect: WorldRect,
4260}
4261
4262bitflags! {
4263 #[cfg_attr(feature = "capture", derive(Serialize))]
4265 pub struct BlitReason: u32 {
4266 const ISOLATE = 1;
4268 const CLIP = 2;
4270 const PRESERVE3D = 4;
4272 const BACKDROP = 8;
4274 }
4275}
4276
4277#[allow(dead_code)]
4280#[derive(Debug, Clone)]
4281#[cfg_attr(feature = "capture", derive(Serialize))]
4282pub enum PictureCompositeMode {
4283 MixBlend(MixBlendMode),
4285 Filter(Filter),
4287 ComponentTransferFilter(FilterDataHandle),
4289 Blit(BlitReason),
4292 TileCache {
4294 slice_id: SliceId,
4295 },
4296 SvgFilter(Vec<FilterPrimitive>, Vec<SFilterData>),
4298}
4299
4300impl PictureCompositeMode {
4301 pub fn inflate_picture_rect(&self, picture_rect: PictureRect, scale_factors: (f32, f32)) -> PictureRect {
4302 let mut result_rect = picture_rect;
4303 match self {
4304 PictureCompositeMode::Filter(filter) => match filter {
4305 Filter::Blur(width, height) => {
4306 let width_factor = clamp_blur_radius(*width, scale_factors).ceil() * BLUR_SAMPLE_SCALE;
4307 let height_factor = clamp_blur_radius(*height, scale_factors).ceil() * BLUR_SAMPLE_SCALE;
4308 result_rect = picture_rect.inflate(width_factor, height_factor);
4309 },
4310 Filter::DropShadows(shadows) => {
4311 let mut max_inflation: f32 = 0.0;
4312 for shadow in shadows {
4313 max_inflation = max_inflation.max(shadow.blur_radius);
4314 }
4315 max_inflation = clamp_blur_radius(max_inflation, scale_factors).ceil() * BLUR_SAMPLE_SCALE;
4316 result_rect = picture_rect.inflate(max_inflation, max_inflation);
4317 },
4318 _ => {}
4319 }
4320 PictureCompositeMode::SvgFilter(primitives, _) => {
4321 let mut output_rects = Vec::with_capacity(primitives.len());
4322 for (cur_index, primitive) in primitives.iter().enumerate() {
4323 let output_rect = match primitive.kind {
4324 FilterPrimitiveKind::Blur(ref primitive) => {
4325 let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect);
4326 let width_factor = primitive.width.round() * BLUR_SAMPLE_SCALE;
4327 let height_factor = primitive.height.round() * BLUR_SAMPLE_SCALE;
4328 input.inflate(width_factor, height_factor)
4329 }
4330 FilterPrimitiveKind::DropShadow(ref primitive) => {
4331 let inflation_factor = primitive.shadow.blur_radius.ceil() * BLUR_SAMPLE_SCALE;
4332 let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect);
4333 let shadow_rect = input.inflate(inflation_factor, inflation_factor);
4334 input.union(&shadow_rect.translate(primitive.shadow.offset * Scale::new(1.0)))
4335 }
4336 FilterPrimitiveKind::Blend(ref primitive) => {
4337 primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect)
4338 .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect))
4339 }
4340 FilterPrimitiveKind::Composite(ref primitive) => {
4341 primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect)
4342 .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect))
4343 }
4344 FilterPrimitiveKind::Identity(ref primitive) =>
4345 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect),
4346 FilterPrimitiveKind::Opacity(ref primitive) =>
4347 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect),
4348 FilterPrimitiveKind::ColorMatrix(ref primitive) =>
4349 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect),
4350 FilterPrimitiveKind::ComponentTransfer(ref primitive) =>
4351 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect),
4352 FilterPrimitiveKind::Offset(ref primitive) => {
4353 let input_rect = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect);
4354 input_rect.translate(primitive.offset * Scale::new(1.0))
4355 },
4356
4357 FilterPrimitiveKind::Flood(..) => picture_rect,
4358 };
4359 output_rects.push(output_rect);
4360 result_rect = result_rect.union(&output_rect);
4361 }
4362 }
4363 _ => {},
4364 }
4365 result_rect
4366 }
4367}
4368
4369#[derive(Clone, Debug)]
4371#[cfg_attr(feature = "capture", derive(Serialize))]
4372pub enum Picture3DContext<C> {
4373 Out,
4375 In {
4377 root_data: Option<Vec<C>>,
4379 ancestor_index: SpatialNodeIndex,
4385 },
4386}
4387
4388#[derive(Clone, Debug)]
4391#[cfg_attr(feature = "capture", derive(Serialize))]
4392pub struct OrderedPictureChild {
4393 pub anchor: PlaneSplitAnchor,
4394 pub spatial_node_index: SpatialNodeIndex,
4395 pub gpu_address: GpuCacheAddress,
4396}
4397
4398bitflags! {
4399 #[cfg_attr(feature = "capture", derive(Serialize))]
4401 pub struct ClusterFlags: u32 {
4402 const IS_BACKFACE_VISIBLE = 1;
4404 const IS_VISIBLE = 2;
4408 const IS_BACKDROP_FILTER = 4;
4410 }
4411}
4412
4413#[cfg_attr(feature = "capture", derive(Serialize))]
4416pub struct PrimitiveCluster {
4417 pub spatial_node_index: SpatialNodeIndex,
4419 bounding_rect: LayoutRect,
4424 pub opaque_rect: LayoutRect,
4428 pub prim_range: Range<usize>,
4430 pub flags: ClusterFlags,
4432}
4433
4434impl PrimitiveCluster {
4435 fn new(
4437 spatial_node_index: SpatialNodeIndex,
4438 flags: ClusterFlags,
4439 first_instance_index: usize,
4440 ) -> Self {
4441 PrimitiveCluster {
4442 bounding_rect: LayoutRect::zero(),
4443 opaque_rect: LayoutRect::zero(),
4444 spatial_node_index,
4445 flags,
4446 prim_range: first_instance_index..first_instance_index
4447 }
4448 }
4449
4450 pub fn is_compatible(
4452 &self,
4453 spatial_node_index: SpatialNodeIndex,
4454 flags: ClusterFlags,
4455 ) -> bool {
4456 self.flags == flags && self.spatial_node_index == spatial_node_index
4457 }
4458
4459 pub fn prim_range(&self) -> Range<usize> {
4460 self.prim_range.clone()
4461 }
4462
4463 fn add_instance(
4465 &mut self,
4466 culling_rect: &LayoutRect,
4467 instance_index: usize,
4468 ) {
4469 debug_assert_eq!(instance_index, self.prim_range.end);
4470 self.bounding_rect = self.bounding_rect.union(culling_rect);
4471 self.prim_range.end += 1;
4472 }
4473}
4474
4475#[cfg_attr(feature = "capture", derive(Serialize))]
4480pub struct PrimitiveList {
4481 pub clusters: Vec<PrimitiveCluster>,
4483 pub prim_instances: Vec<PrimitiveInstance>,
4484 pub child_pictures: Vec<PictureIndex>,
4485 pub compositor_surface_count: usize,
4488}
4489
4490impl PrimitiveList {
4491 pub fn empty() -> Self {
4496 PrimitiveList {
4497 clusters: Vec::new(),
4498 prim_instances: Vec::new(),
4499 child_pictures: Vec::new(),
4500 compositor_surface_count: 0,
4501 }
4502 }
4503
4504 pub fn add_prim(
4506 &mut self,
4507 prim_instance: PrimitiveInstance,
4508 prim_rect: LayoutRect,
4509 spatial_node_index: SpatialNodeIndex,
4510 prim_flags: PrimitiveFlags,
4511 ) {
4512 let mut flags = ClusterFlags::empty();
4513
4514 match prim_instance.kind {
4517 PrimitiveInstanceKind::Picture { pic_index, .. } => {
4518 self.child_pictures.push(pic_index);
4519 }
4520 PrimitiveInstanceKind::Backdrop { .. } => {
4521 flags.insert(ClusterFlags::IS_BACKDROP_FILTER);
4522 }
4523 _ => {}
4524 }
4525
4526 if prim_flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE) {
4527 flags.insert(ClusterFlags::IS_BACKFACE_VISIBLE);
4528 }
4529
4530 if prim_flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
4531 self.compositor_surface_count += 1;
4532 }
4533
4534 let culling_rect = prim_instance.clip_set.local_clip_rect
4535 .intersection(&prim_rect)
4536 .unwrap_or_else(LayoutRect::zero);
4537
4538 let prims_len = self.prim_instances.len();
4551 if prims_len == self.prim_instances.capacity() {
4552 let next_alloc = match prims_len {
4553 1 ..= 31 => 32 - prims_len,
4554 32 ..= 256 => 512 - prims_len,
4555 _ => prims_len * 2,
4556 };
4557
4558 self.prim_instances.reserve(next_alloc);
4559 }
4560
4561 let instance_index = prims_len;
4562 self.prim_instances.push(prim_instance);
4563
4564 if let Some(cluster) = self.clusters.last_mut() {
4565 if cluster.is_compatible(spatial_node_index, flags) {
4566 cluster.add_instance(&culling_rect, instance_index);
4567 return;
4568 }
4569 }
4570
4571 let clusters_len = self.clusters.len();
4573 if clusters_len == self.clusters.capacity() {
4574 let next_alloc = match clusters_len {
4575 1 ..= 15 => 16 - clusters_len,
4576 16 ..= 127 => 128 - clusters_len,
4577 _ => clusters_len * 2,
4578 };
4579
4580 self.clusters.reserve(next_alloc);
4581 }
4582
4583 let mut cluster = PrimitiveCluster::new(
4584 spatial_node_index,
4585 flags,
4586 instance_index,
4587 );
4588
4589 cluster.add_instance(&culling_rect, instance_index);
4590 self.clusters.push(cluster);
4591 }
4592
4593 pub fn is_empty(&self) -> bool {
4595 self.clusters.is_empty()
4596 }
4597}
4598
4599#[cfg_attr(feature = "capture", derive(Serialize))]
4601pub struct PictureOptions {
4602 pub inflate_if_required: bool,
4605}
4606
4607impl Default for PictureOptions {
4608 fn default() -> Self {
4609 PictureOptions {
4610 inflate_if_required: true,
4611 }
4612 }
4613}
4614
4615#[cfg_attr(feature = "capture", derive(Serialize))]
4616pub struct PicturePrimitive {
4617 pub prim_list: PrimitiveList,
4619
4620 #[cfg_attr(feature = "capture", serde(skip))]
4621 pub state: Option<PictureState>,
4622
4623 pub apply_local_clip_rect: bool,
4626 pub is_backface_visible: bool,
4629
4630 pub primary_render_task_id: Option<RenderTaskId>,
4631 pub secondary_render_task_id: Option<RenderTaskId>,
4638 pub requested_composite_mode: Option<PictureCompositeMode>,
4641
4642 pub raster_config: Option<RasterConfig>,
4643 pub context_3d: Picture3DContext<OrderedPictureChild>,
4644
4645 pub extra_gpu_data_handles: SmallVec<[GpuCacheHandle; 1]>,
4649
4650 pub spatial_node_index: SpatialNodeIndex,
4653
4654 pub estimated_local_rect: LayoutRect,
4658
4659 pub precise_local_rect: LayoutRect,
4667
4668 pub prev_precise_local_rect: LayoutRect,
4672
4673 pub segments_are_valid: bool,
4678
4679 pub options: PictureOptions,
4681
4682 pub is_opaque: bool,
4684}
4685
4686impl PicturePrimitive {
4687 pub fn print<T: PrintTreePrinter>(
4688 &self,
4689 pictures: &[Self],
4690 self_index: PictureIndex,
4691 pt: &mut T,
4692 ) {
4693 pt.new_level(format!("{:?}", self_index));
4694 pt.add_item(format!("cluster_count: {:?}", self.prim_list.clusters.len()));
4695 pt.add_item(format!("estimated_local_rect: {:?}", self.estimated_local_rect));
4696 pt.add_item(format!("precise_local_rect: {:?}", self.precise_local_rect));
4697 pt.add_item(format!("spatial_node_index: {:?}", self.spatial_node_index));
4698 pt.add_item(format!("raster_config: {:?}", self.raster_config));
4699 pt.add_item(format!("requested_composite_mode: {:?}", self.requested_composite_mode));
4700
4701 for child_pic_index in &self.prim_list.child_pictures {
4702 pictures[child_pic_index.0].print(pictures, *child_pic_index, pt);
4703 }
4704
4705 pt.end_level();
4706 }
4707
4708 pub fn can_use_segments(&self) -> bool {
4710 match self.raster_config {
4711 Some(RasterConfig { composite_mode: PictureCompositeMode::MixBlend(..), .. }) |
4715 Some(RasterConfig { composite_mode: PictureCompositeMode::Filter(..), .. }) |
4716 Some(RasterConfig { composite_mode: PictureCompositeMode::ComponentTransferFilter(..), .. }) |
4717 Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { .. }, .. }) |
4718 Some(RasterConfig { composite_mode: PictureCompositeMode::SvgFilter(..), .. }) |
4719 None => {
4720 false
4721 }
4722 Some(RasterConfig { composite_mode: PictureCompositeMode::Blit(reason), ..}) => {
4723 reason == BlitReason::CLIP
4724 }
4725 }
4726 }
4727
4728 fn resolve_scene_properties(&mut self, properties: &SceneProperties) -> bool {
4729 match self.requested_composite_mode {
4730 Some(PictureCompositeMode::Filter(ref mut filter)) => {
4731 match *filter {
4732 Filter::Opacity(ref binding, ref mut value) => {
4733 *value = properties.resolve_float(binding);
4734 }
4735 _ => {}
4736 }
4737
4738 filter.is_visible()
4739 }
4740 _ => true,
4741 }
4742 }
4743
4744 pub fn is_visible(&self) -> bool {
4745 match self.requested_composite_mode {
4746 Some(PictureCompositeMode::Filter(ref filter)) => {
4747 filter.is_visible()
4748 }
4749 _ => true,
4750 }
4751 }
4752
4753 pub fn new_image(
4758 requested_composite_mode: Option<PictureCompositeMode>,
4759 context_3d: Picture3DContext<OrderedPictureChild>,
4760 apply_local_clip_rect: bool,
4761 flags: PrimitiveFlags,
4762 prim_list: PrimitiveList,
4763 spatial_node_index: SpatialNodeIndex,
4764 options: PictureOptions,
4765 ) -> Self {
4766 PicturePrimitive {
4767 prim_list,
4768 state: None,
4769 primary_render_task_id: None,
4770 secondary_render_task_id: None,
4771 requested_composite_mode,
4772 raster_config: None,
4773 context_3d,
4774 extra_gpu_data_handles: SmallVec::new(),
4775 apply_local_clip_rect,
4776 is_backface_visible: flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE),
4777 spatial_node_index,
4778 estimated_local_rect: LayoutRect::zero(),
4779 precise_local_rect: LayoutRect::zero(),
4780 prev_precise_local_rect: LayoutRect::zero(),
4781 options,
4782 segments_are_valid: false,
4783 is_opaque: false,
4784 }
4785 }
4786
4787 pub fn take_context(
4788 &mut self,
4789 pic_index: PictureIndex,
4790 surface_spatial_node_index: SpatialNodeIndex,
4791 raster_spatial_node_index: SpatialNodeIndex,
4792 parent_surface_index: SurfaceIndex,
4793 parent_subpixel_mode: SubpixelMode,
4794 frame_state: &mut FrameBuildingState,
4795 frame_context: &FrameBuildingContext,
4796 scratch: &mut PrimitiveScratchBuffer,
4797 tile_cache_logger: &mut TileCacheLogger,
4798 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
4799 ) -> Option<(PictureContext, PictureState, PrimitiveList)> {
4800 self.primary_render_task_id = None;
4801 self.secondary_render_task_id = None;
4802
4803 if !self.is_visible() {
4804 return None;
4805 }
4806
4807 profile_scope!("take_context");
4808
4809 let (raster_spatial_node_index, surface_spatial_node_index, surface_index, inflation_factor) = match self.raster_config {
4813 Some(ref raster_config) => {
4814 let surface = &frame_state.surfaces[raster_config.surface_index.0];
4815
4816 (
4817 surface.raster_spatial_node_index,
4818 self.spatial_node_index,
4819 raster_config.surface_index,
4820 surface.inflation_factor,
4821 )
4822 }
4823 None => {
4824 (
4825 raster_spatial_node_index,
4826 surface_spatial_node_index,
4827 parent_surface_index,
4828 0.0,
4829 )
4830 }
4831 };
4832
4833 let map_pic_to_world = SpaceMapper::new_with_target(
4834 ROOT_SPATIAL_NODE_INDEX,
4835 surface_spatial_node_index,
4836 frame_context.global_screen_world_rect,
4837 frame_context.spatial_tree,
4838 );
4839
4840 let pic_bounds = map_pic_to_world
4841 .unmap(&map_pic_to_world.bounds)
4842 .unwrap_or_else(PictureRect::max_rect);
4843
4844 let map_local_to_pic = SpaceMapper::new(
4845 surface_spatial_node_index,
4846 pic_bounds,
4847 );
4848
4849 let (map_raster_to_world, map_pic_to_raster) = create_raster_mappers(
4850 surface_spatial_node_index,
4851 raster_spatial_node_index,
4852 frame_context.global_screen_world_rect,
4853 frame_context.spatial_tree,
4854 );
4855
4856 let plane_splitter = match self.context_3d {
4857 Picture3DContext::Out => {
4858 None
4859 }
4860 Picture3DContext::In { root_data: Some(_), .. } => {
4861 Some(PlaneSplitter::new())
4862 }
4863 Picture3DContext::In { root_data: None, .. } => {
4864 None
4865 }
4866 };
4867
4868 match self.raster_config {
4869 Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) => {
4870 let tile_cache = tile_caches.get_mut(&slice_id).unwrap();
4871 let mut debug_info = SliceDebugInfo::new();
4872 let mut surface_tasks = Vec::with_capacity(tile_cache.tile_count());
4873 let mut surface_local_rect = PictureRect::zero();
4874 let device_pixel_scale = frame_state
4875 .surfaces[surface_index.0]
4876 .device_pixel_scale;
4877
4878 let world_clip_rect = map_pic_to_world
4881 .map(&tile_cache.local_clip_rect)
4882 .expect("bug: unable to map clip rect")
4883 .round();
4884 let device_clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round();
4885
4886 for (sub_slice_index, sub_slice) in tile_cache.sub_slices.iter_mut().enumerate() {
4887 for tile in sub_slice.tiles.values_mut() {
4888 surface_local_rect = surface_local_rect.union(&tile.current_descriptor.local_valid_rect);
4889
4890 if tile.is_visible {
4891 let world_draw_rect = world_clip_rect.intersection(&tile.world_valid_rect);
4893
4894 match world_draw_rect {
4899 Some(world_draw_rect) => {
4900 if tile_cache.spatial_node_index == ROOT_SPATIAL_NODE_INDEX &&
4902 frame_state.composite_state.occluders.is_tile_occluded(tile.z_id, world_draw_rect) {
4903 let surface = tile.surface.as_mut().expect("no tile surface set!");
4908
4909 if let TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { id, .. }, .. } = surface {
4910 if let Some(id) = id.take() {
4911 frame_state.resource_cache.destroy_compositor_tile(id);
4912 }
4913 }
4914
4915 tile.is_visible = false;
4916
4917 if frame_context.fb_config.testing {
4918 debug_info.tiles.insert(
4919 tile.tile_offset,
4920 TileDebugInfo::Occluded,
4921 );
4922 }
4923
4924 continue;
4925 }
4926 }
4927 None => {
4928 tile.is_visible = false;
4929 }
4930 }
4931 }
4932
4933 if let Some(TileSurface::Texture { descriptor, .. }) = tile.surface.as_ref() {
4938 if let SurfaceTextureDescriptor::TextureCache { ref handle, .. } = descriptor {
4939 frame_state.resource_cache.texture_cache.request(
4940 handle,
4941 frame_state.gpu_cache,
4942 );
4943 }
4944 }
4945
4946 if !tile.is_visible {
4948 if frame_context.fb_config.testing {
4949 debug_info.tiles.insert(
4950 tile.tile_offset,
4951 TileDebugInfo::Culled,
4952 );
4953 }
4954
4955 continue;
4956 }
4957
4958 if frame_context.debug_flags.contains(DebugFlags::PICTURE_CACHING_DBG) {
4959 tile.root.draw_debug_rects(
4960 &map_pic_to_world,
4961 tile.is_opaque,
4962 tile.current_descriptor.local_valid_rect,
4963 scratch,
4964 frame_context.global_device_pixel_scale,
4965 );
4966
4967 let label_offset = DeviceVector2D::new(
4968 20.0 + sub_slice_index as f32 * 20.0,
4969 30.0 + sub_slice_index as f32 * 20.0,
4970 );
4971 let tile_device_rect = tile.world_tile_rect * frame_context.global_device_pixel_scale;
4972 if tile_device_rect.height() >= label_offset.y {
4973 let surface = tile.surface.as_ref().expect("no tile surface set!");
4974
4975 scratch.push_debug_string(
4976 tile_device_rect.min + label_offset,
4977 debug_colors::RED,
4978 format!("{:?}: s={} is_opaque={} surface={} sub={}",
4979 tile.id,
4980 tile_cache.slice,
4981 tile.is_opaque,
4982 surface.kind(),
4983 sub_slice_index,
4984 ),
4985 );
4986 }
4987 }
4988
4989 if let TileSurface::Texture { descriptor, .. } = tile.surface.as_mut().unwrap() {
4990 match descriptor {
4991 SurfaceTextureDescriptor::TextureCache { ref handle, .. } => {
4992 if frame_state.resource_cache.texture_cache.is_allocated(handle) {
4994 frame_state.resource_cache.texture_cache.request(handle, frame_state.gpu_cache);
5003 } else {
5004 tile.invalidate(None, InvalidationReason::NoTexture);
5007 }
5008 }
5009 SurfaceTextureDescriptor::Native { id, .. } => {
5010 if id.is_none() {
5011 tile.invalidate(None, InvalidationReason::NoSurface);
5013 }
5014 }
5015 }
5016 }
5017
5018 tile.local_dirty_rect = tile.local_dirty_rect
5020 .intersection(&tile.current_descriptor.local_valid_rect)
5021 .unwrap_or_else(PictureRect::zero);
5022
5023 let world_dirty_rect = map_pic_to_world.map(&tile.local_dirty_rect).expect("bug");
5025
5026 let device_rect = (tile.world_tile_rect * frame_context.global_device_pixel_scale).round();
5027 tile.device_dirty_rect = (world_dirty_rect * frame_context.global_device_pixel_scale)
5028 .round_out()
5029 .intersection(&device_rect)
5030 .unwrap_or_else(DeviceRect::zero);
5031
5032 if tile.is_valid {
5033 if frame_context.fb_config.testing {
5034 debug_info.tiles.insert(
5035 tile.tile_offset,
5036 TileDebugInfo::Valid,
5037 );
5038 }
5039 } else {
5040 tile_cache.dirty_region.add_dirty_region(
5044 tile.local_dirty_rect,
5045 SubSliceIndex::new(sub_slice_index),
5046 frame_context.spatial_tree,
5047 );
5048
5049 if let TileSurface::Texture { ref mut descriptor } = tile.surface.as_mut().unwrap() {
5051 match descriptor {
5052 SurfaceTextureDescriptor::TextureCache { ref mut handle } => {
5053 if !frame_state.resource_cache.texture_cache.is_allocated(handle) {
5054 frame_state.resource_cache.texture_cache.update_picture_cache(
5055 tile_cache.current_tile_size,
5056 handle,
5057 frame_state.gpu_cache,
5058 );
5059 }
5060 }
5061 SurfaceTextureDescriptor::Native { id } => {
5062 if id.is_none() {
5063 if sub_slice.native_surface.is_none() {
5067 let opaque = frame_state
5068 .resource_cache
5069 .create_compositor_surface(
5070 tile_cache.virtual_offset,
5071 tile_cache.current_tile_size,
5072 true,
5073 );
5074
5075 let alpha = frame_state
5076 .resource_cache
5077 .create_compositor_surface(
5078 tile_cache.virtual_offset,
5079 tile_cache.current_tile_size,
5080 false,
5081 );
5082
5083 sub_slice.native_surface = Some(NativeSurface {
5084 opaque,
5085 alpha,
5086 });
5087 }
5088
5089 let surface_id = if tile.is_opaque {
5091 sub_slice.native_surface.as_ref().unwrap().opaque
5092 } else {
5093 sub_slice.native_surface.as_ref().unwrap().alpha
5094 };
5095
5096 let tile_id = NativeTileId {
5097 surface_id,
5098 x: tile.tile_offset.x,
5099 y: tile.tile_offset.y,
5100 };
5101
5102 frame_state.resource_cache.create_compositor_tile(tile_id);
5103
5104 *id = Some(tile_id);
5105 }
5106 }
5107 }
5108
5109 let content_origin_f = tile.local_tile_rect.min.cast_unit() * device_pixel_scale;
5116 let content_origin = content_origin_f.round();
5117 debug_assert!((content_origin_f.x - content_origin.x).abs() < 0.15);
5122 debug_assert!((content_origin_f.y - content_origin.y).abs() < 0.15);
5123
5124 let surface = descriptor.resolve(
5125 frame_state.resource_cache,
5126 tile_cache.current_tile_size,
5127 );
5128
5129 let scissor_rect = frame_state.composite_state.get_surface_rect(
5130 &tile.local_dirty_rect,
5131 &tile.local_tile_rect,
5132 tile_cache.transform_index,
5133 ).to_i32();
5134
5135 let valid_rect = frame_state.composite_state.get_surface_rect(
5136 &tile.current_descriptor.local_valid_rect,
5137 &tile.local_tile_rect,
5138 tile_cache.transform_index,
5139 ).to_i32();
5140
5141 let task_size = tile_cache.current_tile_size;
5142
5143 let batch_filter = BatchFilter {
5144 rect_in_pic_space: tile.local_dirty_rect,
5145 sub_slice_index: SubSliceIndex::new(sub_slice_index),
5146 };
5147
5148 let render_task_id = frame_state.rg_builder.add().init(
5149 RenderTask::new(
5150 RenderTaskLocation::Static {
5151 surface: StaticRenderTaskSurface::PictureCache {
5152 surface,
5153 },
5154 rect: task_size.into(),
5155 },
5156 RenderTaskKind::new_picture(
5157 task_size,
5158 tile_cache.current_tile_size.to_f32(),
5159 pic_index,
5160 content_origin,
5161 surface_spatial_node_index,
5162 device_pixel_scale,
5163 Some(batch_filter),
5164 Some(scissor_rect),
5165 Some(valid_rect),
5166 )
5167 ),
5168 );
5169
5170 surface_tasks.push(render_task_id);
5171 }
5172
5173 if frame_context.fb_config.testing {
5174 debug_info.tiles.insert(
5175 tile.tile_offset,
5176 TileDebugInfo::Dirty(DirtyTileDebugInfo {
5177 local_valid_rect: tile.current_descriptor.local_valid_rect,
5178 local_dirty_rect: tile.local_dirty_rect,
5179 }),
5180 );
5181 }
5182 }
5183
5184 let surface = tile.surface.as_ref().expect("no tile surface set!");
5185
5186 let descriptor = CompositeTileDescriptor {
5187 surface_kind: surface.into(),
5188 tile_id: tile.id,
5189 };
5190
5191 let (surface, is_opaque) = match surface {
5192 TileSurface::Color { color } => {
5193 (CompositeTileSurface::Color { color: *color }, true)
5194 }
5195 TileSurface::Clear => {
5196 (CompositeTileSurface::Clear, false)
5198 }
5199 TileSurface::Texture { descriptor, .. } => {
5200 let surface = descriptor.resolve(frame_state.resource_cache, tile_cache.current_tile_size);
5201 (
5202 CompositeTileSurface::Texture { surface },
5203 tile.is_opaque
5204 )
5205 }
5206 };
5207
5208 if is_opaque {
5209 sub_slice.opaque_tile_descriptors.push(descriptor);
5210 } else {
5211 sub_slice.alpha_tile_descriptors.push(descriptor);
5212 }
5213
5214 let composite_tile = CompositeTile {
5215 kind: tile_kind(&surface, is_opaque),
5216 surface,
5217 local_rect: tile.local_tile_rect,
5218 local_valid_rect: tile.current_descriptor.local_valid_rect,
5219 local_dirty_rect: tile.local_dirty_rect,
5220 device_clip_rect,
5221 z_id: tile.z_id,
5222 transform_index: tile_cache.transform_index,
5223 };
5224
5225 sub_slice.composite_tiles.push(composite_tile);
5226
5227 tile.local_dirty_rect = PictureRect::zero();
5229 tile.is_valid = true;
5230 }
5231
5232 sub_slice.opaque_tile_descriptors.sort_by_key(|desc| desc.tile_id);
5237 sub_slice.alpha_tile_descriptors.sort_by_key(|desc| desc.tile_id);
5238 }
5239
5240 if frame_context.debug_flags.contains(DebugFlags::INVALIDATION_DBG) {
5242 tile_cache.print();
5243 }
5244
5245 if frame_context.fb_config.testing {
5248 frame_state.composite_state
5249 .picture_cache_debug
5250 .slices
5251 .insert(
5252 tile_cache.slice,
5253 debug_info,
5254 );
5255 }
5256
5257 let surface_raster_rect = map_pic_to_raster.map(&surface_local_rect).expect("bug: unable to map to raster");
5261 let surface_device_rect = surface_raster_rect.cast_unit() * device_pixel_scale;
5262
5263 frame_state.init_surface_tiled(
5264 surface_index,
5265 surface_tasks,
5266 surface_device_rect,
5267 );
5268 }
5269 Some(ref mut raster_config) => {
5270 let pic_rect = self.precise_local_rect.cast_unit();
5271
5272 let mut device_pixel_scale = frame_state
5273 .surfaces[raster_config.surface_index.0]
5274 .device_pixel_scale;
5275
5276 let scale_factors = frame_state
5277 .surfaces[raster_config.surface_index.0]
5278 .scale_factors;
5279
5280 let clip_inflation = match raster_config.composite_mode {
5283 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
5284 let mut max_offset = vec2(0.0, 0.0);
5285 let mut min_offset = vec2(0.0, 0.0);
5286 for shadow in shadows {
5287 let offset = layout_vector_as_picture_vector(shadow.offset);
5288 max_offset = max_offset.max(offset);
5289 min_offset = min_offset.min(offset);
5290 }
5291
5292 let raster_min = map_pic_to_raster.map_vector(min_offset);
5294 let raster_max = map_pic_to_raster.map_vector(max_offset);
5295 let world_min = map_raster_to_world.map_vector(raster_min);
5296 let world_max = map_raster_to_world.map_vector(raster_max);
5297
5298 SideOffsets2D::from_vectors_outer(
5300 -world_max.max(vec2(0.0, 0.0)),
5301 -world_min.min(vec2(0.0, 0.0)),
5302 )
5303 }
5304 _ => SideOffsets2D::zero(),
5305 };
5306
5307 let (mut clipped, mut unclipped) = match get_raster_rects(
5308 pic_rect,
5309 &map_pic_to_raster,
5310 &map_raster_to_world,
5311 raster_config.clipped_bounding_rect.outer_box(clip_inflation),
5312 device_pixel_scale,
5313 ) {
5314 Some(info) => info,
5315 None => {
5316 return None
5317 }
5318 };
5319 let transform = map_pic_to_raster.get_transform();
5320
5321 fn adjust_scale_for_max_surface_size(
5337 raster_config: &RasterConfig,
5338 max_target_size: i32,
5339 pic_rect: PictureRect,
5340 map_pic_to_raster: &SpaceMapper<PicturePixel, RasterPixel>,
5341 map_raster_to_world: &SpaceMapper<RasterPixel, WorldPixel>,
5342 clipped_prim_bounding_rect: WorldRect,
5343 device_pixel_scale : &mut DevicePixelScale,
5344 device_rect: &mut DeviceRect,
5345 unclipped: &mut DeviceRect) -> Option<f32>
5346 {
5347 let limit = if raster_config.establishes_raster_root {
5348 MAX_SURFACE_SIZE
5349 } else {
5350 max_target_size as f32
5351 };
5352 if device_rect.width() > limit || device_rect.height() > limit {
5353 let scale = (limit as f32 - 1.0) /
5356 (f32::max(device_rect.width(), device_rect.height()));
5357 *device_pixel_scale = *device_pixel_scale * Scale::new(scale);
5358 let new_device_rect = device_rect.to_f32() * Scale::new(scale);
5359 *device_rect = new_device_rect.round_out();
5360
5361 *unclipped = match get_raster_rects(
5362 pic_rect,
5363 &map_pic_to_raster,
5364 &map_raster_to_world,
5365 clipped_prim_bounding_rect,
5366 *device_pixel_scale
5367 ) {
5368 Some(info) => info.1,
5369 None => {
5370 return None
5371 }
5372 };
5373 Some(scale)
5374 }
5375 else
5376 {
5377 None
5378 }
5379 }
5380
5381 let primary_render_task_id;
5382 match raster_config.composite_mode {
5383 PictureCompositeMode::TileCache { .. } => {
5384 unreachable!("handled above");
5385 }
5386 PictureCompositeMode::Filter(Filter::Blur(width, height)) => {
5387 let width_std_deviation = clamp_blur_radius(width, scale_factors) * device_pixel_scale.0;
5388 let height_std_deviation = clamp_blur_radius(height, scale_factors) * device_pixel_scale.0;
5389 let mut blur_std_deviation = DeviceSize::new(
5390 width_std_deviation * scale_factors.0,
5391 height_std_deviation * scale_factors.1
5392 );
5393 let mut device_rect = if self.options.inflate_if_required {
5394 let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor;
5395 let inflation_factor = inflation_factor * device_pixel_scale.0;
5396
5397 clipped
5406 .inflate(inflation_factor * scale_factors.0, inflation_factor * scale_factors.1)
5407 .intersection(&unclipped)
5408 .unwrap()
5409 } else {
5410 clipped
5411 };
5412
5413 let mut original_size = device_rect.size();
5414
5415 let adjusted_size = BlurTask::adjusted_blur_source_size(
5419 device_rect.size(),
5420 blur_std_deviation,
5421 );
5422 device_rect.set_size(adjusted_size);
5423
5424 if let Some(scale) = adjust_scale_for_max_surface_size(
5425 raster_config, frame_context.fb_config.max_target_size,
5426 pic_rect, &map_pic_to_raster, &map_raster_to_world,
5427 raster_config.clipped_bounding_rect,
5428 &mut device_pixel_scale, &mut device_rect, &mut unclipped,
5429 ) {
5430 blur_std_deviation = blur_std_deviation * scale;
5431 original_size = original_size.to_f32() * scale;
5432 raster_config.root_scaling_factor = scale;
5433 }
5434
5435 let uv_rect_kind = calculate_uv_rect_kind(
5436 &pic_rect,
5437 &transform,
5438 &device_rect,
5439 device_pixel_scale,
5440 );
5441
5442 let task_size = device_rect.size().to_i32();
5443
5444 let picture_task_id = frame_state.rg_builder.add().init(
5445 RenderTask::new_dynamic(
5446 task_size,
5447 RenderTaskKind::new_picture(
5448 task_size,
5449 unclipped.size(),
5450 pic_index,
5451 device_rect.min,
5452 surface_spatial_node_index,
5453 device_pixel_scale,
5454 None,
5455 None,
5456 None,
5457 )
5458 ).with_uv_rect_kind(uv_rect_kind)
5459 );
5460
5461 let blur_render_task_id = RenderTask::new_blur(
5462 blur_std_deviation,
5463 picture_task_id,
5464 frame_state.rg_builder,
5465 RenderTargetKind::Color,
5466 None,
5467 original_size.to_i32(),
5468 );
5469
5470 primary_render_task_id = Some(blur_render_task_id);
5471
5472 frame_state.init_surface_chain(
5473 raster_config.surface_index,
5474 blur_render_task_id,
5475 picture_task_id,
5476 parent_surface_index,
5477 device_rect,
5478 );
5479 }
5480 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
5481 let mut max_std_deviation = 0.0;
5482 for shadow in shadows {
5483 max_std_deviation = f32::max(max_std_deviation, shadow.blur_radius);
5484 }
5485 max_std_deviation = clamp_blur_radius(max_std_deviation, scale_factors) * device_pixel_scale.0;
5486 let max_blur_range = max_std_deviation * BLUR_SAMPLE_SCALE;
5487
5488 let mut device_rect = clipped
5491 .inflate(max_blur_range * scale_factors.0, max_blur_range * scale_factors.1)
5492 .intersection(&unclipped)
5493 .unwrap();
5494
5495 let adjusted_size = BlurTask::adjusted_blur_source_size(
5496 device_rect.size(),
5497 DeviceSize::new(
5498 max_std_deviation * scale_factors.0,
5499 max_std_deviation * scale_factors.1
5500 ),
5501 );
5502 device_rect.set_size(adjusted_size);
5503
5504 if let Some(scale) = adjust_scale_for_max_surface_size(
5505 raster_config, frame_context.fb_config.max_target_size,
5506 pic_rect, &map_pic_to_raster, &map_raster_to_world,
5507 raster_config.clipped_bounding_rect,
5508 &mut device_pixel_scale, &mut device_rect, &mut unclipped,
5509 ) {
5510 raster_config.root_scaling_factor = scale;
5512 }
5513
5514 let uv_rect_kind = calculate_uv_rect_kind(
5515 &pic_rect,
5516 &transform,
5517 &device_rect,
5518 device_pixel_scale,
5519 );
5520
5521 let task_size = device_rect.size().to_i32();
5522
5523 let picture_task_id = frame_state.rg_builder.add().init(
5524 RenderTask::new_dynamic(
5525 task_size,
5526 RenderTaskKind::new_picture(
5527 task_size,
5528 unclipped.size(),
5529 pic_index,
5530 device_rect.min,
5531 surface_spatial_node_index,
5532 device_pixel_scale,
5533 None,
5534 None,
5535 None,
5536 ),
5537 ).with_uv_rect_kind(uv_rect_kind)
5538 );
5539
5540 frame_state.add_child_render_task(
5543 parent_surface_index,
5544 picture_task_id,
5545 );
5546
5547 let mut blur_tasks = BlurTaskCache::default();
5548
5549 self.extra_gpu_data_handles.resize(shadows.len(), GpuCacheHandle::new());
5550
5551 let mut blur_render_task_id = picture_task_id;
5552 for shadow in shadows {
5553 let blur_radius = clamp_blur_radius(shadow.blur_radius, scale_factors) * device_pixel_scale.0;
5554 blur_render_task_id = RenderTask::new_blur(
5555 DeviceSize::new(
5556 blur_radius * scale_factors.0,
5557 blur_radius * scale_factors.1,
5558 ),
5559 picture_task_id,
5560 frame_state.rg_builder,
5561 RenderTargetKind::Color,
5562 Some(&mut blur_tasks),
5563 device_rect.size().to_i32(),
5564 );
5565 }
5566
5567 primary_render_task_id = Some(blur_render_task_id);
5568 self.secondary_render_task_id = Some(picture_task_id);
5569
5570 frame_state.init_surface_chain(
5571 raster_config.surface_index,
5572 blur_render_task_id,
5573 picture_task_id,
5574 parent_surface_index,
5575 device_rect,
5576 );
5577 }
5578 PictureCompositeMode::MixBlend(mode) if BlendMode::from_mix_blend_mode(
5579 mode,
5580 frame_context.fb_config.gpu_supports_advanced_blend,
5581 frame_context.fb_config.advanced_blend_is_coherent,
5582 frame_context.fb_config.dual_source_blending_is_enabled &&
5583 frame_context.fb_config.dual_source_blending_is_supported,
5584 ).is_none() => {
5585 if let Some(scale) = adjust_scale_for_max_surface_size(
5586 raster_config, frame_context.fb_config.max_target_size,
5587 pic_rect, &map_pic_to_raster, &map_raster_to_world,
5588 raster_config.clipped_bounding_rect,
5589 &mut device_pixel_scale, &mut clipped, &mut unclipped,
5590 ) {
5591 raster_config.root_scaling_factor = scale;
5592 }
5593
5594 let uv_rect_kind = calculate_uv_rect_kind(
5595 &pic_rect,
5596 &transform,
5597 &clipped,
5598 device_pixel_scale,
5599 );
5600
5601 let parent_surface = &frame_state.surfaces[parent_surface_index.0];
5602 let parent_raster_spatial_node_index = parent_surface.raster_spatial_node_index;
5603 let parent_device_pixel_scale = parent_surface.device_pixel_scale;
5604
5605 let map_pic_to_parent = SpaceMapper::new_with_target(
5611 parent_raster_spatial_node_index,
5612 self.spatial_node_index,
5613 RasterRect::max_rect(), frame_context.spatial_tree,
5615 );
5616 let pic_in_raster_space = map_pic_to_parent
5617 .map(&pic_rect)
5618 .expect("bug: unable to map mix-blend content into parent");
5619
5620 let backdrop_rect = raster_rect_to_device_pixels(
5623 pic_in_raster_space,
5624 parent_device_pixel_scale,
5625 );
5626
5627 let parent_surface_rect = parent_surface.get_raster_rect();
5628
5629 let readback_task_id = match backdrop_rect.intersection(&parent_surface_rect) {
5636 Some(available_rect) => {
5637 let backdrop_uv = calculate_uv_rect_kind(
5642 &pic_rect,
5643 &map_pic_to_parent.get_transform(),
5644 &available_rect,
5645 parent_device_pixel_scale,
5646 );
5647
5648 frame_state.rg_builder.add().init(
5649 RenderTask::new_dynamic(
5650 available_rect.size().to_i32(),
5651 RenderTaskKind::new_readback(Some(available_rect.min)),
5652 ).with_uv_rect_kind(backdrop_uv)
5653 )
5654 }
5655 None => {
5656 frame_state.rg_builder.add().init(
5657 RenderTask::new_dynamic(
5658 DeviceIntSize::new(16, 16),
5659 RenderTaskKind::new_readback(None),
5660 )
5661 )
5662 }
5663 };
5664
5665 frame_state.add_child_render_task(
5666 parent_surface_index,
5667 readback_task_id,
5668 );
5669
5670 self.secondary_render_task_id = Some(readback_task_id);
5671
5672 let task_size = clipped.size().to_i32();
5673
5674 let render_task_id = frame_state.rg_builder.add().init(
5675 RenderTask::new_dynamic(
5676 task_size,
5677 RenderTaskKind::new_picture(
5678 task_size,
5679 unclipped.size(),
5680 pic_index,
5681 clipped.min,
5682 surface_spatial_node_index,
5683 device_pixel_scale,
5684 None,
5685 None,
5686 None,
5687 )
5688 ).with_uv_rect_kind(uv_rect_kind)
5689 );
5690
5691 primary_render_task_id = Some(render_task_id);
5692
5693 frame_state.init_surface(
5694 raster_config.surface_index,
5695 render_task_id,
5696 parent_surface_index,
5697 clipped,
5698 );
5699 }
5700 PictureCompositeMode::Filter(..) => {
5701
5702 if let Some(scale) = adjust_scale_for_max_surface_size(
5703 raster_config, frame_context.fb_config.max_target_size,
5704 pic_rect, &map_pic_to_raster, &map_raster_to_world,
5705 raster_config.clipped_bounding_rect,
5706 &mut device_pixel_scale, &mut clipped, &mut unclipped,
5707 ) {
5708 raster_config.root_scaling_factor = scale;
5709 }
5710
5711 let uv_rect_kind = calculate_uv_rect_kind(
5712 &pic_rect,
5713 &transform,
5714 &clipped,
5715 device_pixel_scale,
5716 );
5717
5718 let task_size = clipped.size().to_i32();
5719
5720 let render_task_id = frame_state.rg_builder.add().init(
5721 RenderTask::new_dynamic(
5722 task_size,
5723 RenderTaskKind::new_picture(
5724 task_size,
5725 unclipped.size(),
5726 pic_index,
5727 clipped.min,
5728 surface_spatial_node_index,
5729 device_pixel_scale,
5730 None,
5731 None,
5732 None,
5733 )
5734 ).with_uv_rect_kind(uv_rect_kind)
5735 );
5736
5737 primary_render_task_id = Some(render_task_id);
5738
5739 frame_state.init_surface(
5740 raster_config.surface_index,
5741 render_task_id,
5742 parent_surface_index,
5743 clipped,
5744 );
5745 }
5746 PictureCompositeMode::ComponentTransferFilter(..) => {
5747 if let Some(scale) = adjust_scale_for_max_surface_size(
5748 raster_config, frame_context.fb_config.max_target_size,
5749 pic_rect, &map_pic_to_raster, &map_raster_to_world,
5750 raster_config.clipped_bounding_rect,
5751 &mut device_pixel_scale, &mut clipped, &mut unclipped,
5752 ) {
5753 raster_config.root_scaling_factor = scale;
5754 }
5755
5756 let uv_rect_kind = calculate_uv_rect_kind(
5757 &pic_rect,
5758 &transform,
5759 &clipped,
5760 device_pixel_scale,
5761 );
5762
5763 let task_size = clipped.size().to_i32();
5764
5765 let render_task_id = frame_state.rg_builder.add().init(
5766 RenderTask::new_dynamic(
5767 task_size,
5768 RenderTaskKind::new_picture(
5769 task_size,
5770 unclipped.size(),
5771 pic_index,
5772 clipped.min,
5773 surface_spatial_node_index,
5774 device_pixel_scale,
5775 None,
5776 None,
5777 None,
5778 )
5779 ).with_uv_rect_kind(uv_rect_kind)
5780 );
5781
5782 primary_render_task_id = Some(render_task_id);
5783
5784 frame_state.init_surface(
5785 raster_config.surface_index,
5786 render_task_id,
5787 parent_surface_index,
5788 clipped,
5789 );
5790 }
5791 PictureCompositeMode::MixBlend(..) |
5792 PictureCompositeMode::Blit(_) => {
5793 if let Some(scale) = adjust_scale_for_max_surface_size(
5794 raster_config, frame_context.fb_config.max_target_size,
5795 pic_rect, &map_pic_to_raster, &map_raster_to_world,
5796 raster_config.clipped_bounding_rect,
5797 &mut device_pixel_scale, &mut clipped, &mut unclipped,
5798 ) {
5799 raster_config.root_scaling_factor = scale;
5800 }
5801
5802 let uv_rect_kind = calculate_uv_rect_kind(
5803 &pic_rect,
5804 &transform,
5805 &clipped,
5806 device_pixel_scale,
5807 );
5808
5809 let task_size = clipped.size().to_i32();
5810
5811 let render_task_id = frame_state.rg_builder.add().init(
5812 RenderTask::new_dynamic(
5813 task_size,
5814 RenderTaskKind::new_picture(
5815 task_size,
5816 unclipped.size(),
5817 pic_index,
5818 clipped.min,
5819 surface_spatial_node_index,
5820 device_pixel_scale,
5821 None,
5822 None,
5823 None,
5824 )
5825 ).with_uv_rect_kind(uv_rect_kind)
5826 );
5827
5828 primary_render_task_id = Some(render_task_id);
5829
5830 frame_state.init_surface(
5831 raster_config.surface_index,
5832 render_task_id,
5833 parent_surface_index,
5834 clipped,
5835 );
5836 }
5837 PictureCompositeMode::SvgFilter(ref primitives, ref filter_datas) => {
5838
5839 if let Some(scale) = adjust_scale_for_max_surface_size(
5840 raster_config, frame_context.fb_config.max_target_size,
5841 pic_rect, &map_pic_to_raster, &map_raster_to_world,
5842 raster_config.clipped_bounding_rect,
5843 &mut device_pixel_scale, &mut clipped, &mut unclipped,
5844 ) {
5845 raster_config.root_scaling_factor = scale;
5846 }
5847
5848 let uv_rect_kind = calculate_uv_rect_kind(
5849 &pic_rect,
5850 &transform,
5851 &clipped,
5852 device_pixel_scale,
5853 );
5854
5855 let task_size = clipped.size().to_i32();
5856
5857 let picture_task_id = frame_state.rg_builder.add().init(
5858 RenderTask::new_dynamic(
5859 task_size,
5860 RenderTaskKind::new_picture(
5861 task_size,
5862 unclipped.size(),
5863 pic_index,
5864 clipped.min,
5865 surface_spatial_node_index,
5866 device_pixel_scale,
5867 None,
5868 None,
5869 None,
5870 )
5871 ).with_uv_rect_kind(uv_rect_kind)
5872 );
5873
5874 let filter_task_id = RenderTask::new_svg_filter(
5875 primitives,
5876 filter_datas,
5877 frame_state.rg_builder,
5878 clipped.size().to_i32(),
5879 uv_rect_kind,
5880 picture_task_id,
5881 device_pixel_scale,
5882 );
5883
5884 primary_render_task_id = Some(filter_task_id);
5885
5886 frame_state.init_surface_chain(
5887 raster_config.surface_index,
5888 filter_task_id,
5889 picture_task_id,
5890 parent_surface_index,
5891 clipped,
5892 );
5893 }
5894 }
5895
5896 self.primary_render_task_id = primary_render_task_id;
5897
5898 frame_state
5902 .surfaces[raster_config.surface_index.0]
5903 .device_pixel_scale = device_pixel_scale;
5904 }
5905 None => {}
5906 };
5907
5908
5909 #[cfg(feature = "capture")]
5910 {
5911 if frame_context.debug_flags.contains(DebugFlags::TILE_CACHE_LOGGING_DBG) {
5912 if let Some(PictureCompositeMode::TileCache { slice_id }) = self.requested_composite_mode {
5913 if let Some(ref tile_cache) = tile_caches.get(&slice_id) {
5914 let mut tile_cache_tiny = TileCacheInstanceSerializer {
5916 slice: tile_cache.slice,
5917 tiles: FastHashMap::default(),
5918 background_color: tile_cache.background_color,
5919 };
5920 for (key, tile) in &tile_cache.sub_slices.first().unwrap().tiles {
5922 tile_cache_tiny.tiles.insert(*key, TileSerializer {
5923 rect: tile.local_tile_rect,
5924 current_descriptor: tile.current_descriptor.clone(),
5925 id: tile.id,
5926 root: tile.root.clone(),
5927 background_color: tile.background_color,
5928 invalidation_reason: tile.invalidation_reason.clone()
5929 });
5930 }
5931 let text = ron::ser::to_string_pretty(&tile_cache_tiny, Default::default()).unwrap();
5932 tile_cache_logger.add(text, map_pic_to_world.get_transform());
5933 }
5934 }
5935 }
5936 }
5937 #[cfg(not(feature = "capture"))]
5938 {
5939 let _tile_cache_logger = tile_cache_logger; }
5941
5942 let state = PictureState {
5943 map_local_to_pic,
5945 map_pic_to_world,
5946 map_pic_to_raster,
5947 map_raster_to_world,
5948 plane_splitter,
5949 };
5950
5951 let mut dirty_region_count = 0;
5952
5953 if let Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) = self.raster_config {
5956 let dirty_region = tile_caches[&slice_id].dirty_region.clone();
5957 frame_state.push_dirty_region(dirty_region);
5958 dirty_region_count += 1;
5959 }
5960
5961 if inflation_factor > 0.0 {
5962 let inflated_region = frame_state.current_dirty_region().inflate(
5963 inflation_factor,
5964 frame_context.spatial_tree,
5965 );
5966 frame_state.push_dirty_region(inflated_region);
5967 dirty_region_count += 1;
5968 }
5969
5970 let subpixel_mode = match self.raster_config {
5973 Some(RasterConfig { ref composite_mode, .. }) => {
5974 let subpixel_mode = match composite_mode {
5975 PictureCompositeMode::TileCache { slice_id } => {
5976 tile_caches[&slice_id].subpixel_mode
5977 }
5978 PictureCompositeMode::Blit(..) |
5979 PictureCompositeMode::ComponentTransferFilter(..) |
5980 PictureCompositeMode::Filter(..) |
5981 PictureCompositeMode::MixBlend(..) |
5982 PictureCompositeMode::SvgFilter(..) => {
5983 SubpixelMode::Deny
5988 }
5989 };
5990
5991 subpixel_mode
5992 }
5993 None => {
5994 SubpixelMode::Allow
5995 }
5996 };
5997
5998 let subpixel_mode = match (parent_subpixel_mode, subpixel_mode) {
6000 (SubpixelMode::Allow, SubpixelMode::Allow) => {
6001 SubpixelMode::Allow
6003 }
6004 (SubpixelMode::Allow, SubpixelMode::Conditional { allowed_rect }) => {
6005 SubpixelMode::Conditional {
6007 allowed_rect,
6008 }
6009 }
6010 (SubpixelMode::Conditional { allowed_rect }, SubpixelMode::Allow) => {
6011 SubpixelMode::Conditional {
6013 allowed_rect,
6014 }
6015 }
6016 (SubpixelMode::Conditional { .. }, SubpixelMode::Conditional { ..}) => {
6017 unreachable!("bug: only top level picture caches have conditional subpixel");
6018 }
6019 (SubpixelMode::Deny, _) | (_, SubpixelMode::Deny) => {
6020 SubpixelMode::Deny
6022 }
6023 };
6024
6025 let context = PictureContext {
6026 pic_index,
6027 apply_local_clip_rect: self.apply_local_clip_rect,
6028 raster_spatial_node_index,
6029 surface_spatial_node_index,
6030 surface_index,
6031 dirty_region_count,
6032 subpixel_mode,
6033 };
6034
6035 let prim_list = mem::replace(&mut self.prim_list, PrimitiveList::empty());
6036
6037 Some((context, state, prim_list))
6038 }
6039
6040 pub fn restore_context(
6041 &mut self,
6042 prim_list: PrimitiveList,
6043 context: PictureContext,
6044 state: PictureState,
6045 frame_state: &mut FrameBuildingState,
6046 ) {
6047 for _ in 0 .. context.dirty_region_count {
6049 frame_state.pop_dirty_region();
6050 }
6051
6052 self.prim_list = prim_list;
6053 self.state = Some(state);
6054 }
6055
6056 pub fn take_state(&mut self) -> PictureState {
6057 self.state.take().expect("bug: no state present!")
6058 }
6059
6060 pub fn add_split_plane(
6064 splitter: &mut PlaneSplitter,
6065 spatial_tree: &SpatialTree,
6066 prim_spatial_node_index: SpatialNodeIndex,
6067 original_local_rect: LayoutRect,
6068 combined_local_clip_rect: &LayoutRect,
6069 world_rect: WorldRect,
6070 plane_split_anchor: PlaneSplitAnchor,
6071 ) -> bool {
6072 let transform = spatial_tree
6073 .get_world_transform(prim_spatial_node_index);
6074 let matrix = transform.clone().into_transform().cast();
6075
6076 let local_rect = match original_local_rect
6083 .intersection(combined_local_clip_rect)
6084 {
6085 Some(rect) => rect.cast(),
6086 None => return false,
6087 };
6088 let world_rect = world_rect.cast();
6089
6090 match transform {
6091 CoordinateSpaceMapping::Local => {
6092 let polygon = Polygon::from_rect(
6093 local_rect.to_rect() * Scale::new(1.0),
6094 plane_split_anchor,
6095 );
6096 splitter.add(polygon);
6097 }
6098 CoordinateSpaceMapping::ScaleOffset(scale_offset) if scale_offset.scale == Vector2D::new(1.0, 1.0) => {
6099 let inv_matrix = scale_offset.inverse().to_transform().cast();
6100 let polygon = Polygon::from_transformed_rect_with_inverse(
6101 local_rect.to_rect(),
6102 &matrix,
6103 &inv_matrix,
6104 plane_split_anchor,
6105 ).unwrap();
6106 splitter.add(polygon);
6107 }
6108 CoordinateSpaceMapping::ScaleOffset(_) |
6109 CoordinateSpaceMapping::Transform(_) => {
6110 let mut clipper = Clipper::new();
6111 let results = clipper.clip_transformed(
6112 Polygon::from_rect(
6113 local_rect.to_rect(),
6114 plane_split_anchor,
6115 ),
6116 &matrix,
6117 Some(world_rect.to_rect()),
6118 );
6119 if let Ok(results) = results {
6120 for poly in results {
6121 splitter.add(poly);
6122 }
6123 }
6124 }
6125 }
6126
6127 true
6128 }
6129
6130 pub fn resolve_split_planes(
6131 &mut self,
6132 splitter: &mut PlaneSplitter,
6133 gpu_cache: &mut GpuCache,
6134 spatial_tree: &SpatialTree,
6135 ) {
6136 let ordered = match self.context_3d {
6137 Picture3DContext::In { root_data: Some(ref mut list), .. } => list,
6138 _ => panic!("Expected to find 3D context root"),
6139 };
6140 ordered.clear();
6141
6142 let sorted = splitter.sort(vec3(0.0, 0.0, 1.0));
6145 ordered.reserve(sorted.len());
6146 for poly in sorted {
6147 let cluster = &self.prim_list.clusters[poly.anchor.cluster_index];
6148 let spatial_node_index = cluster.spatial_node_index;
6149 let transform = match spatial_tree
6150 .get_world_transform(spatial_node_index)
6151 .inverse()
6152 {
6153 Some(transform) => transform.into_transform(),
6154 None => continue,
6156 };
6157
6158 let local_points = [
6159 transform.transform_point3d(poly.points[0].cast()),
6160 transform.transform_point3d(poly.points[1].cast()),
6161 transform.transform_point3d(poly.points[2].cast()),
6162 transform.transform_point3d(poly.points[3].cast()),
6163 ];
6164
6165 if local_points.iter().any(|p| p.is_none()) {
6168 continue;
6169 }
6170
6171 let p0 = local_points[0].unwrap();
6172 let p1 = local_points[1].unwrap();
6173 let p2 = local_points[2].unwrap();
6174 let p3 = local_points[3].unwrap();
6175 let gpu_blocks = [
6176 [p0.x, p0.y, p1.x, p1.y].into(),
6177 [p2.x, p2.y, p3.x, p3.y].into(),
6178 ];
6179 let gpu_handle = gpu_cache.push_per_frame_blocks(&gpu_blocks);
6180 let gpu_address = gpu_cache.get_address(&gpu_handle);
6181
6182 ordered.push(OrderedPictureChild {
6183 anchor: poly.anchor,
6184 spatial_node_index,
6185 gpu_address,
6186 });
6187 }
6188 }
6189
6190 fn pre_update(
6194 &mut self,
6195 state: &mut PictureUpdateState,
6196 frame_context: &FrameBuildingContext,
6197 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
6198 ) -> Option<PrimitiveList> {
6199 self.raster_config = None;
6201
6202 if !self.resolve_scene_properties(frame_context.scene_properties) {
6205 return None;
6206 }
6207
6208 if !self.is_backface_visible {
6213 if let Picture3DContext::Out = self.context_3d {
6214 match frame_context.spatial_tree.get_local_visible_face(self.spatial_node_index) {
6215 VisibleFace::Front => {}
6216 VisibleFace::Back => return None,
6217 }
6218 }
6219 }
6220
6221 let actual_composite_mode = self.requested_composite_mode.clone();
6224
6225 if let Some(composite_mode) = actual_composite_mode {
6226 let parent_raster_node_index = state.current_surface().raster_spatial_node_index;
6228 let parent_device_pixel_scale = state.current_surface().device_pixel_scale;
6229 let surface_spatial_node_index = self.spatial_node_index;
6230
6231 let surface_to_parent_transform = frame_context.spatial_tree
6232 .get_relative_transform(surface_spatial_node_index, parent_raster_node_index);
6233
6234 let mut min_scale = 1.0;
6236 let mut max_scale = 1.0e32;
6237
6238 let establishes_raster_root = match composite_mode {
6241 PictureCompositeMode::TileCache { slice_id } => {
6242 let tile_cache = tile_caches.get_mut(&slice_id).unwrap();
6243
6244 let update_raster_scale =
6249 !frame_context.fb_config.low_quality_pinch_zoom ||
6250 !frame_context.spatial_tree.spatial_nodes[tile_cache.spatial_node_index.0 as usize].is_ancestor_or_self_zooming;
6251
6252 if update_raster_scale {
6253 let local_to_device = get_relative_scale_offset(
6255 tile_cache.spatial_node_index,
6256 ROOT_SPATIAL_NODE_INDEX,
6257 frame_context.spatial_tree,
6258 );
6259
6260 tile_cache.current_raster_scale = local_to_device.scale.x;
6261 }
6262
6263 min_scale = 0.0;
6265
6266 if frame_context.fb_config.low_quality_pinch_zoom {
6267 min_scale = tile_cache.current_raster_scale;
6271 max_scale = tile_cache.current_raster_scale;
6272 }
6273
6274 true
6278 }
6279 PictureCompositeMode::SvgFilter(..) => {
6280 true
6282 }
6283 PictureCompositeMode::MixBlend(..) |
6284 PictureCompositeMode::Filter(..) |
6285 PictureCompositeMode::ComponentTransferFilter(..) |
6286 PictureCompositeMode::Blit(..) => {
6287 surface_to_parent_transform.is_perspective()
6289 }
6290 };
6291
6292 let (raster_spatial_node_index, device_pixel_scale) = if establishes_raster_root {
6293 let scale_factors = surface_to_parent_transform.scale_factors();
6296
6297 let scaling_factor = scale_factors.0.max(scale_factors.1).max(min_scale).min(max_scale);
6299
6300 let device_pixel_scale = parent_device_pixel_scale * Scale::new(scaling_factor);
6301 (surface_spatial_node_index, device_pixel_scale)
6302 } else {
6303 (parent_raster_node_index, parent_device_pixel_scale)
6304 };
6305
6306 let scale_factors = frame_context
6307 .spatial_tree
6308 .get_relative_transform(surface_spatial_node_index, raster_spatial_node_index)
6309 .scale_factors();
6310
6311 let mut inflation_factor = 0.0;
6314 if self.options.inflate_if_required {
6315 match composite_mode {
6316 PictureCompositeMode::Filter(Filter::Blur(width, height)) => {
6317 let blur_radius = f32::max(clamp_blur_radius(width, scale_factors), clamp_blur_radius(height, scale_factors));
6318 inflation_factor = blur_radius * BLUR_SAMPLE_SCALE;
6321 }
6322 PictureCompositeMode::SvgFilter(ref primitives, _) => {
6323 let mut max = 0.0;
6324 for primitive in primitives {
6325 if let FilterPrimitiveKind::Blur(ref blur) = primitive.kind {
6326 max = f32::max(max, blur.width);
6327 max = f32::max(max, blur.height);
6328 }
6329 }
6330 inflation_factor = clamp_blur_radius(max, scale_factors) * BLUR_SAMPLE_SCALE;
6331 }
6332 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
6333 let mut max_blur_radius: f32 = 0.0;
6340 for shadow in shadows {
6341 max_blur_radius = max_blur_radius.max(shadow.blur_radius);
6342 }
6343
6344 inflation_factor = clamp_blur_radius(max_blur_radius, scale_factors) * BLUR_SAMPLE_SCALE;
6345 }
6346 _ => {}
6347 }
6348 }
6349
6350 let surface = SurfaceInfo::new(
6351 surface_spatial_node_index,
6352 raster_spatial_node_index,
6353 inflation_factor,
6354 frame_context.global_screen_world_rect,
6355 &frame_context.spatial_tree,
6356 device_pixel_scale,
6357 scale_factors,
6358 );
6359
6360 self.raster_config = Some(RasterConfig {
6361 composite_mode,
6362 establishes_raster_root,
6363 surface_index: state.push_surface(surface),
6364 root_scaling_factor: 1.0,
6365 clipped_bounding_rect: WorldRect::zero(),
6366 });
6367 }
6368
6369 Some(mem::replace(&mut self.prim_list, PrimitiveList::empty()))
6370 }
6371
6372 fn post_update(
6375 &mut self,
6376 prim_list: PrimitiveList,
6377 state: &mut PictureUpdateState,
6378 frame_context: &FrameBuildingContext,
6379 data_stores: &mut DataStores,
6380 ) {
6381 self.prim_list = prim_list;
6383
6384 let surface = state.current_surface_mut();
6385
6386 for cluster in &mut self.prim_list.clusters {
6387 cluster.flags.remove(ClusterFlags::IS_VISIBLE);
6388
6389 if !cluster.flags.contains(ClusterFlags::IS_BACKFACE_VISIBLE) {
6391 if let Picture3DContext::In { ancestor_index, .. } = self.context_3d {
6394 let mut face = VisibleFace::Front;
6395 frame_context.spatial_tree.get_relative_transform_with_face(
6396 cluster.spatial_node_index,
6397 ancestor_index,
6398 Some(&mut face),
6399 );
6400 if face == VisibleFace::Back {
6401 continue
6402 }
6403 }
6404 }
6405
6406 let spatial_node = &frame_context
6408 .spatial_tree
6409 .spatial_nodes[cluster.spatial_node_index.0 as usize];
6410 if !spatial_node.invertible {
6411 continue;
6412 }
6413
6414 if cluster.flags.contains(ClusterFlags::IS_BACKDROP_FILTER) {
6417 let backdrop_to_world_mapper = SpaceMapper::new_with_target(
6418 ROOT_SPATIAL_NODE_INDEX,
6419 cluster.spatial_node_index,
6420 LayoutRect::max_rect(),
6421 frame_context.spatial_tree,
6422 );
6423
6424 for prim_instance in &mut self.prim_list.prim_instances[cluster.prim_range()] {
6425 match prim_instance.kind {
6426 PrimitiveInstanceKind::Backdrop { data_handle, .. } => {
6427 let prim_data = &mut data_stores.backdrop[data_handle];
6430 let spatial_node_index = prim_data.kind.spatial_node_index;
6431
6432 let prim_to_world_mapper = SpaceMapper::new_with_target(
6439 ROOT_SPATIAL_NODE_INDEX,
6440 spatial_node_index,
6441 LayoutRect::max_rect(),
6442 frame_context.spatial_tree,
6443 );
6444
6445 let prim_rect = prim_to_world_mapper
6447 .map(&prim_data.kind.border_rect)
6448 .unwrap_or_else(LayoutRect::zero);
6449 let prim_rect = backdrop_to_world_mapper
6451 .unmap(&prim_rect)
6452 .unwrap_or_else(LayoutRect::zero);
6453
6454 prim_data.common.prim_rect = prim_rect;
6458 prim_instance.clip_set.local_clip_rect = prim_rect;
6459
6460 cluster.bounding_rect = cluster.bounding_rect.union(&prim_rect);
6462 }
6463 _ => {
6464 panic!("BUG: unexpected deferred primitive kind for cluster updates");
6465 }
6466 }
6467 }
6468 }
6469
6470 surface.map_local_to_surface.set_target_spatial_node(
6473 cluster.spatial_node_index,
6474 frame_context.spatial_tree,
6475 );
6476
6477 cluster.flags.insert(ClusterFlags::IS_VISIBLE);
6480 if let Some(cluster_rect) = surface.map_local_to_surface.map(&cluster.bounding_rect) {
6481 surface.rect = surface.rect.union(&cluster_rect);
6482 }
6483 }
6484
6485 if let Some(ref mut raster_config) = self.raster_config {
6489 let surface = state.current_surface_mut();
6490 if self.options.inflate_if_required {
6492 surface.rect = raster_config.composite_mode.inflate_picture_rect(surface.rect, surface.scale_factors);
6493 }
6494
6495 let mut surface_rect = surface.rect * Scale::new(1.0);
6496
6497 let surface_index = state.pop_surface();
6499 debug_assert_eq!(surface_index, raster_config.surface_index);
6500
6501 self.estimated_local_rect = surface_rect;
6504 self.precise_local_rect = surface_rect;
6505
6506 match raster_config.composite_mode {
6509 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
6510 for shadow in shadows {
6511 let shadow_rect = self.estimated_local_rect.translate(shadow.offset);
6512 surface_rect = surface_rect.union(&shadow_rect);
6513 }
6514 }
6515 _ => {}
6516 }
6517
6518 let parent_surface = state.current_surface_mut();
6520 parent_surface.map_local_to_surface.set_target_spatial_node(
6521 self.spatial_node_index,
6522 frame_context.spatial_tree,
6523 );
6524 if let Some(parent_surface_rect) = parent_surface
6525 .map_local_to_surface
6526 .map(&surface_rect)
6527 {
6528 parent_surface.rect = parent_surface.rect.union(&parent_surface_rect);
6529 }
6530 }
6531 }
6532
6533 pub fn prepare_for_render(
6534 &mut self,
6535 frame_context: &FrameBuildingContext,
6536 frame_state: &mut FrameBuildingState,
6537 data_stores: &mut DataStores,
6538 ) -> bool {
6539 let mut pic_state_for_children = self.take_state();
6540
6541 if let Some(ref mut splitter) = pic_state_for_children.plane_splitter {
6542 self.resolve_split_planes(
6543 splitter,
6544 &mut frame_state.gpu_cache,
6545 &frame_context.spatial_tree,
6546 );
6547 }
6548
6549 let raster_config = match self.raster_config {
6550 Some(ref mut raster_config) => raster_config,
6551 None => {
6552 return true
6553 }
6554 };
6555
6556 match raster_config.composite_mode {
6564 PictureCompositeMode::TileCache { .. } => {}
6565 PictureCompositeMode::Filter(Filter::Blur(..)) => {}
6566 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
6567 self.extra_gpu_data_handles.resize(shadows.len(), GpuCacheHandle::new());
6568 for (shadow, extra_handle) in shadows.iter().zip(self.extra_gpu_data_handles.iter_mut()) {
6569 if let Some(mut request) = frame_state.gpu_cache.request(extra_handle) {
6570 let shadow_rect = self.precise_local_rect.translate(shadow.offset);
6574
6575 request.push(shadow.color.premultiplied());
6577 request.push(PremultipliedColorF::WHITE);
6578 request.push([
6579 self.precise_local_rect.width(),
6580 self.precise_local_rect.height(),
6581 0.0,
6582 0.0,
6583 ]);
6584
6585 request.push(shadow_rect);
6587 request.push([0.0, 0.0, 0.0, 0.0]);
6588 }
6589 }
6590 }
6591 PictureCompositeMode::Filter(ref filter) => {
6592 match *filter {
6593 Filter::ColorMatrix(ref m) => {
6594 if self.extra_gpu_data_handles.is_empty() {
6595 self.extra_gpu_data_handles.push(GpuCacheHandle::new());
6596 }
6597 if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handles[0]) {
6598 for i in 0..5 {
6599 request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
6600 }
6601 }
6602 }
6603 Filter::Flood(ref color) => {
6604 if self.extra_gpu_data_handles.is_empty() {
6605 self.extra_gpu_data_handles.push(GpuCacheHandle::new());
6606 }
6607 if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handles[0]) {
6608 request.push(color.to_array());
6609 }
6610 }
6611 _ => {}
6612 }
6613 }
6614 PictureCompositeMode::ComponentTransferFilter(handle) => {
6615 let filter_data = &mut data_stores.filter_data[handle];
6616 filter_data.update(frame_state);
6617 }
6618 PictureCompositeMode::MixBlend(..) |
6619 PictureCompositeMode::Blit(_) |
6620 PictureCompositeMode::SvgFilter(..) => {}
6621 }
6622
6623 true
6624 }
6625}
6626
6627fn calculate_screen_uv(
6629 local_pos: &PicturePoint,
6630 transform: &PictureToRasterTransform,
6631 rendered_rect: &DeviceRect,
6632 device_pixel_scale: DevicePixelScale,
6633) -> DeviceHomogeneousVector {
6634 let raster_pos = transform.transform_point2d_homogeneous(*local_pos);
6635
6636 DeviceHomogeneousVector::new(
6637 (raster_pos.x * device_pixel_scale.0 - rendered_rect.min.x * raster_pos.w) / rendered_rect.width(),
6638 (raster_pos.y * device_pixel_scale.0 - rendered_rect.min.y * raster_pos.w) / rendered_rect.height(),
6639 0.0,
6640 raster_pos.w,
6641 )
6642}
6643
6644fn calculate_uv_rect_kind(
6647 pic_rect: &PictureRect,
6648 transform: &PictureToRasterTransform,
6649 rendered_rect: &DeviceRect,
6650 device_pixel_scale: DevicePixelScale,
6651) -> UvRectKind {
6652 let top_left = calculate_screen_uv(
6653 &pic_rect.top_left(),
6654 transform,
6655 &rendered_rect,
6656 device_pixel_scale,
6657 );
6658
6659 let top_right = calculate_screen_uv(
6660 &pic_rect.top_right(),
6661 transform,
6662 &rendered_rect,
6663 device_pixel_scale,
6664 );
6665
6666 let bottom_left = calculate_screen_uv(
6667 &pic_rect.bottom_left(),
6668 transform,
6669 &rendered_rect,
6670 device_pixel_scale,
6671 );
6672
6673 let bottom_right = calculate_screen_uv(
6674 &pic_rect.bottom_right(),
6675 transform,
6676 &rendered_rect,
6677 device_pixel_scale,
6678 );
6679
6680 UvRectKind::Quad {
6681 top_left,
6682 top_right,
6683 bottom_left,
6684 bottom_right,
6685 }
6686}
6687
6688fn create_raster_mappers(
6689 surface_spatial_node_index: SpatialNodeIndex,
6690 raster_spatial_node_index: SpatialNodeIndex,
6691 world_rect: WorldRect,
6692 spatial_tree: &SpatialTree,
6693) -> (SpaceMapper<RasterPixel, WorldPixel>, SpaceMapper<PicturePixel, RasterPixel>) {
6694 let map_raster_to_world = SpaceMapper::new_with_target(
6695 ROOT_SPATIAL_NODE_INDEX,
6696 raster_spatial_node_index,
6697 world_rect,
6698 spatial_tree,
6699 );
6700
6701 let raster_bounds = map_raster_to_world
6702 .unmap(&world_rect)
6703 .unwrap_or_else(RasterRect::max_rect);
6704
6705 let map_pic_to_raster = SpaceMapper::new_with_target(
6706 raster_spatial_node_index,
6707 surface_spatial_node_index,
6708 raster_bounds,
6709 spatial_tree,
6710 );
6711
6712 (map_raster_to_world, map_pic_to_raster)
6713}
6714
6715fn get_transform_key(
6716 spatial_node_index: SpatialNodeIndex,
6717 cache_spatial_node_index: SpatialNodeIndex,
6718 spatial_tree: &SpatialTree,
6719) -> TransformKey {
6720 let transform = if cache_spatial_node_index >= spatial_node_index {
6723 spatial_tree
6724 .get_relative_transform(
6725 cache_spatial_node_index,
6726 spatial_node_index,
6727 )
6728 } else {
6729 spatial_tree
6730 .get_relative_transform(
6731 spatial_node_index,
6732 cache_spatial_node_index,
6733 )
6734 };
6735 transform.into()
6736}
6737
6738#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
6740struct PrimitiveComparisonKey {
6741 prev_index: PrimitiveDependencyIndex,
6742 curr_index: PrimitiveDependencyIndex,
6743}
6744
6745#[derive(Debug, Copy, Clone, PartialEq)]
6747#[cfg_attr(feature = "capture", derive(Serialize))]
6748#[cfg_attr(feature = "replay", derive(Deserialize))]
6749pub struct ImageDependency {
6750 pub key: ImageKey,
6751 pub generation: ImageGeneration,
6752}
6753
6754impl ImageDependency {
6755 pub const INVALID: ImageDependency = ImageDependency {
6756 key: ImageKey::DUMMY,
6757 generation: ImageGeneration::INVALID,
6758 };
6759}
6760
6761struct PrimitiveComparer<'a> {
6763 clip_comparer: CompareHelper<'a, ItemUid>,
6764 transform_comparer: CompareHelper<'a, SpatialNodeKey>,
6765 image_comparer: CompareHelper<'a, ImageDependency>,
6766 opacity_comparer: CompareHelper<'a, OpacityBinding>,
6767 color_comparer: CompareHelper<'a, ColorBinding>,
6768 resource_cache: &'a ResourceCache,
6769 spatial_node_comparer: &'a mut SpatialNodeComparer,
6770 opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
6771 color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
6772}
6773
6774impl<'a> PrimitiveComparer<'a> {
6775 fn new(
6776 prev: &'a TileDescriptor,
6777 curr: &'a TileDescriptor,
6778 resource_cache: &'a ResourceCache,
6779 spatial_node_comparer: &'a mut SpatialNodeComparer,
6780 opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
6781 color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
6782 ) -> Self {
6783 let clip_comparer = CompareHelper::new(
6784 &prev.clips,
6785 &curr.clips,
6786 );
6787
6788 let transform_comparer = CompareHelper::new(
6789 &prev.transforms,
6790 &curr.transforms,
6791 );
6792
6793 let image_comparer = CompareHelper::new(
6794 &prev.images,
6795 &curr.images,
6796 );
6797
6798 let opacity_comparer = CompareHelper::new(
6799 &prev.opacity_bindings,
6800 &curr.opacity_bindings,
6801 );
6802
6803 let color_comparer = CompareHelper::new(
6804 &prev.color_bindings,
6805 &curr.color_bindings,
6806 );
6807
6808 PrimitiveComparer {
6809 clip_comparer,
6810 transform_comparer,
6811 image_comparer,
6812 opacity_comparer,
6813 color_comparer,
6814 resource_cache,
6815 spatial_node_comparer,
6816 opacity_bindings,
6817 color_bindings,
6818 }
6819 }
6820
6821 fn reset(&mut self) {
6822 self.clip_comparer.reset();
6823 self.transform_comparer.reset();
6824 self.image_comparer.reset();
6825 self.opacity_comparer.reset();
6826 self.color_comparer.reset();
6827 }
6828
6829 fn advance_prev(&mut self, prim: &PrimitiveDescriptor) {
6830 self.clip_comparer.advance_prev(prim.clip_dep_count);
6831 self.transform_comparer.advance_prev(prim.transform_dep_count);
6832 self.image_comparer.advance_prev(prim.image_dep_count);
6833 self.opacity_comparer.advance_prev(prim.opacity_binding_dep_count);
6834 self.color_comparer.advance_prev(prim.color_binding_dep_count);
6835 }
6836
6837 fn advance_curr(&mut self, prim: &PrimitiveDescriptor) {
6838 self.clip_comparer.advance_curr(prim.clip_dep_count);
6839 self.transform_comparer.advance_curr(prim.transform_dep_count);
6840 self.image_comparer.advance_curr(prim.image_dep_count);
6841 self.opacity_comparer.advance_curr(prim.opacity_binding_dep_count);
6842 self.color_comparer.advance_curr(prim.color_binding_dep_count);
6843 }
6844
6845 fn compare_prim(
6847 &mut self,
6848 prev: &PrimitiveDescriptor,
6849 curr: &PrimitiveDescriptor,
6850 opt_detail: Option<&mut PrimitiveCompareResultDetail>,
6851 ) -> PrimitiveCompareResult {
6852 let resource_cache = self.resource_cache;
6853 let spatial_node_comparer = &mut self.spatial_node_comparer;
6854 let opacity_bindings = self.opacity_bindings;
6855 let color_bindings = self.color_bindings;
6856
6857 if prev != curr {
6859 if let Some(detail) = opt_detail {
6860 *detail = PrimitiveCompareResultDetail::Descriptor{ old: *prev, new: *curr };
6861 }
6862 return PrimitiveCompareResult::Descriptor;
6863 }
6864
6865 let mut clip_result = CompareHelperResult::Equal;
6867 if !self.clip_comparer.is_same(
6868 prev.clip_dep_count,
6869 curr.clip_dep_count,
6870 |prev, curr| {
6871 prev == curr
6872 },
6873 if opt_detail.is_some() { Some(&mut clip_result) } else { None }
6874 ) {
6875 if let Some(detail) = opt_detail { *detail = PrimitiveCompareResultDetail::Clip{ detail: clip_result }; }
6876 return PrimitiveCompareResult::Clip;
6877 }
6878
6879 let mut transform_result = CompareHelperResult::Equal;
6881 if !self.transform_comparer.is_same(
6882 prev.transform_dep_count,
6883 curr.transform_dep_count,
6884 |prev, curr| {
6885 spatial_node_comparer.are_transforms_equivalent(prev, curr)
6886 },
6887 if opt_detail.is_some() { Some(&mut transform_result) } else { None },
6888 ) {
6889 if let Some(detail) = opt_detail {
6890 *detail = PrimitiveCompareResultDetail::Transform{ detail: transform_result };
6891 }
6892 return PrimitiveCompareResult::Transform;
6893 }
6894
6895 let mut image_result = CompareHelperResult::Equal;
6897 if !self.image_comparer.is_same(
6898 prev.image_dep_count,
6899 curr.image_dep_count,
6900 |prev, curr| {
6901 prev == curr &&
6902 resource_cache.get_image_generation(curr.key) == curr.generation
6903 },
6904 if opt_detail.is_some() { Some(&mut image_result) } else { None },
6905 ) {
6906 if let Some(detail) = opt_detail {
6907 *detail = PrimitiveCompareResultDetail::Image{ detail: image_result };
6908 }
6909 return PrimitiveCompareResult::Image;
6910 }
6911
6912 let mut bind_result = CompareHelperResult::Equal;
6914 if !self.opacity_comparer.is_same(
6915 prev.opacity_binding_dep_count,
6916 curr.opacity_binding_dep_count,
6917 |prev, curr| {
6918 if prev != curr {
6919 return false;
6920 }
6921
6922 if let OpacityBinding::Binding(id) = curr {
6923 if opacity_bindings
6924 .get(id)
6925 .map_or(true, |info| info.changed) {
6926 return false;
6927 }
6928 }
6929
6930 true
6931 },
6932 if opt_detail.is_some() { Some(&mut bind_result) } else { None },
6933 ) {
6934 if let Some(detail) = opt_detail {
6935 *detail = PrimitiveCompareResultDetail::OpacityBinding{ detail: bind_result };
6936 }
6937 return PrimitiveCompareResult::OpacityBinding;
6938 }
6939
6940 let mut bind_result = CompareHelperResult::Equal;
6942 if !self.color_comparer.is_same(
6943 prev.color_binding_dep_count,
6944 curr.color_binding_dep_count,
6945 |prev, curr| {
6946 if prev != curr {
6947 return false;
6948 }
6949
6950 if let ColorBinding::Binding(id) = curr {
6951 if color_bindings
6952 .get(id)
6953 .map_or(true, |info| info.changed) {
6954 return false;
6955 }
6956 }
6957
6958 true
6959 },
6960 if opt_detail.is_some() { Some(&mut bind_result) } else { None },
6961 ) {
6962 if let Some(detail) = opt_detail {
6963 *detail = PrimitiveCompareResultDetail::ColorBinding{ detail: bind_result };
6964 }
6965 return PrimitiveCompareResult::ColorBinding;
6966 }
6967
6968 PrimitiveCompareResult::Equal
6969 }
6970}
6971
6972#[cfg_attr(any(feature="capture",feature="replay"), derive(Clone))]
6974#[cfg_attr(feature = "capture", derive(Serialize))]
6975#[cfg_attr(feature = "replay", derive(Deserialize))]
6976pub enum TileNodeKind {
6977 Leaf {
6978 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
6980 prev_indices: Vec<PrimitiveDependencyIndex>,
6981 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
6983 curr_indices: Vec<PrimitiveDependencyIndex>,
6984 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
6986 dirty_tracker: u64,
6987 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
6989 frames_since_modified: usize,
6990 },
6991 Node {
6992 children: Vec<TileNode>,
6994 },
6995}
6996
6997#[derive(Copy, Clone, PartialEq, Debug)]
6999enum TileModification {
7000 Split,
7001 Merge,
7002}
7003
7004#[cfg_attr(any(feature="capture",feature="replay"), derive(Clone))]
7006#[cfg_attr(feature = "capture", derive(Serialize))]
7007#[cfg_attr(feature = "replay", derive(Deserialize))]
7008pub struct TileNode {
7009 pub kind: TileNodeKind,
7011 pub rect: PictureBox2D,
7013}
7014
7015impl TileNode {
7016 fn new_leaf(curr_indices: Vec<PrimitiveDependencyIndex>) -> Self {
7018 TileNode {
7019 kind: TileNodeKind::Leaf {
7020 prev_indices: Vec::new(),
7021 curr_indices,
7022 dirty_tracker: 0,
7023 frames_since_modified: 0,
7024 },
7025 rect: PictureBox2D::zero(),
7026 }
7027 }
7028
7029 fn draw_debug_rects(
7031 &self,
7032 pic_to_world_mapper: &SpaceMapper<PicturePixel, WorldPixel>,
7033 is_opaque: bool,
7034 local_valid_rect: PictureRect,
7035 scratch: &mut PrimitiveScratchBuffer,
7036 global_device_pixel_scale: DevicePixelScale,
7037 ) {
7038 match self.kind {
7039 TileNodeKind::Leaf { dirty_tracker, .. } => {
7040 let color = if (dirty_tracker & 1) != 0 {
7041 debug_colors::RED
7042 } else if is_opaque {
7043 debug_colors::GREEN
7044 } else {
7045 debug_colors::YELLOW
7046 };
7047
7048 if let Some(local_rect) = local_valid_rect.intersection(&self.rect) {
7049 let world_rect = pic_to_world_mapper
7050 .map(&local_rect)
7051 .unwrap();
7052 let device_rect = world_rect * global_device_pixel_scale;
7053
7054 let outer_color = color.scale_alpha(0.3);
7055 let inner_color = outer_color.scale_alpha(0.5);
7056 scratch.push_debug_rect(
7057 device_rect.inflate(-3.0, -3.0),
7058 outer_color,
7059 inner_color
7060 );
7061 }
7062 }
7063 TileNodeKind::Node { ref children, .. } => {
7064 for child in children.iter() {
7065 child.draw_debug_rects(
7066 pic_to_world_mapper,
7067 is_opaque,
7068 local_valid_rect,
7069 scratch,
7070 global_device_pixel_scale,
7071 );
7072 }
7073 }
7074 }
7075 }
7076
7077 fn get_child_rects(
7079 rect: &PictureBox2D,
7080 result: &mut [PictureBox2D; 4],
7081 ) {
7082 let p0 = rect.min;
7083 let p1 = rect.max;
7084 let pc = p0 + rect.size() * 0.5;
7085
7086 *result = [
7087 PictureBox2D::new(
7088 p0,
7089 pc,
7090 ),
7091 PictureBox2D::new(
7092 PicturePoint::new(pc.x, p0.y),
7093 PicturePoint::new(p1.x, pc.y),
7094 ),
7095 PictureBox2D::new(
7096 PicturePoint::new(p0.x, pc.y),
7097 PicturePoint::new(pc.x, p1.y),
7098 ),
7099 PictureBox2D::new(
7100 pc,
7101 p1,
7102 ),
7103 ];
7104 }
7105
7106 fn clear(
7108 &mut self,
7109 rect: PictureBox2D,
7110 ) {
7111 self.rect = rect;
7112
7113 match self.kind {
7114 TileNodeKind::Leaf { ref mut prev_indices, ref mut curr_indices, ref mut dirty_tracker, ref mut frames_since_modified } => {
7115 mem::swap(prev_indices, curr_indices);
7117 curr_indices.clear();
7118 *dirty_tracker = *dirty_tracker << 1;
7120 *frames_since_modified += 1;
7121 }
7122 TileNodeKind::Node { ref mut children, .. } => {
7123 let mut child_rects = [PictureBox2D::zero(); 4];
7124 TileNode::get_child_rects(&rect, &mut child_rects);
7125 assert_eq!(child_rects.len(), children.len());
7126
7127 for (child, rect) in children.iter_mut().zip(child_rects.iter()) {
7128 child.clear(*rect);
7129 }
7130 }
7131 }
7132 }
7133
7134 fn add_prim(
7136 &mut self,
7137 index: PrimitiveDependencyIndex,
7138 prim_rect: &PictureBox2D,
7139 ) {
7140 match self.kind {
7141 TileNodeKind::Leaf { ref mut curr_indices, .. } => {
7142 curr_indices.push(index);
7143 }
7144 TileNodeKind::Node { ref mut children, .. } => {
7145 for child in children.iter_mut() {
7146 if child.rect.intersects(prim_rect) {
7147 child.add_prim(index, prim_rect);
7148 }
7149 }
7150 }
7151 }
7152 }
7153
7154 fn maybe_merge_or_split(
7156 &mut self,
7157 level: i32,
7158 curr_prims: &[PrimitiveDescriptor],
7159 max_split_levels: i32,
7160 ) {
7161 let mut tile_mod = None;
7163
7164 fn get_dirty_frames(
7165 dirty_tracker: u64,
7166 frames_since_modified: usize,
7167 ) -> Option<u32> {
7168 if frames_since_modified > 64 {
7170 Some(dirty_tracker.count_ones())
7172 } else {
7173 None
7174 }
7175 }
7176
7177 match self.kind {
7178 TileNodeKind::Leaf { dirty_tracker, frames_since_modified, .. } => {
7179 if level < max_split_levels {
7181 if let Some(dirty_frames) = get_dirty_frames(dirty_tracker, frames_since_modified) {
7182 if dirty_frames > 32 {
7184 tile_mod = Some(TileModification::Split);
7185 }
7186 }
7187 }
7188 }
7189 TileNodeKind::Node { ref children, .. } => {
7190 let mut static_count = 0;
7197 let mut changing_count = 0;
7198
7199 for child in children {
7200 if let TileNodeKind::Leaf { dirty_tracker, frames_since_modified, .. } = child.kind {
7202 if let Some(dirty_frames) = get_dirty_frames(dirty_tracker, frames_since_modified) {
7203 if dirty_frames == 0 {
7204 static_count += 1;
7206 } else if dirty_frames == 64 {
7207 changing_count += 1;
7209 }
7210 }
7211 }
7212
7213 if static_count == 4 || changing_count == 4 {
7217 tile_mod = Some(TileModification::Merge);
7218 }
7219 }
7220 }
7221 }
7222
7223 match tile_mod {
7224 Some(TileModification::Split) => {
7225 let curr_indices = match self.kind {
7228 TileNodeKind::Node { .. } => {
7229 unreachable!("bug - only leaves can split");
7230 }
7231 TileNodeKind::Leaf { ref mut curr_indices, .. } => {
7232 curr_indices.take()
7233 }
7234 };
7235
7236 let mut child_rects = [PictureBox2D::zero(); 4];
7237 TileNode::get_child_rects(&self.rect, &mut child_rects);
7238
7239 let mut child_indices = [
7240 Vec::new(),
7241 Vec::new(),
7242 Vec::new(),
7243 Vec::new(),
7244 ];
7245
7246 for index in curr_indices {
7249 let prim = &curr_prims[index.0 as usize];
7250 for (child_rect, indices) in child_rects.iter().zip(child_indices.iter_mut()) {
7251 if prim.prim_clip_box.intersects(child_rect) {
7252 indices.push(index);
7253 }
7254 }
7255 }
7256
7257 let children = child_indices
7259 .iter_mut()
7260 .map(|i| TileNode::new_leaf(mem::replace(i, Vec::new())))
7261 .collect();
7262
7263 self.kind = TileNodeKind::Node {
7264 children,
7265 };
7266 }
7267 Some(TileModification::Merge) => {
7268 let merged_indices = match self.kind {
7271 TileNodeKind::Node { ref mut children, .. } => {
7272 let mut merged_indices = Vec::new();
7273
7274 for child in children.iter() {
7275 let child_indices = match child.kind {
7276 TileNodeKind::Leaf { ref curr_indices, .. } => {
7277 curr_indices
7278 }
7279 TileNodeKind::Node { .. } => {
7280 unreachable!("bug: child is not a leaf");
7281 }
7282 };
7283 merged_indices.extend_from_slice(child_indices);
7284 }
7285
7286 merged_indices.sort();
7287 merged_indices.dedup();
7288
7289 merged_indices
7290 }
7291 TileNodeKind::Leaf { .. } => {
7292 unreachable!("bug - trying to merge a leaf");
7293 }
7294 };
7295
7296 self.kind = TileNodeKind::Leaf {
7298 prev_indices: Vec::new(),
7299 curr_indices: merged_indices,
7300 dirty_tracker: 0,
7301 frames_since_modified: 0,
7302 };
7303 }
7304 None => {
7305 if let TileNodeKind::Node { ref mut children, .. } = self.kind {
7308 for child in children.iter_mut() {
7309 child.maybe_merge_or_split(
7310 level+1,
7311 curr_prims,
7312 max_split_levels,
7313 );
7314 }
7315 }
7316 }
7317 }
7318 }
7319
7320 fn update_dirty_rects(
7322 &mut self,
7323 prev_prims: &[PrimitiveDescriptor],
7324 curr_prims: &[PrimitiveDescriptor],
7325 prim_comparer: &mut PrimitiveComparer,
7326 dirty_rect: &mut PictureBox2D,
7327 compare_cache: &mut FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
7328 invalidation_reason: &mut Option<InvalidationReason>,
7329 frame_context: &FrameVisibilityContext,
7330 ) {
7331 match self.kind {
7332 TileNodeKind::Node { ref mut children, .. } => {
7333 for child in children.iter_mut() {
7334 child.update_dirty_rects(
7335 prev_prims,
7336 curr_prims,
7337 prim_comparer,
7338 dirty_rect,
7339 compare_cache,
7340 invalidation_reason,
7341 frame_context,
7342 );
7343 }
7344 }
7345 TileNodeKind::Leaf { ref prev_indices, ref curr_indices, ref mut dirty_tracker, .. } => {
7346 if prev_indices.len() == curr_indices.len() {
7348 let mut prev_i0 = 0;
7349 let mut prev_i1 = 0;
7350 prim_comparer.reset();
7351
7352 for (prev_index, curr_index) in prev_indices.iter().zip(curr_indices.iter()) {
7354 let i0 = prev_index.0 as usize;
7355 let i1 = curr_index.0 as usize;
7356
7357 for i in prev_i0 .. i0 {
7360 prim_comparer.advance_prev(&prev_prims[i]);
7361 }
7362 for i in prev_i1 .. i1 {
7363 prim_comparer.advance_curr(&curr_prims[i]);
7364 }
7365
7366 let key = PrimitiveComparisonKey {
7369 prev_index: *prev_index,
7370 curr_index: *curr_index,
7371 };
7372
7373 #[cfg(any(feature = "capture", feature = "replay"))]
7374 let mut compare_detail = PrimitiveCompareResultDetail::Equal;
7375 #[cfg(any(feature = "capture", feature = "replay"))]
7376 let prim_compare_result_detail =
7377 if frame_context.debug_flags.contains(DebugFlags::TILE_CACHE_LOGGING_DBG) {
7378 Some(&mut compare_detail)
7379 } else {
7380 None
7381 };
7382
7383 #[cfg(not(any(feature = "capture", feature = "replay")))]
7384 let compare_detail = PrimitiveCompareResultDetail::Equal;
7385 #[cfg(not(any(feature = "capture", feature = "replay")))]
7386 let prim_compare_result_detail = None;
7387
7388 let prim_compare_result = *compare_cache
7389 .entry(key)
7390 .or_insert_with(|| {
7391 let prev = &prev_prims[i0];
7392 let curr = &curr_prims[i1];
7393 prim_comparer.compare_prim(prev, curr, prim_compare_result_detail)
7394 });
7395
7396 if prim_compare_result != PrimitiveCompareResult::Equal {
7398 if invalidation_reason.is_none() {
7399 *invalidation_reason = Some(InvalidationReason::Content {
7400 prim_compare_result,
7401 prim_compare_result_detail: Some(compare_detail)
7402 });
7403 }
7404 *dirty_rect = self.rect.union(dirty_rect);
7405 *dirty_tracker = *dirty_tracker | 1;
7406 break;
7407 }
7408
7409 prev_i0 = i0;
7410 prev_i1 = i1;
7411 }
7412 } else {
7413 if invalidation_reason.is_none() {
7414 #[cfg(any(feature = "capture", feature = "replay"))]
7418 {
7419 if frame_context.debug_flags.contains(DebugFlags::TILE_CACHE_LOGGING_DBG) {
7420 let old = prev_indices.iter().map( |i| prev_prims[i.0 as usize].prim_uid ).collect();
7421 let new = curr_indices.iter().map( |i| curr_prims[i.0 as usize].prim_uid ).collect();
7422 *invalidation_reason = Some(InvalidationReason::PrimCount {
7423 old: Some(old),
7424 new: Some(new) });
7425 } else {
7426 *invalidation_reason = Some(InvalidationReason::PrimCount {
7427 old: None,
7428 new: None });
7429 }
7430 }
7431 #[cfg(not(any(feature = "capture", feature = "replay")))]
7432 {
7433 *invalidation_reason = Some(InvalidationReason::PrimCount {
7434 old: None,
7435 new: None });
7436 }
7437 }
7438 *dirty_rect = self.rect.union(dirty_rect);
7439 *dirty_tracker = *dirty_tracker | 1;
7440 }
7441 }
7442 }
7443 }
7444}
7445
7446impl CompositeState {
7447 pub fn destroy_native_tiles<'a, I: Iterator<Item = &'a mut Box<Tile>>>(
7449 &mut self,
7450 tiles_iter: I,
7451 resource_cache: &mut ResourceCache,
7452 ) {
7453 if let CompositorKind::Native { .. } = self.compositor_kind {
7458 for tile in tiles_iter {
7459 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
7463 if let Some(id) = id.take() {
7464 resource_cache.destroy_compositor_tile(id);
7465 }
7466 }
7467 }
7468 }
7469 }
7470}
7471
7472pub fn get_raster_rects(
7473 pic_rect: PictureRect,
7474 map_to_raster: &SpaceMapper<PicturePixel, RasterPixel>,
7475 map_to_world: &SpaceMapper<RasterPixel, WorldPixel>,
7476 prim_bounding_rect: WorldRect,
7477 device_pixel_scale: DevicePixelScale,
7478) -> Option<(DeviceRect, DeviceRect)> {
7479 let unclipped_raster_rect = map_to_raster.map(&pic_rect)?;
7480
7481 let unclipped = raster_rect_to_device_pixels(
7482 unclipped_raster_rect,
7483 device_pixel_scale,
7484 );
7485
7486 let unclipped_world_rect = map_to_world.map(&unclipped_raster_rect)?;
7487 let clipped_world_rect = unclipped_world_rect.intersection(&prim_bounding_rect)?;
7488
7489 let clipped_raster_rect = match map_to_world.unmap(&clipped_world_rect) {
7492 Some(rect) => rect.intersection(&unclipped_raster_rect)?,
7493 None => return Some((unclipped, unclipped)),
7494 };
7495
7496 let clipped = raster_rect_to_device_pixels(
7497 clipped_raster_rect,
7498 device_pixel_scale,
7499 );
7500
7501 if clipped.is_empty() {
7503 return None;
7504 }
7505
7506 Some((clipped, unclipped))
7507}
7508
7509fn get_relative_scale_offset(
7510 child_spatial_node_index: SpatialNodeIndex,
7511 parent_spatial_node_index: SpatialNodeIndex,
7512 spatial_tree: &SpatialTree,
7513) -> ScaleOffset {
7514 let transform = spatial_tree.get_relative_transform(
7515 child_spatial_node_index,
7516 parent_spatial_node_index,
7517 );
7518 let mut scale_offset = match transform {
7519 CoordinateSpaceMapping::Local => ScaleOffset::identity(),
7520 CoordinateSpaceMapping::ScaleOffset(scale_offset) => scale_offset,
7521 CoordinateSpaceMapping::Transform(m) => {
7522 ScaleOffset::from_transform(&m).expect("bug: pictures caches don't support complex transforms")
7523 }
7524 };
7525
7526 scale_offset.offset = scale_offset.offset.round();
7530
7531 scale_offset
7532}