1use api::{BorderRadius, ClipMode, FilterPrimitiveKind, MixBlendMode, PremultipliedColorF, SVGFE_GRAPH_MAX};
98use api::{PropertyBinding, PropertyBindingId, FilterPrimitive, FilterOpGraphPictureBufferId, RasterSpace};
99use api::{DebugFlags, ImageKey, ColorF, ColorU, PrimitiveFlags, SnapshotInfo};
100use api::{ImageRendering, ColorDepth, YuvRangedColorSpace, YuvFormat, AlphaType};
101use api::units::*;
102use crate::prim_store::image::AdjustedImageSource;
103use crate::{command_buffer::PrimitiveCommand, render_task_graph::RenderTaskGraphBuilder, renderer::GpuBufferBuilderF};
104use crate::box_shadow::BLUR_SAMPLE_SCALE;
105use crate::clip::{ClipChainInstance, ClipItemKind, ClipLeafId, ClipNodeId, ClipSpaceConversion, ClipStore, ClipTreeBuilder};
106use crate::profiler::{self, TransactionProfile};
107use crate::spatial_tree::{SpatialTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace};
108use crate::composite::{tile_kind, CompositeState, CompositeTileSurface, CompositorClipIndex, CompositorKind, NativeSurfaceId, NativeTileId};
109use crate::composite::{ExternalSurfaceDescriptor, ExternalSurfaceDependency, CompositeTileDescriptor, CompositeTile};
110use crate::composite::{CompositorTransformIndex, CompositorSurfaceKind};
111use crate::debug_colors;
112use euclid::{vec3, Point2D, Scale, Vector2D, Box2D};
113use euclid::approxeq::ApproxEq;
114use crate::filterdata::SFilterData;
115use crate::intern::ItemUid;
116use crate::internal_types::{FastHashMap, FastHashSet, PlaneSplitter, FilterGraphOp, FilterGraphNode, Filter, FrameId};
117use crate::internal_types::{PlaneSplitterIndex, PlaneSplitAnchor, TextureSource};
118use crate::frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState, PictureContext};
119use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
120use crate::gpu_types::{UvRectKind, ZBufferId};
121use peek_poke::{PeekPoke, poke_into_vec, peek_from_slice, ensure_red_zone};
122use plane_split::{Clipper, Polygon};
123use crate::prim_store::{PrimitiveTemplateKind, PictureIndex, PrimitiveInstance, PrimitiveInstanceKind};
124use crate::prim_store::{ColorBindingStorage, ColorBindingIndex, PrimitiveScratchBuffer};
125use crate::print_tree::{PrintTree, PrintTreePrinter};
126use crate::render_backend::DataStores;
127use crate::render_task_graph::RenderTaskId;
128use crate::render_target::RenderTargetKind;
129use crate::render_task::{BlurTask, RenderTask, RenderTaskLocation, BlurTaskCache};
130use crate::render_task::{StaticRenderTaskSurface, RenderTaskKind};
131use crate::renderer::BlendMode;
132use crate::resource_cache::{ResourceCache, ImageGeneration, ImageRequest};
133use crate::space::SpaceMapper;
134use crate::scene::SceneProperties;
135use crate::spatial_tree::CoordinateSystemId;
136use crate::surface::{SurfaceDescriptor, SurfaceTileDescriptor};
137use smallvec::SmallVec;
138use std::{mem, u8, marker, u32};
139use std::fmt::{Display, Error, Formatter};
140use std::sync::atomic::{AtomicUsize, Ordering};
141use std::collections::hash_map::Entry;
142use std::ops::Range;
143use crate::picture_textures::PictureCacheTextureHandle;
144use crate::util::{MaxRect, VecHelper, MatrixHelpers, Recycler, ScaleOffset};
145use crate::filterdata::FilterDataHandle;
146use crate::tile_cache::{SliceDebugInfo, TileDebugInfo, DirtyTileDebugInfo};
147use crate::visibility::{PrimitiveVisibilityFlags, FrameVisibilityContext};
148use crate::visibility::{VisibilityState, FrameVisibilityState};
149use crate::scene_building::SliceFlags;
150use core::time::Duration;
151
152const MAX_BLUR_RADIUS: f32 = 100.;
155
156#[derive(Debug, Copy, Clone)]
158pub enum SubpixelMode {
159 Allow,
161 Deny,
163 Conditional {
166 allowed_rect: PictureRect,
167 prohibited_rect: PictureRect,
168 },
169}
170
171#[derive(Debug, Clone)]
173struct MatrixKey {
174 m: [f32; 16],
175}
176
177impl PartialEq for MatrixKey {
178 fn eq(&self, other: &Self) -> bool {
179 const EPSILON: f32 = 0.001;
180
181 for (i, j) in self.m.iter().zip(other.m.iter()) {
185 if !i.approx_eq_eps(j, &EPSILON) {
186 return false;
187 }
188 }
189
190 true
191 }
192}
193
194#[derive(Debug, Clone)]
196struct ScaleOffsetKey {
197 sx: f32,
198 sy: f32,
199 tx: f32,
200 ty: f32,
201}
202
203impl PartialEq for ScaleOffsetKey {
204 fn eq(&self, other: &Self) -> bool {
205 const EPSILON: f32 = 0.001;
206
207 self.sx.approx_eq_eps(&other.sx, &EPSILON) &&
208 self.sy.approx_eq_eps(&other.sy, &EPSILON) &&
209 self.tx.approx_eq_eps(&other.tx, &EPSILON) &&
210 self.ty.approx_eq_eps(&other.ty, &EPSILON)
211 }
212}
213
214#[derive(Debug, PartialEq, Clone)]
217enum TransformKey {
218 Local,
219 ScaleOffset {
220 so: ScaleOffsetKey,
221 },
222 Transform {
223 m: MatrixKey,
224 }
225}
226
227impl<Src, Dst> From<CoordinateSpaceMapping<Src, Dst>> for TransformKey {
228 fn from(transform: CoordinateSpaceMapping<Src, Dst>) -> TransformKey {
229 match transform {
230 CoordinateSpaceMapping::Local => {
231 TransformKey::Local
232 }
233 CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
234 TransformKey::ScaleOffset {
235 so: ScaleOffsetKey {
236 sx: scale_offset.scale.x,
237 sy: scale_offset.scale.y,
238 tx: scale_offset.offset.x,
239 ty: scale_offset.offset.y,
240 }
241 }
242 }
243 CoordinateSpaceMapping::Transform(ref m) => {
244 TransformKey::Transform {
245 m: MatrixKey {
246 m: m.to_array(),
247 },
248 }
249 }
250 }
251 }
252}
253
254#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
256pub struct TileCoordinate;
257
258pub type TileOffset = Point2D<i32, TileCoordinate>;
260pub type TileRect = Box2D<i32, TileCoordinate>;
261
262pub const MAX_COMPOSITOR_SURFACES: usize = 4;
266
267pub const TILE_SIZE_DEFAULT: DeviceIntSize = DeviceIntSize {
269 width: 1024,
270 height: 512,
271 _unit: marker::PhantomData,
272};
273
274pub const TILE_SIZE_SCROLLBAR_HORIZONTAL: DeviceIntSize = DeviceIntSize {
276 width: 1024,
277 height: 32,
278 _unit: marker::PhantomData,
279};
280
281pub const TILE_SIZE_SCROLLBAR_VERTICAL: DeviceIntSize = DeviceIntSize {
283 width: 32,
284 height: 1024,
285 _unit: marker::PhantomData,
286};
287
288pub const MAX_SURFACE_SIZE: usize = 4096;
292const MAX_COMPOSITOR_SURFACES_SIZE: f32 = 8192.0;
294
295static NEXT_TILE_ID: AtomicUsize = AtomicUsize::new(0);
298
299fn clamp(value: i32, low: i32, high: i32) -> i32 {
300 value.max(low).min(high)
301}
302
303fn clampf(value: f32, low: f32, high: f32) -> f32 {
304 value.max(low).min(high)
305}
306
307#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
309#[cfg_attr(feature = "capture", derive(Serialize))]
310#[cfg_attr(feature = "replay", derive(Deserialize))]
311pub struct PrimitiveDependencyIndex(pub u32);
312
313#[derive(Debug)]
315pub struct BindingInfo<T> {
316 value: T,
318 changed: bool,
320}
321
322#[derive(Debug, PartialEq, Clone, Copy, PeekPoke)]
324#[cfg_attr(feature = "capture", derive(Serialize))]
325#[cfg_attr(feature = "replay", derive(Deserialize))]
326pub enum Binding<T> {
327 Value(T),
328 Binding(PropertyBindingId),
329}
330
331impl<T: Default> Default for Binding<T> {
332 fn default() -> Self {
333 Binding::Value(T::default())
334 }
335}
336
337impl<T> From<PropertyBinding<T>> for Binding<T> {
338 fn from(binding: PropertyBinding<T>) -> Binding<T> {
339 match binding {
340 PropertyBinding::Binding(key, _) => Binding::Binding(key.id),
341 PropertyBinding::Value(value) => Binding::Value(value),
342 }
343 }
344}
345
346pub type OpacityBinding = Binding<f32>;
347pub type OpacityBindingInfo = BindingInfo<f32>;
348
349pub type ColorBinding = Binding<ColorU>;
350pub type ColorBindingInfo = BindingInfo<ColorU>;
351
352#[derive(PeekPoke)]
353enum PrimitiveDependency {
354 OpacityBinding {
355 binding: OpacityBinding,
356 },
357 ColorBinding {
358 binding: ColorBinding,
359 },
360 SpatialNode {
361 index: SpatialNodeIndex,
362 },
363 Clip {
364 clip: ItemUid,
365 },
366 Image {
367 image: ImageDependency,
368 },
369}
370
371#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PeekPoke, Default)]
373#[cfg_attr(feature = "capture", derive(Serialize))]
374#[cfg_attr(feature = "replay", derive(Deserialize))]
375pub struct SpatialNodeKey {
376 spatial_node_index: SpatialNodeIndex,
377 frame_id: FrameId,
378}
379
380struct SpatialNodeComparer {
385 ref_spatial_node_index: SpatialNodeIndex,
387 spatial_nodes: FastHashMap<SpatialNodeKey, TransformKey>,
389 compare_cache: FastHashMap<(SpatialNodeKey, SpatialNodeKey), bool>,
391 referenced_frames: FastHashSet<FrameId>,
393}
394
395impl SpatialNodeComparer {
396 fn new() -> Self {
398 SpatialNodeComparer {
399 ref_spatial_node_index: SpatialNodeIndex::INVALID,
400 spatial_nodes: FastHashMap::default(),
401 compare_cache: FastHashMap::default(),
402 referenced_frames: FastHashSet::default(),
403 }
404 }
405
406 fn next_frame(
408 &mut self,
409 ref_spatial_node_index: SpatialNodeIndex,
410 ) {
411 let referenced_frames = &self.referenced_frames;
414 self.spatial_nodes.retain(|key, _| {
415 referenced_frames.contains(&key.frame_id)
416 });
417
418 self.ref_spatial_node_index = ref_spatial_node_index;
420 self.compare_cache.clear();
421 self.referenced_frames.clear();
422 }
423
424 fn register_used_transform(
426 &mut self,
427 spatial_node_index: SpatialNodeIndex,
428 frame_id: FrameId,
429 spatial_tree: &SpatialTree,
430 ) {
431 let key = SpatialNodeKey {
432 spatial_node_index,
433 frame_id,
434 };
435
436 if let Entry::Vacant(entry) = self.spatial_nodes.entry(key) {
437 entry.insert(
438 get_transform_key(
439 spatial_node_index,
440 self.ref_spatial_node_index,
441 spatial_tree,
442 )
443 );
444 }
445 }
446
447 fn are_transforms_equivalent(
449 &mut self,
450 prev_spatial_node_key: &SpatialNodeKey,
451 curr_spatial_node_key: &SpatialNodeKey,
452 ) -> bool {
453 let key = (*prev_spatial_node_key, *curr_spatial_node_key);
454 let spatial_nodes = &self.spatial_nodes;
455
456 *self.compare_cache
457 .entry(key)
458 .or_insert_with(|| {
459 let prev = &spatial_nodes[&prev_spatial_node_key];
460 let curr = &spatial_nodes[&curr_spatial_node_key];
461 curr == prev
462 })
463 }
464
465 fn retain_for_frame(&mut self, frame_id: FrameId) {
467 self.referenced_frames.insert(frame_id);
468 }
469}
470
471struct TilePreUpdateContext {
473 pic_to_world_mapper: SpaceMapper<PicturePixel, WorldPixel>,
475
476 background_color: Option<ColorF>,
478
479 global_screen_world_rect: WorldRect,
481
482 tile_size: PictureSize,
484
485 frame_id: FrameId,
487}
488
489struct TileUpdateDirtyContext<'a> {
491 pic_to_world_mapper: SpaceMapper<PicturePixel, WorldPixel>,
493
494 global_device_pixel_scale: DevicePixelScale,
496
497 opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
499
500 color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
502
503 local_rect: PictureRect,
505
506 invalidate_all: bool,
509}
510
511struct TileUpdateDirtyState<'a> {
513 resource_cache: &'a mut ResourceCache,
515
516 composite_state: &'a mut CompositeState,
518
519 compare_cache: &'a mut FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
521
522 spatial_node_comparer: &'a mut SpatialNodeComparer,
524}
525
526struct TilePostUpdateContext<'a> {
528 local_clip_rect: PictureRect,
530
531 backdrop: Option<BackdropInfo>,
533
534 current_tile_size: DeviceIntSize,
536
537 z_id: ZBufferId,
539
540 underlays: &'a [ExternalSurfaceDescriptor],
542}
543
544struct TilePostUpdateState<'a> {
546 resource_cache: &'a mut ResourceCache,
548
549 composite_state: &'a mut CompositeState,
551}
552
553struct PrimitiveDependencyInfo {
555 prim_uid: ItemUid,
557
558 prim_clip_box: PictureBox2D,
560
561 images: SmallVec<[ImageDependency; 8]>,
563
564 opacity_bindings: SmallVec<[OpacityBinding; 4]>,
566
567 color_binding: Option<ColorBinding>,
569
570 clips: SmallVec<[ItemUid; 8]>,
572
573 spatial_nodes: SmallVec<[SpatialNodeIndex; 4]>,
575}
576
577impl PrimitiveDependencyInfo {
578 fn new(
580 prim_uid: ItemUid,
581 prim_clip_box: PictureBox2D,
582 ) -> Self {
583 PrimitiveDependencyInfo {
584 prim_uid,
585 images: SmallVec::new(),
586 opacity_bindings: SmallVec::new(),
587 color_binding: None,
588 prim_clip_box,
589 clips: SmallVec::new(),
590 spatial_nodes: SmallVec::new(),
591 }
592 }
593}
594
595#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
598#[cfg_attr(feature = "capture", derive(Serialize))]
599#[cfg_attr(feature = "replay", derive(Deserialize))]
600pub struct TileId(pub usize);
601
602#[cfg_attr(feature = "capture", derive(Serialize))]
604#[cfg_attr(feature = "replay", derive(Deserialize))]
605#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)]
606pub struct TileKey {
607 pub tile_offset: TileOffset,
609 pub sub_slice_index: SubSliceIndex,
611}
612
613#[derive(Debug)]
616pub enum SurfaceTextureDescriptor {
617 TextureCache {
620 handle: Option<PictureCacheTextureHandle>,
621 },
622 Native {
625 id: Option<NativeTileId>,
627 },
628}
629
630#[derive(Clone, Debug, Eq, PartialEq, Hash)]
634#[cfg_attr(feature = "capture", derive(Serialize))]
635#[cfg_attr(feature = "replay", derive(Deserialize))]
636pub enum ResolvedSurfaceTexture {
637 TextureCache {
638 texture: TextureSource,
640 },
641 Native {
642 id: NativeTileId,
644 size: DeviceIntSize,
646 }
647}
648
649impl SurfaceTextureDescriptor {
650 pub fn resolve(
652 &self,
653 resource_cache: &ResourceCache,
654 size: DeviceIntSize,
655 ) -> ResolvedSurfaceTexture {
656 match self {
657 SurfaceTextureDescriptor::TextureCache { handle } => {
658 let texture = resource_cache
659 .picture_textures
660 .get_texture_source(handle.as_ref().unwrap());
661
662 ResolvedSurfaceTexture::TextureCache { texture }
663 }
664 SurfaceTextureDescriptor::Native { id } => {
665 ResolvedSurfaceTexture::Native {
666 id: id.expect("bug: native surface not allocated"),
667 size,
668 }
669 }
670 }
671 }
672}
673
674#[derive(Debug)]
676pub enum TileSurface {
677 Texture {
678 descriptor: SurfaceTextureDescriptor,
680 },
681 Color {
682 color: ColorF,
683 },
684 Clear,
685}
686
687impl TileSurface {
688 fn kind(&self) -> &'static str {
689 match *self {
690 TileSurface::Color { .. } => "Color",
691 TileSurface::Texture { .. } => "Texture",
692 TileSurface::Clear => "Clear",
693 }
694 }
695}
696
697#[derive(Debug, Copy, Clone, PartialEq)]
700#[cfg_attr(feature = "capture", derive(Serialize))]
701#[cfg_attr(feature = "replay", derive(Deserialize))]
702pub enum CompareHelperResult<T> {
703 Equal,
705 Count {
707 prev_count: u8,
708 curr_count: u8,
709 },
710 Sentinel,
712 NotEqual {
714 prev: T,
715 curr: T,
716 },
717 PredicateTrue {
719 curr: T
720 },
721}
722
723#[derive(Debug, Copy, Clone, PartialEq)]
727#[cfg_attr(feature = "capture", derive(Serialize))]
728#[cfg_attr(feature = "replay", derive(Deserialize))]
729#[repr(u8)]
730pub enum PrimitiveCompareResult {
731 Equal,
733 Descriptor,
735 Clip,
737 Transform,
739 Image,
741 OpacityBinding,
743 ColorBinding,
745}
746
747#[derive(Debug,Clone)]
749#[cfg_attr(feature = "capture", derive(Serialize))]
750#[cfg_attr(feature = "replay", derive(Deserialize))]
751pub enum InvalidationReason {
752 BackgroundColor,
754 SurfaceOpacityChanged,
756 NoTexture,
758 NoSurface,
760 PrimCount,
762 Content,
764 CompositorKindChanged,
766 ValidRectChanged,
768 ScaleChanged,
770 SurfaceContentChanged,
772}
773
774pub struct Tile {
776 pub tile_offset: TileOffset,
778 pub world_tile_rect: WorldRect,
780 pub local_tile_rect: PictureRect,
782 pub local_dirty_rect: PictureRect,
784 pub device_dirty_rect: DeviceRect,
788 pub world_valid_rect: WorldRect,
790 pub device_valid_rect: DeviceRect,
792 pub current_descriptor: TileDescriptor,
795 pub prev_descriptor: TileDescriptor,
797 pub surface: Option<TileSurface>,
799 pub is_valid: bool,
803 pub is_visible: bool,
806 pub id: TileId,
809 pub is_opaque: bool,
812 root: TileNode,
814 background_color: Option<ColorF>,
816 invalidation_reason: Option<InvalidationReason>,
818 pub local_valid_rect: PictureBox2D,
820 pub z_id: ZBufferId,
822 pub sub_graphs: Vec<(PictureRect, Vec<(PictureCompositeMode, SurfaceIndex)>)>,
823}
824
825impl Tile {
826 fn new(tile_offset: TileOffset) -> Self {
828 let id = TileId(NEXT_TILE_ID.fetch_add(1, Ordering::Relaxed));
829
830 Tile {
831 tile_offset,
832 local_tile_rect: PictureRect::zero(),
833 world_tile_rect: WorldRect::zero(),
834 world_valid_rect: WorldRect::zero(),
835 device_valid_rect: DeviceRect::zero(),
836 local_dirty_rect: PictureRect::zero(),
837 device_dirty_rect: DeviceRect::zero(),
838 surface: None,
839 current_descriptor: TileDescriptor::new(),
840 prev_descriptor: TileDescriptor::new(),
841 is_valid: false,
842 is_visible: false,
843 id,
844 is_opaque: false,
845 root: TileNode::new_leaf(Vec::new()),
846 background_color: None,
847 invalidation_reason: None,
848 local_valid_rect: PictureBox2D::zero(),
849 z_id: ZBufferId::invalid(),
850 sub_graphs: Vec::new(),
851 }
852 }
853
854 fn print(&self, pt: &mut dyn PrintTreePrinter) {
856 pt.new_level(format!("Tile {:?}", self.id));
857 pt.add_item(format!("local_tile_rect: {:?}", self.local_tile_rect));
858 pt.add_item(format!("background_color: {:?}", self.background_color));
859 pt.add_item(format!("invalidation_reason: {:?}", self.invalidation_reason));
860 self.current_descriptor.print(pt);
861 pt.end_level();
862 }
863
864 fn update_dirty_rects(
866 &mut self,
867 ctx: &TileUpdateDirtyContext,
868 state: &mut TileUpdateDirtyState,
869 invalidation_reason: &mut Option<InvalidationReason>,
870 frame_context: &FrameVisibilityContext,
871 ) -> PictureRect {
872 let mut prim_comparer = PrimitiveComparer::new(
873 &self.prev_descriptor,
874 &self.current_descriptor,
875 state.resource_cache,
876 state.spatial_node_comparer,
877 ctx.opacity_bindings,
878 ctx.color_bindings,
879 );
880
881 let mut dirty_rect = PictureBox2D::zero();
882 self.root.update_dirty_rects(
883 &self.prev_descriptor.prims,
884 &self.current_descriptor.prims,
885 &mut prim_comparer,
886 &mut dirty_rect,
887 state.compare_cache,
888 invalidation_reason,
889 frame_context,
890 );
891
892 dirty_rect
893 }
894
895 fn update_content_validity(
900 &mut self,
901 ctx: &TileUpdateDirtyContext,
902 state: &mut TileUpdateDirtyState,
903 frame_context: &FrameVisibilityContext,
904 ) {
905 state.compare_cache.clear();
908 let mut invalidation_reason = None;
909 let dirty_rect = self.update_dirty_rects(
910 ctx,
911 state,
912 &mut invalidation_reason,
913 frame_context,
914 );
915 if !dirty_rect.is_empty() {
916 self.invalidate(
917 Some(dirty_rect),
918 invalidation_reason.expect("bug: no invalidation_reason"),
919 );
920 }
921 if ctx.invalidate_all {
922 self.invalidate(None, InvalidationReason::ScaleChanged);
923 }
924 if self.current_descriptor.local_valid_rect != self.prev_descriptor.local_valid_rect {
927 self.invalidate(None, InvalidationReason::ValidRectChanged);
928 state.composite_state.dirty_rects_are_valid = false;
929 }
930 }
931
932 fn invalidate(
935 &mut self,
936 invalidation_rect: Option<PictureRect>,
937 reason: InvalidationReason,
938 ) {
939 self.is_valid = false;
940
941 match invalidation_rect {
942 Some(rect) => {
943 self.local_dirty_rect = self.local_dirty_rect.union(&rect);
944 }
945 None => {
946 self.local_dirty_rect = self.local_tile_rect;
947 }
948 }
949
950 if self.invalidation_reason.is_none() {
951 self.invalidation_reason = Some(reason);
952 }
953 }
954
955 fn pre_update(
958 &mut self,
959 ctx: &TilePreUpdateContext,
960 ) {
961 self.local_tile_rect = PictureRect::new(
962 PicturePoint::new(
963 self.tile_offset.x as f32 * ctx.tile_size.width,
964 self.tile_offset.y as f32 * ctx.tile_size.height,
965 ),
966 PicturePoint::new(
967 (self.tile_offset.x + 1) as f32 * ctx.tile_size.width,
968 (self.tile_offset.y + 1) as f32 * ctx.tile_size.height,
969 ),
970 );
971 self.local_valid_rect = PictureBox2D::new(
975 PicturePoint::new( 1.0e32, 1.0e32),
976 PicturePoint::new(-1.0e32, -1.0e32),
977 );
978 self.invalidation_reason = None;
979 self.sub_graphs.clear();
980
981 self.world_tile_rect = ctx.pic_to_world_mapper
982 .map(&self.local_tile_rect)
983 .expect("bug: map local tile rect");
984
985 self.is_visible = self.world_tile_rect.intersects(&ctx.global_screen_world_rect);
987
988 if !self.is_visible {
992 return;
993 }
994
995 if ctx.background_color != self.background_color {
996 self.invalidate(None, InvalidationReason::BackgroundColor);
997 self.background_color = ctx.background_color;
998 }
999
1000 mem::swap(
1003 &mut self.current_descriptor,
1004 &mut self.prev_descriptor,
1005 );
1006 self.current_descriptor.clear();
1007 self.root.clear(self.local_tile_rect);
1008
1009 self.current_descriptor.last_updated_frame_id = ctx.frame_id;
1012 }
1013
1014 fn add_prim_dependency(
1016 &mut self,
1017 info: &PrimitiveDependencyInfo,
1018 ) {
1019 if !self.is_visible {
1022 return;
1023 }
1024
1025 self.local_valid_rect = self.local_valid_rect.union(&info.prim_clip_box);
1029
1030 let tile_p0 = self.local_tile_rect.min;
1044 let tile_p1 = self.local_tile_rect.max;
1045
1046 let prim_clip_box = PictureBox2D::new(
1047 PicturePoint::new(
1048 clampf(info.prim_clip_box.min.x, tile_p0.x, tile_p1.x),
1049 clampf(info.prim_clip_box.min.y, tile_p0.y, tile_p1.y),
1050 ),
1051 PicturePoint::new(
1052 clampf(info.prim_clip_box.max.x, tile_p0.x, tile_p1.x),
1053 clampf(info.prim_clip_box.max.y, tile_p0.y, tile_p1.y),
1054 ),
1055 );
1056
1057 let prim_index = PrimitiveDependencyIndex(self.current_descriptor.prims.len() as u32);
1059
1060 let dep_offset = self.current_descriptor.dep_data.len() as u32;
1062 let mut dep_count = 0;
1063
1064 for clip in &info.clips {
1065 dep_count += 1;
1066 poke_into_vec(
1067 &PrimitiveDependency::Clip {
1068 clip: *clip,
1069 },
1070 &mut self.current_descriptor.dep_data,
1071 );
1072 }
1073
1074 for spatial_node_index in &info.spatial_nodes {
1075 dep_count += 1;
1076 poke_into_vec(
1077 &PrimitiveDependency::SpatialNode {
1078 index: *spatial_node_index,
1079 },
1080 &mut self.current_descriptor.dep_data,
1081 );
1082 }
1083
1084 for image in &info.images {
1085 dep_count += 1;
1086 poke_into_vec(
1087 &PrimitiveDependency::Image {
1088 image: *image,
1089 },
1090 &mut self.current_descriptor.dep_data,
1091 );
1092 }
1093
1094 for binding in &info.opacity_bindings {
1095 dep_count += 1;
1096 poke_into_vec(
1097 &PrimitiveDependency::OpacityBinding {
1098 binding: *binding,
1099 },
1100 &mut self.current_descriptor.dep_data,
1101 );
1102 }
1103
1104 if let Some(ref binding) = info.color_binding {
1105 dep_count += 1;
1106 poke_into_vec(
1107 &PrimitiveDependency::ColorBinding {
1108 binding: *binding,
1109 },
1110 &mut self.current_descriptor.dep_data,
1111 );
1112 }
1113
1114 self.current_descriptor.prims.push(PrimitiveDescriptor {
1115 prim_uid: info.prim_uid,
1116 prim_clip_box,
1117 dep_offset,
1118 dep_count,
1119 });
1120
1121 self.root.add_prim(prim_index, &info.prim_clip_box);
1123 }
1124
1125 fn update_dirty_and_valid_rects(
1128 &mut self,
1129 ctx: &TileUpdateDirtyContext,
1130 state: &mut TileUpdateDirtyState,
1131 frame_context: &FrameVisibilityContext,
1132 ) {
1133 ensure_red_zone::<PrimitiveDependency>(&mut self.current_descriptor.dep_data);
1135
1136 state.spatial_node_comparer.retain_for_frame(self.current_descriptor.last_updated_frame_id);
1141
1142 if !self.is_visible {
1146 return;
1147 }
1148
1149 self.current_descriptor.local_valid_rect = self.local_valid_rect;
1151
1152 self.current_descriptor.local_valid_rect = self.local_tile_rect
1163 .intersection(&ctx.local_rect)
1164 .and_then(|r| r.intersection(&self.current_descriptor.local_valid_rect))
1165 .unwrap_or_else(PictureRect::zero);
1166
1167 self.world_valid_rect = ctx.pic_to_world_mapper
1170 .map(&self.current_descriptor.local_valid_rect)
1171 .expect("bug: map local valid rect");
1172
1173 let device_rect = (self.world_tile_rect * ctx.global_device_pixel_scale).round();
1178 self.device_valid_rect = (self.world_valid_rect * ctx.global_device_pixel_scale)
1179 .round_out()
1180 .intersection(&device_rect)
1181 .unwrap_or_else(DeviceRect::zero);
1182
1183 self.update_content_validity(ctx, state, frame_context);
1185 }
1186
1187 fn post_update(
1190 &mut self,
1191 ctx: &TilePostUpdateContext,
1192 state: &mut TilePostUpdateState,
1193 frame_context: &FrameVisibilityContext,
1194 ) {
1195 if !self.is_visible {
1199 return;
1200 }
1201
1202 if self.current_descriptor.prims.is_empty() || self.device_valid_rect.is_empty() {
1206 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { mut id, .. }, .. }) = self.surface.take() {
1211 if let Some(id) = id.take() {
1212 state.resource_cache.destroy_compositor_tile(id);
1213 }
1214 }
1215
1216 self.is_visible = false;
1217 return;
1218 }
1219
1220 let clipped_rect = self.current_descriptor.local_valid_rect
1224 .intersection(&ctx.local_clip_rect)
1225 .unwrap_or_else(PictureRect::zero);
1226
1227 let has_opaque_bg_color = self.background_color.map_or(false, |c| c.a >= 1.0);
1228 let has_opaque_backdrop = ctx.backdrop.map_or(false, |b| b.opaque_rect.contains_box(&clipped_rect));
1229 let mut is_opaque = has_opaque_bg_color || has_opaque_backdrop;
1230
1231 for underlay in ctx.underlays {
1234 if clipped_rect.intersects(&underlay.local_rect) {
1235 is_opaque = false;
1236 break;
1237 }
1238 }
1239
1240 self.z_id = ctx.z_id;
1242
1243 if is_opaque != self.is_opaque {
1244 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = self.surface {
1252 if let Some(id) = id.take() {
1253 state.resource_cache.destroy_compositor_tile(id);
1254 }
1255 }
1256
1257 self.invalidate(None, InvalidationReason::SurfaceOpacityChanged);
1259 self.is_opaque = is_opaque;
1260 }
1261
1262 let (supports_dirty_rects, supports_simple_prims) = match state.composite_state.compositor_kind {
1267 CompositorKind::Draw { .. } => {
1268 (frame_context.config.gpu_supports_render_target_partial_update, true)
1269 }
1270 CompositorKind::Native { capabilities, .. } => {
1271 (capabilities.max_update_rects > 0, false)
1272 }
1273 CompositorKind::Layer { .. } => {
1274 (false, true)
1276 }
1277 };
1278
1279 if supports_dirty_rects {
1282 if ctx.current_tile_size == state.resource_cache.picture_textures.default_tile_size() {
1284 let max_split_level = 3;
1285
1286 self.root.maybe_merge_or_split(
1288 0,
1289 &self.current_descriptor.prims,
1290 max_split_level,
1291 );
1292 }
1293 }
1294
1295 if !self.is_valid && !supports_dirty_rects {
1299 self.local_dirty_rect = self.local_tile_rect;
1300 }
1301
1302 let is_simple_prim =
1308 ctx.backdrop.map_or(false, |b| b.kind.is_some()) &&
1309 self.current_descriptor.prims.len() == 1 &&
1310 self.is_opaque &&
1311 supports_simple_prims;
1312
1313 let surface = if is_simple_prim {
1315 match ctx.backdrop.unwrap().kind {
1319 Some(BackdropKind::Color { color }) => {
1320 TileSurface::Color {
1321 color,
1322 }
1323 }
1324 Some(BackdropKind::Clear) => {
1325 TileSurface::Clear
1326 }
1327 None => {
1328 unreachable!();
1330 }
1331 }
1332 } else {
1333 match self.surface.take() {
1338 Some(TileSurface::Texture { descriptor }) => {
1339 TileSurface::Texture {
1341 descriptor,
1342 }
1343 }
1344 Some(TileSurface::Color { .. }) | Some(TileSurface::Clear) | None => {
1345 let descriptor = match state.composite_state.compositor_kind {
1350 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
1351 SurfaceTextureDescriptor::TextureCache {
1354 handle: None,
1355 }
1356 }
1357 CompositorKind::Native { .. } => {
1358 SurfaceTextureDescriptor::Native {
1362 id: None,
1363 }
1364 }
1365 };
1366
1367 TileSurface::Texture {
1368 descriptor,
1369 }
1370 }
1371 }
1372 };
1373
1374 self.surface = Some(surface);
1376 }
1377}
1378
1379#[derive(Debug, Clone)]
1381#[cfg_attr(feature = "capture", derive(Serialize))]
1382#[cfg_attr(feature = "replay", derive(Deserialize))]
1383pub struct PrimitiveDescriptor {
1384 pub prim_uid: ItemUid,
1385 pub prim_clip_box: PictureBox2D,
1386 pub dep_offset: u32,
1388 pub dep_count: u32,
1389}
1390
1391impl PartialEq for PrimitiveDescriptor {
1392 fn eq(&self, other: &Self) -> bool {
1393 const EPSILON: f32 = 0.001;
1394
1395 if self.prim_uid != other.prim_uid {
1396 return false;
1397 }
1398
1399 if !self.prim_clip_box.min.x.approx_eq_eps(&other.prim_clip_box.min.x, &EPSILON) {
1400 return false;
1401 }
1402 if !self.prim_clip_box.min.y.approx_eq_eps(&other.prim_clip_box.min.y, &EPSILON) {
1403 return false;
1404 }
1405 if !self.prim_clip_box.max.x.approx_eq_eps(&other.prim_clip_box.max.x, &EPSILON) {
1406 return false;
1407 }
1408 if !self.prim_clip_box.max.y.approx_eq_eps(&other.prim_clip_box.max.y, &EPSILON) {
1409 return false;
1410 }
1411
1412 if self.dep_count != other.dep_count {
1413 return false;
1414 }
1415
1416 true
1417 }
1418}
1419
1420#[cfg_attr(any(feature="capture",feature="replay"), derive(Clone))]
1423#[cfg_attr(feature = "capture", derive(Serialize))]
1424#[cfg_attr(feature = "replay", derive(Deserialize))]
1425pub struct TileDescriptor {
1426 prims: Vec<PrimitiveDescriptor>,
1430
1431 pub local_valid_rect: PictureRect,
1433
1434 last_updated_frame_id: FrameId,
1437
1438 dep_data: Vec<u8>,
1440}
1441
1442impl TileDescriptor {
1443 fn new() -> Self {
1444 TileDescriptor {
1445 local_valid_rect: PictureRect::zero(),
1446 dep_data: Vec::new(),
1447 prims: Vec::new(),
1448 last_updated_frame_id: FrameId::INVALID,
1449 }
1450 }
1451
1452 fn print(&self, pt: &mut dyn PrintTreePrinter) {
1454 pt.new_level("current_descriptor".to_string());
1455
1456 pt.new_level("prims".to_string());
1457 for prim in &self.prims {
1458 pt.new_level(format!("prim uid={}", prim.prim_uid.get_uid()));
1459 pt.add_item(format!("clip: p0={},{} p1={},{}",
1460 prim.prim_clip_box.min.x,
1461 prim.prim_clip_box.min.y,
1462 prim.prim_clip_box.max.x,
1463 prim.prim_clip_box.max.y,
1464 ));
1465 pt.end_level();
1466 }
1467 pt.end_level();
1468
1469 pt.end_level();
1470 }
1471
1472 fn clear(&mut self) {
1475 self.local_valid_rect = PictureRect::zero();
1476 self.prims.clear();
1477 self.dep_data.clear();
1478 }
1479}
1480
1481#[derive(Clone)]
1488pub struct DirtyRegion {
1489 pub combined: VisRect,
1491
1492 pub visibility_spatial_node: SpatialNodeIndex,
1495 local_spatial_node: SpatialNodeIndex,
1497}
1498
1499impl DirtyRegion {
1500 pub fn new(
1502 visibility_spatial_node: SpatialNodeIndex,
1503 local_spatial_node: SpatialNodeIndex,
1504 ) -> Self {
1505 DirtyRegion {
1506 combined: VisRect::zero(),
1507 visibility_spatial_node,
1508 local_spatial_node,
1509 }
1510 }
1511
1512 pub fn reset(
1514 &mut self,
1515 visibility_spatial_node: SpatialNodeIndex,
1516 local_spatial_node: SpatialNodeIndex,
1517 ) {
1518 self.combined = VisRect::zero();
1519 self.visibility_spatial_node = visibility_spatial_node;
1520 self.local_spatial_node = local_spatial_node;
1521 }
1522
1523 pub fn add_dirty_region(
1526 &mut self,
1527 rect_in_pic_space: PictureRect,
1528 spatial_tree: &SpatialTree,
1529 ) {
1530 let map_pic_to_raster = SpaceMapper::new_with_target(
1531 self.visibility_spatial_node,
1532 self.local_spatial_node,
1533 VisRect::max_rect(),
1534 spatial_tree,
1535 );
1536
1537 let raster_rect = map_pic_to_raster
1538 .map(&rect_in_pic_space)
1539 .expect("bug");
1540
1541 self.combined = self.combined.union(&raster_rect);
1543 }
1544}
1545
1546#[derive(Debug, Copy, Clone)]
1550pub enum BackdropKind {
1551 Color {
1552 color: ColorF,
1553 },
1554 Clear,
1555}
1556
1557#[derive(Debug, Copy, Clone)]
1559pub struct BackdropInfo {
1560 pub opaque_rect: PictureRect,
1564 pub spanning_opaque_color: Option<ColorF>,
1567 pub kind: Option<BackdropKind>,
1569 pub backdrop_rect: PictureRect,
1571}
1572
1573impl BackdropInfo {
1574 fn empty() -> Self {
1575 BackdropInfo {
1576 opaque_rect: PictureRect::zero(),
1577 spanning_opaque_color: None,
1578 kind: None,
1579 backdrop_rect: PictureRect::zero(),
1580 }
1581 }
1582}
1583
1584pub struct NativeSurface {
1596 pub opaque: NativeSurfaceId,
1598 pub alpha: NativeSurfaceId,
1600}
1601
1602#[derive(PartialEq, Eq, Hash)]
1604pub struct ExternalNativeSurfaceKey {
1605 pub image_keys: [ImageKey; 3],
1607 pub size: Option<DeviceIntSize>,
1611}
1612
1613pub struct ExternalNativeSurface {
1615 pub used_this_frame: bool,
1618 pub native_surface_id: NativeSurfaceId,
1620 pub image_dependencies: [ImageDependency; 3],
1624}
1625
1626#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1629#[cfg_attr(feature = "capture", derive(Serialize))]
1630#[cfg_attr(feature = "replay", derive(Deserialize))]
1631pub struct SliceId(usize);
1632
1633impl SliceId {
1634 pub fn new(index: usize) -> Self {
1635 SliceId(index)
1636 }
1637}
1638
1639pub struct TileCacheParams {
1642 pub debug_flags: DebugFlags,
1644 pub slice: usize,
1646 pub slice_flags: SliceFlags,
1648 pub spatial_node_index: SpatialNodeIndex,
1650 pub visibility_node_index: SpatialNodeIndex,
1652 pub background_color: Option<ColorF>,
1655 pub shared_clip_node_id: ClipNodeId,
1657 pub shared_clip_leaf_id: Option<ClipLeafId>,
1659 pub virtual_surface_size: i32,
1661 pub image_surface_count: usize,
1665 pub yuv_image_surface_count: usize,
1669}
1670
1671#[cfg_attr(feature = "capture", derive(Serialize))]
1674#[cfg_attr(feature = "replay", derive(Deserialize))]
1675#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1676pub struct SubSliceIndex(u8);
1677
1678impl SubSliceIndex {
1679 pub const DEFAULT: SubSliceIndex = SubSliceIndex(0);
1680
1681 pub fn new(index: usize) -> Self {
1682 SubSliceIndex(index as u8)
1683 }
1684
1685 pub fn is_primary(&self) -> bool {
1688 self.0 == 0
1689 }
1690
1691 pub fn as_usize(&self) -> usize {
1693 self.0 as usize
1694 }
1695}
1696
1697pub struct CompositorSurface {
1700 pub descriptor: ExternalSurfaceDescriptor,
1702 prohibited_rect: PictureRect,
1705 pub is_opaque: bool,
1707}
1708
1709pub struct SubSlice {
1714 pub tiles: FastHashMap<TileOffset, Box<Tile>>,
1716 pub native_surface: Option<NativeSurface>,
1720 pub compositor_surfaces: Vec<CompositorSurface>,
1723 pub composite_tiles: Vec<CompositeTile>,
1725 pub opaque_tile_descriptors: Vec<CompositeTileDescriptor>,
1727 pub alpha_tile_descriptors: Vec<CompositeTileDescriptor>,
1729}
1730
1731impl SubSlice {
1732 fn new() -> Self {
1734 SubSlice {
1735 tiles: FastHashMap::default(),
1736 native_surface: None,
1737 compositor_surfaces: Vec::new(),
1738 composite_tiles: Vec::new(),
1739 opaque_tile_descriptors: Vec::new(),
1740 alpha_tile_descriptors: Vec::new(),
1741 }
1742 }
1743
1744 fn reset(&mut self) {
1747 self.compositor_surfaces.clear();
1748 self.composite_tiles.clear();
1749 self.opaque_tile_descriptors.clear();
1750 self.alpha_tile_descriptors.clear();
1751 }
1752
1753 fn resize(&mut self, new_tile_rect: TileRect) -> FastHashMap<TileOffset, Box<Tile>> {
1755 let mut old_tiles = mem::replace(&mut self.tiles, FastHashMap::default());
1756 self.tiles.reserve(new_tile_rect.area() as usize);
1757
1758 for y in new_tile_rect.min.y .. new_tile_rect.max.y {
1759 for x in new_tile_rect.min.x .. new_tile_rect.max.x {
1760 let key = TileOffset::new(x, y);
1761 let tile = old_tiles
1762 .remove(&key)
1763 .unwrap_or_else(|| {
1764 Box::new(Tile::new(key))
1765 });
1766 self.tiles.insert(key, tile);
1767 }
1768 }
1769
1770 old_tiles
1771 }
1772}
1773
1774pub struct BackdropSurface {
1775 pub id: NativeSurfaceId,
1776 color: ColorF,
1777 pub device_rect: DeviceRect,
1778}
1779
1780pub struct TileCacheInstance {
1782 pub debug_flags: DebugFlags,
1784 pub slice: usize,
1791 pub slice_flags: SliceFlags,
1793 pub current_tile_size: DeviceIntSize,
1795 pub sub_slices: Vec<SubSlice>,
1797 pub spatial_node_index: SpatialNodeIndex,
1799 pub visibility_node_index: SpatialNodeIndex,
1801 opacity_bindings: FastHashMap<PropertyBindingId, OpacityBindingInfo>,
1804 old_opacity_bindings: FastHashMap<PropertyBindingId, OpacityBindingInfo>,
1806 spatial_node_comparer: SpatialNodeComparer,
1808 color_bindings: FastHashMap<PropertyBindingId, ColorBindingInfo>,
1811 old_color_bindings: FastHashMap<PropertyBindingId, ColorBindingInfo>,
1813 pub dirty_region: DirtyRegion,
1815 tile_size: PictureSize,
1817 tile_rect: TileRect,
1819 tile_bounds_p0: TileOffset,
1822 tile_bounds_p1: TileOffset,
1823 pub local_rect: PictureRect,
1825 pub local_clip_rect: PictureRect,
1827 pub compositor_clip: Option<CompositorClipIndex>,
1829 pub screen_rect_in_pic_space: PictureRect,
1831 surface_index: SurfaceIndex,
1833 pub background_color: Option<ColorF>,
1836 pub backdrop: BackdropInfo,
1838 pub subpixel_mode: SubpixelMode,
1841 pub shared_clip_node_id: ClipNodeId,
1843 pub shared_clip_leaf_id: Option<ClipLeafId>,
1845 frames_until_size_eval: usize,
1850 virtual_offset: DeviceIntPoint,
1857 compare_cache: FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
1860 tile_size_override: Option<DeviceIntSize>,
1863 pub external_native_surface_cache: FastHashMap<ExternalNativeSurfaceKey, ExternalNativeSurface>,
1865 frame_id: FrameId,
1867 pub transform_index: CompositorTransformIndex,
1869 local_to_raster: ScaleOffset,
1871 raster_to_device: ScaleOffset,
1873 invalidate_all_tiles: bool,
1875 current_raster_scale: f32,
1877 current_surface_traversal_depth: usize,
1879 deferred_dirty_tests: Vec<DeferredDirtyTest>,
1882 found_prims_after_backdrop: bool,
1884 pub backdrop_surface: Option<BackdropSurface>,
1885 pub underlays: Vec<ExternalSurfaceDescriptor>,
1887 pub overlay_region: PictureRect,
1889 pub yuv_images_count: usize,
1891 pub yuv_images_remaining: usize,
1894}
1895
1896#[derive(Clone, Copy)]
1897enum SurfacePromotionFailure {
1898 ImageWaitingOnYuvImage,
1899 NotPremultipliedAlpha,
1900 OverlaySurfaceLimit,
1901 OverlayNeedsMask,
1902 UnderlayAlphaBackdrop,
1903 UnderlaySurfaceLimit,
1904 UnderlayIntersectsOverlay,
1905 UnderlayLowQualityZoom,
1906 NotRootTileCache,
1907 ComplexTransform,
1908 SliceAtomic,
1909 SizeTooLarge,
1910}
1911
1912impl Display for SurfacePromotionFailure {
1913 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
1914 write!(
1915 f,
1916 "{}",
1917 match *self {
1918 SurfacePromotionFailure::ImageWaitingOnYuvImage => "Image prim waiting for all YuvImage prims to be considered for promotion",
1919 SurfacePromotionFailure::NotPremultipliedAlpha => "does not use premultiplied alpha",
1920 SurfacePromotionFailure::OverlaySurfaceLimit => "hit the overlay surface limit",
1921 SurfacePromotionFailure::OverlayNeedsMask => "overlay not allowed for prim with mask",
1922 SurfacePromotionFailure::UnderlayAlphaBackdrop => "underlay requires an opaque backdrop",
1923 SurfacePromotionFailure::UnderlaySurfaceLimit => "hit the underlay surface limit",
1924 SurfacePromotionFailure::UnderlayIntersectsOverlay => "underlay intersects already-promoted overlay",
1925 SurfacePromotionFailure::UnderlayLowQualityZoom => "underlay not allowed during low-quality pinch zoom",
1926 SurfacePromotionFailure::NotRootTileCache => "is not on a root tile cache",
1927 SurfacePromotionFailure::ComplexTransform => "has a complex transform",
1928 SurfacePromotionFailure::SliceAtomic => "slice is atomic",
1929 SurfacePromotionFailure::SizeTooLarge => "surface is too large for compositor",
1930 }.to_owned()
1931 )
1932 }
1933}
1934
1935impl TileCacheInstance {
1936 pub fn new(params: TileCacheParams) -> Self {
1937 let sub_slice_count = (params.image_surface_count + params.yuv_image_surface_count).min(MAX_COMPOSITOR_SURFACES) + 1;
1940
1941 let mut sub_slices = Vec::with_capacity(sub_slice_count);
1942 for _ in 0 .. sub_slice_count {
1943 sub_slices.push(SubSlice::new());
1944 }
1945
1946 TileCacheInstance {
1947 debug_flags: params.debug_flags,
1948 slice: params.slice,
1949 slice_flags: params.slice_flags,
1950 spatial_node_index: params.spatial_node_index,
1951 visibility_node_index: params.visibility_node_index,
1952 sub_slices,
1953 opacity_bindings: FastHashMap::default(),
1954 old_opacity_bindings: FastHashMap::default(),
1955 spatial_node_comparer: SpatialNodeComparer::new(),
1956 color_bindings: FastHashMap::default(),
1957 old_color_bindings: FastHashMap::default(),
1958 dirty_region: DirtyRegion::new(params.visibility_node_index, params.spatial_node_index),
1959 tile_size: PictureSize::zero(),
1960 tile_rect: TileRect::zero(),
1961 tile_bounds_p0: TileOffset::zero(),
1962 tile_bounds_p1: TileOffset::zero(),
1963 local_rect: PictureRect::zero(),
1964 local_clip_rect: PictureRect::zero(),
1965 compositor_clip: None,
1966 screen_rect_in_pic_space: PictureRect::zero(),
1967 surface_index: SurfaceIndex(0),
1968 background_color: params.background_color,
1969 backdrop: BackdropInfo::empty(),
1970 subpixel_mode: SubpixelMode::Allow,
1971 shared_clip_node_id: params.shared_clip_node_id,
1972 shared_clip_leaf_id: params.shared_clip_leaf_id,
1973 current_tile_size: DeviceIntSize::zero(),
1974 frames_until_size_eval: 0,
1975 virtual_offset: DeviceIntPoint::new(
1977 params.virtual_surface_size / 2,
1978 params.virtual_surface_size / 2,
1979 ),
1980 compare_cache: FastHashMap::default(),
1981 tile_size_override: None,
1982 external_native_surface_cache: FastHashMap::default(),
1983 frame_id: FrameId::INVALID,
1984 transform_index: CompositorTransformIndex::INVALID,
1985 raster_to_device: ScaleOffset::identity(),
1986 local_to_raster: ScaleOffset::identity(),
1987 invalidate_all_tiles: true,
1988 current_raster_scale: 1.0,
1989 current_surface_traversal_depth: 0,
1990 deferred_dirty_tests: Vec::new(),
1991 found_prims_after_backdrop: false,
1992 backdrop_surface: None,
1993 underlays: Vec::new(),
1994 overlay_region: PictureRect::zero(),
1995 yuv_images_count: params.yuv_image_surface_count,
1996 yuv_images_remaining: 0,
1997 }
1998 }
1999
2000 pub fn tile_count(&self) -> usize {
2002 self.tile_rect.area() as usize * self.sub_slices.len()
2003 }
2004
2005 pub fn memory_pressure(&mut self, resource_cache: &mut ResourceCache) {
2007 for sub_slice in &mut self.sub_slices {
2008 for tile in sub_slice.tiles.values_mut() {
2009 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2010 if let Some(id) = id.take() {
2013 resource_cache.destroy_compositor_tile(id);
2014 }
2015 }
2016 }
2017 if let Some(native_surface) = sub_slice.native_surface.take() {
2018 resource_cache.destroy_compositor_surface(native_surface.opaque);
2019 resource_cache.destroy_compositor_surface(native_surface.alpha);
2020 }
2021 }
2022 }
2023
2024 pub fn prepare_for_new_scene(
2028 &mut self,
2029 params: TileCacheParams,
2030 resource_cache: &mut ResourceCache,
2031 ) {
2032 assert_eq!(self.slice, params.slice);
2034
2035 let required_sub_slice_count = (params.image_surface_count + params.yuv_image_surface_count).min(MAX_COMPOSITOR_SURFACES) + 1;
2038
2039 if self.sub_slices.len() != required_sub_slice_count {
2040 self.tile_rect = TileRect::zero();
2041
2042 if self.sub_slices.len() > required_sub_slice_count {
2043 let old_sub_slices = self.sub_slices.split_off(required_sub_slice_count);
2044
2045 for mut sub_slice in old_sub_slices {
2046 for tile in sub_slice.tiles.values_mut() {
2047 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2048 if let Some(id) = id.take() {
2049 resource_cache.destroy_compositor_tile(id);
2050 }
2051 }
2052 }
2053
2054 if let Some(native_surface) = sub_slice.native_surface {
2055 resource_cache.destroy_compositor_surface(native_surface.opaque);
2056 resource_cache.destroy_compositor_surface(native_surface.alpha);
2057 }
2058 }
2059 } else {
2060 while self.sub_slices.len() < required_sub_slice_count {
2061 self.sub_slices.push(SubSlice::new());
2062 }
2063 }
2064 }
2065
2066 self.slice_flags = params.slice_flags;
2070 self.spatial_node_index = params.spatial_node_index;
2071 self.background_color = params.background_color;
2072 self.shared_clip_leaf_id = params.shared_clip_leaf_id;
2073 self.shared_clip_node_id = params.shared_clip_node_id;
2074
2075 self.frames_until_size_eval = 0;
2078
2079 self.yuv_images_count = params.yuv_image_surface_count;
2081 }
2082
2083 pub fn destroy(
2086 self,
2087 resource_cache: &mut ResourceCache,
2088 ) {
2089 for sub_slice in self.sub_slices {
2090 if let Some(native_surface) = sub_slice.native_surface {
2091 resource_cache.destroy_compositor_surface(native_surface.opaque);
2092 resource_cache.destroy_compositor_surface(native_surface.alpha);
2093 }
2094 }
2095
2096 for (_, external_surface) in self.external_native_surface_cache {
2097 resource_cache.destroy_compositor_surface(external_surface.native_surface_id)
2098 }
2099
2100 if let Some(backdrop_surface) = &self.backdrop_surface {
2101 resource_cache.destroy_compositor_surface(backdrop_surface.id);
2102 }
2103 }
2104
2105 fn get_tile_coords_for_rect(
2107 &self,
2108 rect: &PictureRect,
2109 ) -> (TileOffset, TileOffset) {
2110 let mut p0 = TileOffset::new(
2112 (rect.min.x / self.tile_size.width).floor() as i32,
2113 (rect.min.y / self.tile_size.height).floor() as i32,
2114 );
2115
2116 let mut p1 = TileOffset::new(
2117 (rect.max.x / self.tile_size.width).ceil() as i32,
2118 (rect.max.y / self.tile_size.height).ceil() as i32,
2119 );
2120
2121 p0.x = clamp(p0.x, self.tile_bounds_p0.x, self.tile_bounds_p1.x);
2123 p0.y = clamp(p0.y, self.tile_bounds_p0.y, self.tile_bounds_p1.y);
2124 p1.x = clamp(p1.x, self.tile_bounds_p0.x, self.tile_bounds_p1.x);
2125 p1.y = clamp(p1.y, self.tile_bounds_p0.y, self.tile_bounds_p1.y);
2126
2127 (p0, p1)
2128 }
2129
2130 pub fn pre_update(
2132 &mut self,
2133 surface_index: SurfaceIndex,
2134 frame_context: &FrameVisibilityContext,
2135 frame_state: &mut FrameVisibilityState,
2136 ) -> WorldRect {
2137 let surface = &frame_state.surfaces[surface_index.0];
2138 let pic_rect = surface.unclipped_local_rect;
2139
2140 self.surface_index = surface_index;
2141 self.local_rect = pic_rect;
2142 self.local_clip_rect = PictureRect::max_rect();
2143 self.deferred_dirty_tests.clear();
2144 self.underlays.clear();
2145 self.overlay_region = PictureRect::zero();
2146 self.yuv_images_remaining = self.yuv_images_count;
2147
2148 for sub_slice in &mut self.sub_slices {
2149 sub_slice.reset();
2150 }
2151
2152 self.backdrop = BackdropInfo::empty();
2155
2156 let pic_to_world_mapper = SpaceMapper::new_with_target(
2159 frame_context.root_spatial_node_index,
2160 self.spatial_node_index,
2161 frame_context.global_screen_world_rect,
2162 frame_context.spatial_tree,
2163 );
2164 self.screen_rect_in_pic_space = pic_to_world_mapper
2165 .unmap(&frame_context.global_screen_world_rect)
2166 .expect("unable to unmap screen rect");
2167
2168 let pic_to_vis_mapper = SpaceMapper::new_with_target(
2169 frame_context.root_spatial_node_index,
2171 self.spatial_node_index,
2172 surface.culling_rect,
2173 frame_context.spatial_tree,
2174 );
2175
2176 if let Some(shared_clip_leaf_id) = self.shared_clip_leaf_id {
2180 let map_local_to_picture = SpaceMapper::new(
2181 self.spatial_node_index,
2182 pic_rect,
2183 );
2184
2185 frame_state.clip_store.set_active_clips(
2186 self.spatial_node_index,
2187 map_local_to_picture.ref_spatial_node_index,
2188 surface.visibility_spatial_node_index,
2189 shared_clip_leaf_id,
2190 frame_context.spatial_tree,
2191 &mut frame_state.data_stores.clip,
2192 &frame_state.clip_tree,
2193 );
2194
2195 let clip_chain_instance = frame_state.clip_store.build_clip_chain_instance(
2196 pic_rect.cast_unit(),
2197 &map_local_to_picture,
2198 &pic_to_vis_mapper,
2199 frame_context.spatial_tree,
2200 frame_state.gpu_cache,
2201 frame_state.resource_cache,
2202 frame_context.global_device_pixel_scale,
2203 &surface.culling_rect,
2204 &mut frame_state.data_stores.clip,
2205 frame_state.rg_builder,
2206 true,
2207 );
2208
2209 self.local_clip_rect = PictureRect::zero();
2213 self.compositor_clip = None;
2214
2215 if let Some(clip_chain) = clip_chain_instance {
2216 self.local_clip_rect = clip_chain.pic_coverage_rect;
2217
2218 self.compositor_clip = if clip_chain.needs_mask {
2219 let clip_instance = frame_state
2220 .clip_store
2221 .get_instance_from_range(&clip_chain.clips_range, 0);
2222 let clip_node = &frame_state.data_stores.clip[clip_instance.handle];
2223
2224 let index = match clip_node.item.kind {
2225 ClipItemKind::RoundedRectangle { rect, radius, mode } => {
2226 assert_eq!(mode, ClipMode::Clip);
2227
2228 let map = ClipSpaceConversion::new(
2233 frame_context.root_spatial_node_index,
2234 clip_node.item.spatial_node_index,
2235 frame_context.root_spatial_node_index,
2236 frame_context.spatial_tree,
2237 );
2238
2239 let (rect, radius) = match map {
2240 ClipSpaceConversion::Local => {
2241 (rect.cast_unit(), radius)
2242 }
2243 ClipSpaceConversion::ScaleOffset(scale_offset) => {
2244 (
2245 scale_offset.map_rect(&rect),
2246 BorderRadius {
2247 top_left: scale_offset.map_size(&radius.top_left),
2248 top_right: scale_offset.map_size(&radius.top_right),
2249 bottom_left: scale_offset.map_size(&radius.bottom_left),
2250 bottom_right: scale_offset.map_size(&radius.bottom_right),
2251 },
2252 )
2253 }
2254 ClipSpaceConversion::Transform(..) => {
2255 unreachable!();
2256 }
2257 };
2258
2259 frame_state.composite_state.register_clip(
2260 rect,
2261 radius,
2262 )
2263 }
2264 _ => {
2265 unreachable!();
2270 }
2271 };
2272
2273 Some(index)
2274 } else {
2275 None
2276 };
2277 }
2278 }
2279
2280 self.frame_id.advance();
2283
2284 self.spatial_node_comparer.next_frame(self.spatial_node_index);
2287
2288 for external_native_surface in self.external_native_surface_cache.values_mut() {
2294 external_native_surface.used_this_frame = false;
2295 }
2296
2297 if self.frames_until_size_eval == 0 ||
2301 self.tile_size_override != frame_context.config.tile_size_override {
2302
2303 let desired_tile_size = match frame_context.config.tile_size_override {
2305 Some(tile_size_override) => {
2306 tile_size_override
2307 }
2308 None => {
2309 if self.slice_flags.contains(SliceFlags::IS_SCROLLBAR) {
2310 if pic_rect.width() <= pic_rect.height() {
2311 TILE_SIZE_SCROLLBAR_VERTICAL
2312 } else {
2313 TILE_SIZE_SCROLLBAR_HORIZONTAL
2314 }
2315 } else {
2316 frame_state.resource_cache.picture_textures.default_tile_size()
2317 }
2318 }
2319 };
2320
2321 if desired_tile_size != self.current_tile_size {
2324 for sub_slice in &mut self.sub_slices {
2325 if let Some(native_surface) = sub_slice.native_surface.take() {
2328 frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
2329 frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
2330 }
2331 sub_slice.tiles.clear();
2332 }
2333 self.tile_rect = TileRect::zero();
2334 self.current_tile_size = desired_tile_size;
2335 }
2336
2337 self.frames_until_size_eval = 120;
2340 self.tile_size_override = frame_context.config.tile_size_override;
2341 }
2342
2343 let local_to_device = get_relative_scale_offset(
2345 self.spatial_node_index,
2346 frame_context.root_spatial_node_index,
2347 frame_context.spatial_tree,
2348 );
2349
2350 let mut raster_to_device = local_to_device;
2352
2353 if frame_context.config.low_quality_pinch_zoom {
2354 raster_to_device.scale.x /= self.current_raster_scale;
2355 raster_to_device.scale.y /= self.current_raster_scale;
2356 } else {
2357 raster_to_device.scale.x = 1.0;
2358 raster_to_device.scale.y = 1.0;
2359 }
2360
2361 let local_to_raster = local_to_device.then(&raster_to_device.inverse());
2363
2364 const EPSILON: f32 = 0.001;
2365 let compositor_translation_changed =
2366 !raster_to_device.offset.x.approx_eq_eps(&self.raster_to_device.offset.x, &EPSILON) ||
2367 !raster_to_device.offset.y.approx_eq_eps(&self.raster_to_device.offset.y, &EPSILON);
2368 let compositor_scale_changed =
2369 !raster_to_device.scale.x.approx_eq_eps(&self.raster_to_device.scale.x, &EPSILON) ||
2370 !raster_to_device.scale.y.approx_eq_eps(&self.raster_to_device.scale.y, &EPSILON);
2371 let surface_scale_changed =
2372 !local_to_raster.scale.x.approx_eq_eps(&self.local_to_raster.scale.x, &EPSILON) ||
2373 !local_to_raster.scale.y.approx_eq_eps(&self.local_to_raster.scale.y, &EPSILON);
2374
2375 if compositor_translation_changed ||
2376 compositor_scale_changed ||
2377 surface_scale_changed ||
2378 frame_context.config.force_invalidation {
2379 frame_state.composite_state.dirty_rects_are_valid = false;
2380 }
2381
2382 self.raster_to_device = raster_to_device;
2383 self.local_to_raster = local_to_raster;
2384 self.invalidate_all_tiles = surface_scale_changed || frame_context.config.force_invalidation;
2385
2386 let current_properties = frame_context.scene_properties.float_properties();
2389 mem::swap(&mut self.opacity_bindings, &mut self.old_opacity_bindings);
2390
2391 self.opacity_bindings.clear();
2392 for (id, value) in current_properties {
2393 let changed = match self.old_opacity_bindings.get(id) {
2394 Some(old_property) => !old_property.value.approx_eq(value),
2395 None => true,
2396 };
2397 self.opacity_bindings.insert(*id, OpacityBindingInfo {
2398 value: *value,
2399 changed,
2400 });
2401 }
2402
2403 let current_properties = frame_context.scene_properties.color_properties();
2406 mem::swap(&mut self.color_bindings, &mut self.old_color_bindings);
2407
2408 self.color_bindings.clear();
2409 for (id, value) in current_properties {
2410 let changed = match self.old_color_bindings.get(id) {
2411 Some(old_property) => old_property.value != (*value).into(),
2412 None => true,
2413 };
2414 self.color_bindings.insert(*id, ColorBindingInfo {
2415 value: (*value).into(),
2416 changed,
2417 });
2418 }
2419
2420 let world_tile_size = WorldSize::new(
2421 self.current_tile_size.width as f32 / frame_context.global_device_pixel_scale.0,
2422 self.current_tile_size.height as f32 / frame_context.global_device_pixel_scale.0,
2423 );
2424
2425 self.tile_size = PictureSize::new(
2426 world_tile_size.width / self.local_to_raster.scale.x,
2427 world_tile_size.height / self.local_to_raster.scale.y,
2428 );
2429
2430 let desired_rect_in_pic_space = self.screen_rect_in_pic_space
2435 .inflate(0.0, 1.0 * self.tile_size.height);
2436
2437 let needed_rect_in_pic_space = desired_rect_in_pic_space
2438 .intersection(&pic_rect)
2439 .unwrap_or_else(Box2D::zero);
2440
2441 let p0 = needed_rect_in_pic_space.min;
2442 let p1 = needed_rect_in_pic_space.max;
2443
2444 let x0 = (p0.x / self.tile_size.width).floor() as i32;
2445 let x1 = (p1.x / self.tile_size.width).ceil() as i32;
2446
2447 let y0 = (p0.y / self.tile_size.height).floor() as i32;
2448 let y1 = (p1.y / self.tile_size.height).ceil() as i32;
2449
2450 let new_tile_rect = TileRect {
2451 min: TileOffset::new(x0, y0),
2452 max: TileOffset::new(x1, y1),
2453 };
2454
2455 let virtual_surface_size = frame_context.config.compositor_kind.get_virtual_surface_size();
2461 if virtual_surface_size > 0 {
2464 let tx0 = self.virtual_offset.x + x0 * self.current_tile_size.width;
2466 let ty0 = self.virtual_offset.y + y0 * self.current_tile_size.height;
2467 let tx1 = self.virtual_offset.x + (x1+1) * self.current_tile_size.width;
2468 let ty1 = self.virtual_offset.y + (y1+1) * self.current_tile_size.height;
2469
2470 let need_new_virtual_offset = tx0 < 0 ||
2471 ty0 < 0 ||
2472 tx1 >= virtual_surface_size ||
2473 ty1 >= virtual_surface_size;
2474
2475 if need_new_virtual_offset {
2476 self.virtual_offset = DeviceIntPoint::new(
2480 (virtual_surface_size/2) - ((x0 + x1) / 2) * self.current_tile_size.width,
2481 (virtual_surface_size/2) - ((y0 + y1) / 2) * self.current_tile_size.height,
2482 );
2483
2484 for sub_slice in &mut self.sub_slices {
2487 for tile in sub_slice.tiles.values_mut() {
2488 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2489 if let Some(id) = id.take() {
2490 frame_state.resource_cache.destroy_compositor_tile(id);
2491 tile.surface = None;
2492 tile.invalidate(None, InvalidationReason::CompositorKindChanged);
2495 }
2496 }
2497 }
2498
2499 if let Some(native_surface) = sub_slice.native_surface.take() {
2502 frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
2503 frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
2504 }
2505 }
2506 }
2507 }
2508
2509 if new_tile_rect != self.tile_rect {
2511 for sub_slice in &mut self.sub_slices {
2512 let mut old_tiles = sub_slice.resize(new_tile_rect);
2513
2514 if !old_tiles.is_empty() {
2516 frame_state.composite_state.dirty_rects_are_valid = false;
2517 }
2518
2519 frame_state.composite_state.destroy_native_tiles(
2524 old_tiles.values_mut(),
2525 frame_state.resource_cache,
2526 );
2527 }
2528 }
2529
2530 self.tile_bounds_p0 = TileOffset::new(x0, y0);
2533 self.tile_bounds_p1 = TileOffset::new(x1, y1);
2534 self.tile_rect = new_tile_rect;
2535
2536 let mut world_culling_rect = WorldRect::zero();
2537
2538 let mut ctx = TilePreUpdateContext {
2539 pic_to_world_mapper,
2540 background_color: self.background_color,
2541 global_screen_world_rect: frame_context.global_screen_world_rect,
2542 tile_size: self.tile_size,
2543 frame_id: self.frame_id,
2544 };
2545
2546 for sub_slice in &mut self.sub_slices {
2548 for tile in sub_slice.tiles.values_mut() {
2549 tile.pre_update(&ctx);
2550
2551 if tile.is_visible {
2564 world_culling_rect = world_culling_rect.union(&tile.world_tile_rect);
2565 }
2566 }
2567
2568 ctx.background_color = None;
2570 }
2571
2572 match frame_context.config.compositor_kind {
2574 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
2575 for sub_slice in &mut self.sub_slices {
2576 for tile in sub_slice.tiles.values_mut() {
2577 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2578 if let Some(id) = id.take() {
2579 frame_state.resource_cache.destroy_compositor_tile(id);
2580 }
2581 tile.surface = None;
2582 tile.invalidate(None, InvalidationReason::CompositorKindChanged);
2584 }
2585 }
2586
2587 if let Some(native_surface) = sub_slice.native_surface.take() {
2588 frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
2589 frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
2590 }
2591 }
2592
2593 for (_, external_surface) in self.external_native_surface_cache.drain() {
2594 frame_state.resource_cache.destroy_compositor_surface(external_surface.native_surface_id)
2595 }
2596 }
2597 CompositorKind::Native { .. } => {
2598 for sub_slice in &mut self.sub_slices {
2601 for tile in sub_slice.tiles.values_mut() {
2602 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::TextureCache { .. }, .. }) = tile.surface {
2603 tile.surface = None;
2604 tile.invalidate(None, InvalidationReason::CompositorKindChanged);
2606 }
2607 }
2608 }
2609 }
2610 }
2611
2612 world_culling_rect
2613 }
2614
2615 fn can_promote_to_surface(
2616 &mut self,
2617 prim_clip_chain: &ClipChainInstance,
2618 prim_spatial_node_index: SpatialNodeIndex,
2619 is_root_tile_cache: bool,
2620 sub_slice_index: usize,
2621 surface_kind: CompositorSurfaceKind,
2622 pic_coverage_rect: PictureRect,
2623 frame_context: &FrameVisibilityContext,
2624 ) -> Result<CompositorSurfaceKind, SurfacePromotionFailure> {
2625 use crate::picture::SurfacePromotionFailure::*;
2626
2627 match surface_kind {
2629 CompositorSurfaceKind::Overlay => {
2630 if sub_slice_index == self.sub_slices.len() - 1 {
2634 return Err(OverlaySurfaceLimit);
2635 }
2636
2637 if prim_clip_chain.needs_mask {
2640 return Err(OverlayNeedsMask);
2641 }
2642 }
2643 CompositorSurfaceKind::Underlay => {
2644 if prim_clip_chain.needs_mask {
2646 if !self.backdrop.opaque_rect.contains_box(&pic_coverage_rect) {
2650 return Err(UnderlayAlphaBackdrop);
2651 }
2652
2653 if !self.underlays.is_empty() {
2655 return Err(UnderlaySurfaceLimit);
2656 }
2657 }
2658
2659 if self.overlay_region.intersects(&pic_coverage_rect) {
2662 return Err(UnderlayIntersectsOverlay);
2663 }
2664
2665 if frame_context.config.low_quality_pinch_zoom &&
2669 frame_context.spatial_tree.get_spatial_node(prim_spatial_node_index).is_ancestor_or_self_zooming
2670 {
2671 return Err(UnderlayLowQualityZoom);
2672 }
2673 }
2674 CompositorSurfaceKind::Blit => unreachable!(),
2675 }
2676
2677 if !is_root_tile_cache {
2680 return Err(NotRootTileCache);
2681 }
2682
2683 let mapper : SpaceMapper<PicturePixel, WorldPixel> = SpaceMapper::new_with_target(
2684 frame_context.root_spatial_node_index,
2685 prim_spatial_node_index,
2686 frame_context.global_screen_world_rect,
2687 &frame_context.spatial_tree);
2688 let transform = mapper.get_transform();
2689 if !transform.is_2d_scale_translation() {
2690 return Err(ComplexTransform);
2691 }
2692
2693 if self.slice_flags.contains(SliceFlags::IS_ATOMIC) {
2694 return Err(SliceAtomic);
2695 }
2696
2697 Ok(surface_kind)
2698 }
2699
2700 fn setup_compositor_surfaces_yuv(
2701 &mut self,
2702 sub_slice_index: usize,
2703 prim_info: &mut PrimitiveDependencyInfo,
2704 flags: PrimitiveFlags,
2705 local_prim_rect: LayoutRect,
2706 prim_spatial_node_index: SpatialNodeIndex,
2707 pic_coverage_rect: PictureRect,
2708 frame_context: &FrameVisibilityContext,
2709 image_dependencies: &[ImageDependency;3],
2710 api_keys: &[ImageKey; 3],
2711 resource_cache: &mut ResourceCache,
2712 composite_state: &mut CompositeState,
2713 gpu_cache: &mut GpuCache,
2714 image_rendering: ImageRendering,
2715 color_depth: ColorDepth,
2716 color_space: YuvRangedColorSpace,
2717 format: YuvFormat,
2718 surface_kind: CompositorSurfaceKind,
2719 ) -> Result<CompositorSurfaceKind, SurfacePromotionFailure> {
2720 for &key in api_keys {
2721 if key != ImageKey::DUMMY {
2722 resource_cache.request_image(ImageRequest {
2724 key,
2725 rendering: image_rendering,
2726 tile: None,
2727 },
2728 gpu_cache,
2729 );
2730 }
2731 }
2732
2733 self.setup_compositor_surfaces_impl(
2734 sub_slice_index,
2735 prim_info,
2736 flags,
2737 local_prim_rect,
2738 prim_spatial_node_index,
2739 pic_coverage_rect,
2740 frame_context,
2741 ExternalSurfaceDependency::Yuv {
2742 image_dependencies: *image_dependencies,
2743 color_space,
2744 format,
2745 channel_bit_depth: color_depth.bit_depth(),
2746 },
2747 api_keys,
2748 resource_cache,
2749 composite_state,
2750 image_rendering,
2751 true,
2752 surface_kind,
2753 )
2754 }
2755
2756 fn setup_compositor_surfaces_rgb(
2757 &mut self,
2758 sub_slice_index: usize,
2759 prim_info: &mut PrimitiveDependencyInfo,
2760 flags: PrimitiveFlags,
2761 local_prim_rect: LayoutRect,
2762 prim_spatial_node_index: SpatialNodeIndex,
2763 pic_coverage_rect: PictureRect,
2764 frame_context: &FrameVisibilityContext,
2765 image_dependency: ImageDependency,
2766 api_key: ImageKey,
2767 resource_cache: &mut ResourceCache,
2768 composite_state: &mut CompositeState,
2769 gpu_cache: &mut GpuCache,
2770 image_rendering: ImageRendering,
2771 is_opaque: bool,
2772 surface_kind: CompositorSurfaceKind,
2773 ) -> Result<CompositorSurfaceKind, SurfacePromotionFailure> {
2774 let mut api_keys = [ImageKey::DUMMY; 3];
2775 api_keys[0] = api_key;
2776
2777 resource_cache.request_image(ImageRequest {
2784 key: api_key,
2785 rendering: image_rendering,
2786 tile: None,
2787 },
2788 gpu_cache,
2789 );
2790
2791 self.setup_compositor_surfaces_impl(
2792 sub_slice_index,
2793 prim_info,
2794 flags,
2795 local_prim_rect,
2796 prim_spatial_node_index,
2797 pic_coverage_rect,
2798 frame_context,
2799 ExternalSurfaceDependency::Rgb {
2800 image_dependency,
2801 },
2802 &api_keys,
2803 resource_cache,
2804 composite_state,
2805 image_rendering,
2806 is_opaque,
2807 surface_kind,
2808 )
2809 }
2810
2811 fn setup_compositor_surfaces_impl(
2814 &mut self,
2815 sub_slice_index: usize,
2816 prim_info: &mut PrimitiveDependencyInfo,
2817 flags: PrimitiveFlags,
2818 local_prim_rect: LayoutRect,
2819 prim_spatial_node_index: SpatialNodeIndex,
2820 pic_coverage_rect: PictureRect,
2821 frame_context: &FrameVisibilityContext,
2822 dependency: ExternalSurfaceDependency,
2823 api_keys: &[ImageKey; 3],
2824 resource_cache: &mut ResourceCache,
2825 composite_state: &mut CompositeState,
2826 image_rendering: ImageRendering,
2827 is_opaque: bool,
2828 surface_kind: CompositorSurfaceKind,
2829 ) -> Result<CompositorSurfaceKind, SurfacePromotionFailure> {
2830 use crate::picture::SurfacePromotionFailure::*;
2831
2832 let map_local_to_picture = SpaceMapper::new_with_target(
2833 self.spatial_node_index,
2834 prim_spatial_node_index,
2835 self.local_rect,
2836 frame_context.spatial_tree,
2837 );
2838
2839 let prim_rect = match map_local_to_picture.map(&local_prim_rect) {
2841 Some(rect) => rect,
2842 None => return Ok(surface_kind),
2843 };
2844
2845 if prim_rect.is_empty() {
2847 return Ok(surface_kind);
2848 }
2849
2850 let pic_to_world_mapper = SpaceMapper::new_with_target(
2851 frame_context.root_spatial_node_index,
2852 self.spatial_node_index,
2853 frame_context.global_screen_world_rect,
2854 frame_context.spatial_tree,
2855 );
2856
2857 let world_clip_rect = pic_to_world_mapper
2858 .map(&prim_info.prim_clip_box)
2859 .expect("bug: unable to map clip to world space");
2860
2861 let is_visible = world_clip_rect.intersects(&frame_context.global_screen_world_rect);
2862 if !is_visible {
2863 return Ok(surface_kind);
2864 }
2865
2866 let prim_offset = ScaleOffset::from_offset(local_prim_rect.min.to_vector().cast_unit());
2867
2868 let local_prim_to_device = get_relative_scale_offset(
2869 prim_spatial_node_index,
2870 frame_context.root_spatial_node_index,
2871 frame_context.spatial_tree,
2872 );
2873
2874 let normalized_prim_to_device = prim_offset.then(&local_prim_to_device);
2875
2876 let local_to_raster = ScaleOffset::identity();
2877 let raster_to_device = normalized_prim_to_device;
2878
2879 let mut external_image_id = if flags.contains(PrimitiveFlags::SUPPORTS_EXTERNAL_COMPOSITOR_SURFACE)
2883 && image_rendering == ImageRendering::Auto {
2884 resource_cache.get_image_properties(api_keys[0])
2885 .and_then(|properties| properties.external_image)
2886 .and_then(|image| Some(image.id))
2887 } else {
2888 None
2889 };
2890
2891
2892 if let CompositorKind::Native { capabilities, .. } = composite_state.compositor_kind {
2893 if external_image_id.is_some() &&
2894 !capabilities.supports_external_compositor_surface_negative_scaling &&
2895 (raster_to_device.scale.x < 0.0 || raster_to_device.scale.y < 0.0) {
2896 external_image_id = None;
2897 }
2898 }
2899
2900 let compositor_transform_index = composite_state.register_transform(
2901 local_to_raster,
2902 raster_to_device,
2903 );
2904
2905 let surface_size = composite_state.get_surface_rect(
2906 &local_prim_rect,
2907 &local_prim_rect,
2908 compositor_transform_index,
2909 ).size();
2910
2911 let clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round();
2912
2913 if surface_size.width >= MAX_COMPOSITOR_SURFACES_SIZE ||
2914 surface_size.height >= MAX_COMPOSITOR_SURFACES_SIZE {
2915 return Err(SizeTooLarge);
2916 }
2917
2918 let (native_surface_id, update_params) = match composite_state.compositor_kind {
2923 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
2924 (None, None)
2925 }
2926 CompositorKind::Native { .. } => {
2927 let native_surface_size = surface_size.to_i32();
2928
2929 let key = ExternalNativeSurfaceKey {
2930 image_keys: *api_keys,
2931 size: if external_image_id.is_some() { None } else { Some(native_surface_size) },
2932 };
2933
2934 let native_surface = self.external_native_surface_cache
2935 .entry(key)
2936 .or_insert_with(|| {
2937 let native_surface_id = match external_image_id {
2939 Some(_external_image) => {
2940 resource_cache.create_compositor_external_surface(is_opaque)
2943 }
2944 None => {
2945 let native_surface_id =
2948 resource_cache.create_compositor_surface(
2949 DeviceIntPoint::zero(),
2950 native_surface_size,
2951 is_opaque,
2952 );
2953
2954 let tile_id = NativeTileId {
2955 surface_id: native_surface_id,
2956 x: 0,
2957 y: 0,
2958 };
2959 resource_cache.create_compositor_tile(tile_id);
2960
2961 native_surface_id
2962 }
2963 };
2964
2965 ExternalNativeSurface {
2966 used_this_frame: true,
2967 native_surface_id,
2968 image_dependencies: [ImageDependency::INVALID; 3],
2969 }
2970 });
2971
2972 native_surface.used_this_frame = true;
2975
2976 let update_params = match external_image_id {
2977 Some(external_image) => {
2978 resource_cache.attach_compositor_external_image(
2982 native_surface.native_surface_id,
2983 external_image,
2984 );
2985 None
2986 }
2987 None => {
2988 match dependency {
2991 ExternalSurfaceDependency::Yuv{ image_dependencies, .. } => {
2992 if image_dependencies == native_surface.image_dependencies {
2993 None
2994 } else {
2995 Some(native_surface_size)
2996 }
2997 },
2998 ExternalSurfaceDependency::Rgb{ image_dependency, .. } => {
2999 if image_dependency == native_surface.image_dependencies[0] {
3000 None
3001 } else {
3002 Some(native_surface_size)
3003 }
3004 },
3005 }
3006 }
3007 };
3008
3009 (Some(native_surface.native_surface_id), update_params)
3010 }
3011 };
3012
3013 let descriptor = ExternalSurfaceDescriptor {
3014 local_surface_size: local_prim_rect.size(),
3015 local_rect: prim_rect,
3016 local_clip_rect: prim_info.prim_clip_box,
3017 dependency,
3018 image_rendering,
3019 clip_rect,
3020 transform_index: compositor_transform_index,
3021 z_id: ZBufferId::invalid(),
3022 native_surface_id,
3023 update_params,
3024 external_image_id,
3025 };
3026
3027 match surface_kind {
3030 CompositorSurfaceKind::Underlay => {
3031 self.underlays.push(descriptor);
3032 }
3033 CompositorSurfaceKind::Overlay => {
3034 assert!(sub_slice_index < self.sub_slices.len() - 1);
3037 let sub_slice = &mut self.sub_slices[sub_slice_index];
3038
3039 sub_slice.compositor_surfaces.push(CompositorSurface {
3041 prohibited_rect: pic_coverage_rect,
3042 is_opaque,
3043 descriptor,
3044 });
3045
3046 self.overlay_region = self.overlay_region.union(&pic_coverage_rect);
3050 }
3051 CompositorSurfaceKind::Blit => unreachable!(),
3052 }
3053
3054 Ok(surface_kind)
3055 }
3056
3057 pub fn push_surface(
3063 &mut self,
3064 estimated_local_rect: LayoutRect,
3065 surface_spatial_node_index: SpatialNodeIndex,
3066 spatial_tree: &SpatialTree,
3067 ) {
3068 if self.current_surface_traversal_depth == 0 && self.sub_slices.len() > 1 {
3070 let map_local_to_picture = SpaceMapper::new_with_target(
3071 self.spatial_node_index,
3072 surface_spatial_node_index,
3073 self.local_rect,
3074 spatial_tree,
3075 );
3076
3077 if let Some(pic_rect) = map_local_to_picture.map(&estimated_local_rect) {
3078 for sub_slice in &mut self.sub_slices {
3081 let mut intersects_prohibited_region = false;
3082
3083 for surface in &mut sub_slice.compositor_surfaces {
3084 if pic_rect.intersects(&surface.prohibited_rect) {
3085 surface.prohibited_rect = surface.prohibited_rect.union(&pic_rect);
3086
3087 intersects_prohibited_region = true;
3088 }
3089 }
3090
3091 if !intersects_prohibited_region {
3092 break;
3093 }
3094 }
3095 }
3096 }
3097
3098 self.current_surface_traversal_depth += 1;
3099 }
3100
3101 pub fn pop_surface(&mut self) {
3103 self.current_surface_traversal_depth -= 1;
3104 }
3105
3106 fn maybe_report_promotion_failure(&self,
3107 result: Result<CompositorSurfaceKind, SurfacePromotionFailure>,
3108 rect: PictureRect,
3109 reported: &mut bool) {
3110 if !self.debug_flags.contains(DebugFlags::SURFACE_PROMOTION_LOGGING) || result.is_ok() || *reported {
3111 return;
3112 }
3113
3114 warn!("Surface promotion of prim at {:?} failed with: {}.", rect, result.unwrap_err());
3117 *reported = true;
3118 }
3119
3120 pub fn update_prim_dependencies(
3122 &mut self,
3123 prim_instance: &mut PrimitiveInstance,
3124 prim_spatial_node_index: SpatialNodeIndex,
3125 local_prim_rect: LayoutRect,
3126 frame_context: &FrameVisibilityContext,
3127 data_stores: &DataStores,
3128 clip_store: &ClipStore,
3129 pictures: &[PicturePrimitive],
3130 resource_cache: &mut ResourceCache,
3131 color_bindings: &ColorBindingStorage,
3132 surface_stack: &[(PictureIndex, SurfaceIndex)],
3133 composite_state: &mut CompositeState,
3134 gpu_cache: &mut GpuCache,
3135 scratch: &mut PrimitiveScratchBuffer,
3136 is_root_tile_cache: bool,
3137 surfaces: &mut [SurfaceInfo],
3138 profile: &mut TransactionProfile,
3139 ) -> VisibilityState {
3140 use crate::picture::SurfacePromotionFailure::*;
3141
3142 profile_scope!("update_prim_dependencies");
3144 let prim_surface_index = surface_stack.last().unwrap().1;
3145 let prim_clip_chain = &prim_instance.vis.clip_chain;
3146
3147 let on_picture_surface = prim_surface_index == self.surface_index;
3151 let pic_coverage_rect = if on_picture_surface {
3152 prim_clip_chain.pic_coverage_rect
3153 } else {
3154 let mut current_pic_coverage_rect = prim_clip_chain.pic_coverage_rect;
3162 let mut current_spatial_node_index = surfaces[prim_surface_index.0]
3163 .surface_spatial_node_index;
3164
3165 for (pic_index, surface_index) in surface_stack.iter().rev() {
3166 let surface = &surfaces[surface_index.0];
3167 let pic = &pictures[pic_index.0];
3168
3169 let map_local_to_parent = SpaceMapper::new_with_target(
3170 surface.surface_spatial_node_index,
3171 current_spatial_node_index,
3172 surface.unclipped_local_rect,
3173 frame_context.spatial_tree,
3174 );
3175
3176 current_pic_coverage_rect = match map_local_to_parent.map(¤t_pic_coverage_rect) {
3180 Some(rect) => {
3181 pic.composite_mode.as_ref().unwrap().get_coverage(
3187 surface,
3188 Some(rect.cast_unit()),
3189 ).cast_unit()
3190 }
3191 None => {
3192 return VisibilityState::Culled;
3193 }
3194 };
3195
3196 current_spatial_node_index = surface.surface_spatial_node_index;
3197 }
3198
3199 current_pic_coverage_rect
3200 };
3201
3202 let (p0, p1) = self.get_tile_coords_for_rect(&pic_coverage_rect);
3204
3205 if p0.x == p1.x || p0.y == p1.y {
3208 return VisibilityState::Culled;
3209 }
3210
3211 let mut prim_info = PrimitiveDependencyInfo::new(
3213 prim_instance.uid(),
3214 pic_coverage_rect,
3215 );
3216
3217 let mut sub_slice_index = self.sub_slices.len() - 1;
3218
3219 if sub_slice_index > 0 {
3221 for (i, sub_slice) in self.sub_slices.iter_mut().enumerate() {
3224 let mut intersects_prohibited_region = false;
3225
3226 for surface in &mut sub_slice.compositor_surfaces {
3227 if pic_coverage_rect.intersects(&surface.prohibited_rect) {
3228 surface.prohibited_rect = surface.prohibited_rect.union(&pic_coverage_rect);
3229
3230 intersects_prohibited_region = true;
3231 }
3232 }
3233
3234 if !intersects_prohibited_region {
3235 sub_slice_index = i;
3236 break;
3237 }
3238 }
3239 }
3240
3241 if prim_spatial_node_index != self.spatial_node_index {
3243 prim_info.spatial_nodes.push(prim_spatial_node_index);
3244 }
3245
3246 let clip_instances = &clip_store
3248 .clip_node_instances[prim_clip_chain.clips_range.to_range()];
3249 for clip_instance in clip_instances {
3250 let clip = &data_stores.clip[clip_instance.handle];
3251
3252 prim_info.clips.push(clip_instance.handle.uid());
3253
3254 if clip.item.spatial_node_index != self.spatial_node_index
3257 && !prim_info.spatial_nodes.contains(&clip.item.spatial_node_index) {
3258 prim_info.spatial_nodes.push(clip.item.spatial_node_index);
3259 }
3260 }
3261
3262 let mut backdrop_candidate = None;
3265
3266 let mut promotion_result: Result<CompositorSurfaceKind, SurfacePromotionFailure> = Ok(CompositorSurfaceKind::Blit);
3278 let mut promotion_failure_reported = false;
3279 match prim_instance.kind {
3280 PrimitiveInstanceKind::Picture { pic_index,.. } => {
3281 let pic = &pictures[pic_index.0];
3283 if let Some(PictureCompositeMode::Filter(Filter::Opacity(binding, _))) = pic.composite_mode {
3284 prim_info.opacity_bindings.push(binding.into());
3285 }
3286 }
3287 PrimitiveInstanceKind::Rectangle { data_handle, color_binding_index, .. } => {
3288 let color = match data_stores.prim[data_handle].kind {
3292 PrimitiveTemplateKind::Rectangle { color, .. } => {
3293 frame_context.scene_properties.resolve_color(&color)
3294 }
3295 _ => unreachable!(),
3296 };
3297 if color.a >= 1.0 {
3298 backdrop_candidate = Some(BackdropInfo {
3299 opaque_rect: pic_coverage_rect,
3300 spanning_opaque_color: None,
3301 kind: Some(BackdropKind::Color { color }),
3302 backdrop_rect: pic_coverage_rect,
3303 });
3304 }
3305
3306 if color_binding_index != ColorBindingIndex::INVALID {
3307 prim_info.color_binding = Some(color_bindings[color_binding_index].into());
3308 }
3309 }
3310 PrimitiveInstanceKind::Image { data_handle, ref mut compositor_surface_kind, .. } => {
3311 let image_key = &data_stores.image[data_handle];
3312 let image_data = &image_key.kind;
3313
3314 let mut is_opaque = false;
3319
3320 if let Some(image_properties) = resource_cache.get_image_properties(image_data.key) {
3321 if image_properties.descriptor.is_opaque() &&
3327 image_properties.tiling.is_none() &&
3328 image_data.tile_spacing == LayoutSize::zero() &&
3329 image_data.color.a >= 1.0 {
3330 backdrop_candidate = Some(BackdropInfo {
3331 opaque_rect: pic_coverage_rect,
3332 spanning_opaque_color: None,
3333 kind: None,
3334 backdrop_rect: PictureRect::zero(),
3335 });
3336 }
3337
3338 is_opaque = image_properties.descriptor.is_opaque();
3339 }
3340
3341 if image_key.common.flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
3342 if self.yuv_images_remaining > 0 {
3345 promotion_result = Err(ImageWaitingOnYuvImage);
3346 } else {
3347 promotion_result = self.can_promote_to_surface(prim_clip_chain,
3348 prim_spatial_node_index,
3349 is_root_tile_cache,
3350 sub_slice_index,
3351 CompositorSurfaceKind::Overlay,
3352 pic_coverage_rect,
3353 frame_context);
3354 }
3355
3356 if image_data.alpha_type == AlphaType::Alpha {
3359 promotion_result = Err(NotPremultipliedAlpha);
3360 }
3361
3362 if let Ok(kind) = promotion_result {
3363 promotion_result = self.setup_compositor_surfaces_rgb(
3364 sub_slice_index,
3365 &mut prim_info,
3366 image_key.common.flags,
3367 local_prim_rect,
3368 prim_spatial_node_index,
3369 pic_coverage_rect,
3370 frame_context,
3371 ImageDependency {
3372 key: image_data.key,
3373 generation: resource_cache.get_image_generation(image_data.key),
3374 },
3375 image_data.key,
3376 resource_cache,
3377 composite_state,
3378 gpu_cache,
3379 image_data.image_rendering,
3380 is_opaque,
3381 kind,
3382 );
3383 }
3384 }
3385
3386 if let Ok(kind) = promotion_result {
3387 *compositor_surface_kind = kind;
3388
3389 if kind == CompositorSurfaceKind::Overlay {
3390 profile.inc(profiler::COMPOSITOR_SURFACE_OVERLAYS);
3391 return VisibilityState::Culled;
3392 }
3393
3394 assert!(kind == CompositorSurfaceKind::Blit, "Image prims should either be overlays or blits.");
3395 } else {
3396 *compositor_surface_kind = CompositorSurfaceKind::Blit;
3398 }
3399
3400 if image_key.common.flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
3401 profile.inc(profiler::COMPOSITOR_SURFACE_BLITS);
3402 }
3403
3404 prim_info.images.push(ImageDependency {
3405 key: image_data.key,
3406 generation: resource_cache.get_image_generation(image_data.key),
3407 });
3408 }
3409 PrimitiveInstanceKind::YuvImage { data_handle, ref mut compositor_surface_kind, .. } => {
3410 let prim_data = &data_stores.yuv_image[data_handle];
3411
3412 if prim_data.common.flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
3413 if is_root_tile_cache {
3419 self.yuv_images_remaining -= 1;
3420 }
3421
3422 let clip_on_top = prim_clip_chain.needs_mask;
3423 let prefer_underlay = clip_on_top || !cfg!(target_os = "macos");
3424 let promotion_attempts = if prefer_underlay {
3425 [CompositorSurfaceKind::Underlay, CompositorSurfaceKind::Overlay]
3426 } else {
3427 [CompositorSurfaceKind::Overlay, CompositorSurfaceKind::Underlay]
3428 };
3429
3430 for kind in promotion_attempts {
3431 promotion_failure_reported = false;
3434 promotion_result = self.can_promote_to_surface(
3435 prim_clip_chain,
3436 prim_spatial_node_index,
3437 is_root_tile_cache,
3438 sub_slice_index,
3439 kind,
3440 pic_coverage_rect,
3441 frame_context);
3442 if promotion_result.is_ok() {
3443 break;
3444 }
3445
3446 if let Err(SliceAtomic) = promotion_result {
3451 if prim_data.kind. color_depth != ColorDepth::Color8 {
3452 promotion_result = Ok(kind);
3454 break;
3455 }
3456 }
3457
3458 self.maybe_report_promotion_failure(promotion_result, pic_coverage_rect, &mut promotion_failure_reported);
3459 }
3460
3461 if let Ok(kind) = promotion_result {
3470 let mut image_dependencies = [ImageDependency::INVALID; 3];
3473 for (key, dep) in prim_data.kind.yuv_key.iter().cloned().zip(image_dependencies.iter_mut()) {
3474 *dep = ImageDependency {
3475 key,
3476 generation: resource_cache.get_image_generation(key),
3477 }
3478 }
3479
3480 promotion_result = self.setup_compositor_surfaces_yuv(
3481 sub_slice_index,
3482 &mut prim_info,
3483 prim_data.common.flags,
3484 local_prim_rect,
3485 prim_spatial_node_index,
3486 pic_coverage_rect,
3487 frame_context,
3488 &image_dependencies,
3489 &prim_data.kind.yuv_key,
3490 resource_cache,
3491 composite_state,
3492 gpu_cache,
3493 prim_data.kind.image_rendering,
3494 prim_data.kind.color_depth,
3495 prim_data.kind.color_space.with_range(prim_data.kind.color_range),
3496 prim_data.kind.format,
3497 kind,
3498 );
3499 }
3500 }
3501
3502 if let Ok(kind) = promotion_result {
3506 *compositor_surface_kind = kind;
3507 if kind == CompositorSurfaceKind::Overlay {
3508 profile.inc(profiler::COMPOSITOR_SURFACE_OVERLAYS);
3509 return VisibilityState::Culled;
3510 }
3511
3512 profile.inc(profiler::COMPOSITOR_SURFACE_UNDERLAYS);
3513 } else {
3514 *compositor_surface_kind = CompositorSurfaceKind::Blit;
3516 if prim_data.common.flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
3517 profile.inc(profiler::COMPOSITOR_SURFACE_BLITS);
3518 }
3519 }
3520
3521 if *compositor_surface_kind == CompositorSurfaceKind::Blit {
3522 prim_info.images.extend(
3523 prim_data.kind.yuv_key.iter().map(|key| {
3524 ImageDependency {
3525 key: *key,
3526 generation: resource_cache.get_image_generation(*key),
3527 }
3528 })
3529 );
3530 }
3531 }
3532 PrimitiveInstanceKind::ImageBorder { data_handle, .. } => {
3533 let border_data = &data_stores.image_border[data_handle].kind;
3534 prim_info.images.push(ImageDependency {
3535 key: border_data.request.key,
3536 generation: resource_cache.get_image_generation(border_data.request.key),
3537 });
3538 }
3539 PrimitiveInstanceKind::Clear { .. } => {
3540 backdrop_candidate = Some(BackdropInfo {
3541 opaque_rect: pic_coverage_rect,
3542 spanning_opaque_color: None,
3543 kind: Some(BackdropKind::Clear),
3544 backdrop_rect: pic_coverage_rect,
3545 });
3546 }
3547 PrimitiveInstanceKind::LinearGradient { data_handle, .. }
3548 | PrimitiveInstanceKind::CachedLinearGradient { data_handle, .. } => {
3549 let gradient_data = &data_stores.linear_grad[data_handle];
3550 if gradient_data.stops_opacity.is_opaque
3551 && gradient_data.tile_spacing == LayoutSize::zero()
3552 {
3553 backdrop_candidate = Some(BackdropInfo {
3554 opaque_rect: pic_coverage_rect,
3555 spanning_opaque_color: None,
3556 kind: None,
3557 backdrop_rect: PictureRect::zero(),
3558 });
3559 }
3560 }
3561 PrimitiveInstanceKind::ConicGradient { data_handle, .. } => {
3562 let gradient_data = &data_stores.conic_grad[data_handle];
3563 if gradient_data.stops_opacity.is_opaque
3564 && gradient_data.tile_spacing == LayoutSize::zero()
3565 {
3566 backdrop_candidate = Some(BackdropInfo {
3567 opaque_rect: pic_coverage_rect,
3568 spanning_opaque_color: None,
3569 kind: None,
3570 backdrop_rect: PictureRect::zero(),
3571 });
3572 }
3573 }
3574 PrimitiveInstanceKind::RadialGradient { data_handle, .. } => {
3575 let gradient_data = &data_stores.radial_grad[data_handle];
3576 if gradient_data.stops_opacity.is_opaque
3577 && gradient_data.tile_spacing == LayoutSize::zero()
3578 {
3579 backdrop_candidate = Some(BackdropInfo {
3580 opaque_rect: pic_coverage_rect,
3581 spanning_opaque_color: None,
3582 kind: None,
3583 backdrop_rect: PictureRect::zero(),
3584 });
3585 }
3586 }
3587 PrimitiveInstanceKind::BackdropCapture { .. } => {}
3588 PrimitiveInstanceKind::BackdropRender { pic_index, .. } => {
3589 if !pic_coverage_rect.is_empty() {
3595 scratch.required_sub_graphs.insert(pic_index);
3598
3599 let sub_slice = &mut self.sub_slices[sub_slice_index];
3602
3603 let mut surface_info = Vec::new();
3604 for (pic_index, surface_index) in surface_stack.iter().rev() {
3605 let pic = &pictures[pic_index.0];
3606 surface_info.push((pic.composite_mode.as_ref().unwrap().clone(), *surface_index));
3607 }
3608
3609 for y in p0.y .. p1.y {
3610 for x in p0.x .. p1.x {
3611 let key = TileOffset::new(x, y);
3612 let tile = sub_slice.tiles.get_mut(&key).expect("bug: no tile");
3613 tile.sub_graphs.push((pic_coverage_rect, surface_info.clone()));
3614 }
3615 }
3616
3617 self.deferred_dirty_tests.push(DeferredDirtyTest {
3620 tile_rect: TileRect::new(p0, p1),
3621 prim_rect: pic_coverage_rect,
3622 });
3623 }
3624 }
3625 PrimitiveInstanceKind::LineDecoration { .. } |
3626 PrimitiveInstanceKind::NormalBorder { .. } |
3627 PrimitiveInstanceKind::BoxShadow { .. } |
3628 PrimitiveInstanceKind::TextRun { .. } => {
3629 }
3631 };
3632
3633 self.maybe_report_promotion_failure(promotion_result, pic_coverage_rect, &mut promotion_failure_reported);
3634
3635 let visible_local_clip_rect = self.local_clip_rect.intersection(&self.screen_rect_in_pic_space).unwrap_or_default();
3639 if pic_coverage_rect.intersects(&visible_local_clip_rect) {
3640 self.found_prims_after_backdrop = true;
3641 }
3642
3643 let mut vis_flags = PrimitiveVisibilityFlags::empty();
3646 let sub_slice = &mut self.sub_slices[sub_slice_index];
3647 if let Some(mut backdrop_candidate) = backdrop_candidate {
3648 match backdrop_candidate.kind {
3653 Some(BackdropKind::Color { .. }) | None => {
3654 let surface = &mut surfaces[prim_surface_index.0];
3655
3656 let is_same_coord_system = frame_context.spatial_tree.is_matching_coord_system(
3657 prim_spatial_node_index,
3658 surface.surface_spatial_node_index,
3659 );
3660
3661 if is_same_coord_system &&
3666 !prim_clip_chain.needs_mask &&
3667 prim_clip_chain.pic_coverage_rect.contains_box(&surface.unclipped_local_rect)
3668 {
3669 surface.is_opaque = true;
3674 }
3675 }
3676 Some(BackdropKind::Clear) => {}
3677 }
3678
3679 let is_suitable_backdrop = match backdrop_candidate.kind {
3680 Some(BackdropKind::Clear) => {
3681 true
3686 }
3687 Some(BackdropKind::Color { .. }) | None => {
3688 let same_coord_system = frame_context.spatial_tree.is_matching_coord_system(
3697 prim_spatial_node_index,
3698 self.spatial_node_index,
3699 );
3700
3701 same_coord_system && on_picture_surface
3702 }
3703 };
3704
3705 if sub_slice_index == 0 &&
3706 is_suitable_backdrop &&
3707 sub_slice.compositor_surfaces.is_empty() {
3708
3709 if prim_clip_chain.needs_mask {
3712 backdrop_candidate.opaque_rect = clip_store
3713 .get_inner_rect_for_clip_chain(
3714 prim_clip_chain,
3715 &data_stores.clip,
3716 frame_context.spatial_tree,
3717 )
3718 .unwrap_or(PictureRect::zero());
3719 }
3720
3721 if backdrop_candidate.opaque_rect.contains_box(&self.backdrop.opaque_rect) {
3725 self.backdrop.opaque_rect = backdrop_candidate.opaque_rect;
3726 }
3727
3728 if let Some(kind) = backdrop_candidate.kind {
3729 if backdrop_candidate.opaque_rect.contains_box(&visible_local_clip_rect) {
3730 self.found_prims_after_backdrop = false;
3731 self.backdrop.kind = Some(kind);
3732 self.backdrop.backdrop_rect = backdrop_candidate.opaque_rect;
3733
3734 if let BackdropKind::Color { color } = kind {
3740 if backdrop_candidate.opaque_rect.contains_box(&self.local_rect) {
3741 vis_flags |= PrimitiveVisibilityFlags::IS_BACKDROP;
3742 self.backdrop.spanning_opaque_color = Some(color);
3743 }
3744 }
3745 }
3746 }
3747 }
3748 }
3749
3750 for spatial_node_index in &prim_info.spatial_nodes {
3752 self.spatial_node_comparer.register_used_transform(
3753 *spatial_node_index,
3754 self.frame_id,
3755 frame_context.spatial_tree,
3756 );
3757 }
3758
3759 for y in p0.y .. p1.y {
3762 for x in p0.x .. p1.x {
3763 let key = TileOffset::new(x, y);
3765 let tile = sub_slice.tiles.get_mut(&key).expect("bug: no tile");
3766
3767 tile.add_prim_dependency(&prim_info);
3768 }
3769 }
3770
3771 VisibilityState::Visible {
3772 vis_flags,
3773 sub_slice_index: SubSliceIndex::new(sub_slice_index),
3774 }
3775 }
3776
3777 fn print(&self) {
3779 let mut pt = PrintTree::new("Picture Cache");
3785
3786 pt.new_level(format!("Slice {:?}", self.slice));
3787
3788 pt.add_item(format!("background_color: {:?}", self.background_color));
3789
3790 for (sub_slice_index, sub_slice) in self.sub_slices.iter().enumerate() {
3791 pt.new_level(format!("SubSlice {:?}", sub_slice_index));
3792
3793 for y in self.tile_bounds_p0.y .. self.tile_bounds_p1.y {
3794 for x in self.tile_bounds_p0.x .. self.tile_bounds_p1.x {
3795 let key = TileOffset::new(x, y);
3796 let tile = &sub_slice.tiles[&key];
3797 tile.print(&mut pt);
3798 }
3799 }
3800
3801 pt.end_level();
3802 }
3803
3804 pt.end_level();
3805 }
3806
3807 fn calculate_subpixel_mode(&self) -> SubpixelMode {
3808 if self.underlays.is_empty() {
3810 let has_opaque_bg_color = self.background_color.map_or(false, |c| c.a >= 1.0);
3811
3812 if has_opaque_bg_color {
3814 return SubpixelMode::Allow;
3815 }
3816
3817 if self.backdrop.opaque_rect.contains_box(&self.local_rect) {
3821 return SubpixelMode::Allow;
3822 }
3823 }
3824
3825 if self.backdrop.opaque_rect.is_empty() {
3827 return SubpixelMode::Deny;
3828 }
3829
3830 let prohibited_rect = self
3836 .underlays
3837 .iter()
3838 .fold(
3839 PictureRect::zero(),
3840 |acc, underlay| {
3841 acc.union(&underlay.local_rect)
3842 }
3843 );
3844
3845 SubpixelMode::Conditional {
3853 allowed_rect: self.backdrop.opaque_rect,
3854 prohibited_rect,
3855 }
3856 }
3857
3858 pub fn post_update(
3862 &mut self,
3863 frame_context: &FrameVisibilityContext,
3864 composite_state: &mut CompositeState,
3865 resource_cache: &mut ResourceCache,
3866 ) {
3867 assert!(self.current_surface_traversal_depth == 0);
3868
3869 let visibility_node = frame_context.spatial_tree.root_reference_frame_index();
3871
3872 self.dirty_region.reset(visibility_node, self.spatial_node_index);
3873 self.subpixel_mode = self.calculate_subpixel_mode();
3874
3875 self.transform_index = composite_state.register_transform(
3876 self.local_to_raster,
3877 self.raster_to_device,
3880 );
3881
3882 let map_pic_to_world = SpaceMapper::new_with_target(
3883 frame_context.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 composite_state.dirty_rects_are_valid = false;
3896
3897 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 frame_context.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 ctx = TileUpdateDirtyContext {
3911 pic_to_world_mapper,
3912 global_device_pixel_scale: frame_context.global_device_pixel_scale,
3913 opacity_bindings: &self.opacity_bindings,
3914 color_bindings: &self.color_bindings,
3915 local_rect: self.local_rect,
3916 invalidate_all: self.invalidate_all_tiles,
3917 };
3918
3919 let mut state = TileUpdateDirtyState {
3920 resource_cache,
3921 composite_state,
3922 compare_cache: &mut self.compare_cache,
3923 spatial_node_comparer: &mut self.spatial_node_comparer,
3924 };
3925
3926 for sub_slice in &mut self.sub_slices {
3929 for tile in sub_slice.tiles.values_mut() {
3930 tile.update_dirty_and_valid_rects(&ctx, &mut state, frame_context);
3931 }
3932 }
3933
3934 for sub_slice in &mut self.sub_slices {
3936 for dirty_test in self.deferred_dirty_tests.drain(..) {
3937 let mut total_dirty_rect = PictureRect::zero();
3939
3940 for y in dirty_test.tile_rect.min.y .. dirty_test.tile_rect.max.y {
3941 for x in dirty_test.tile_rect.min.x .. dirty_test.tile_rect.max.x {
3942 let key = TileOffset::new(x, y);
3943 let tile = sub_slice.tiles.get_mut(&key).expect("bug: no tile");
3944 total_dirty_rect = total_dirty_rect.union(&tile.local_dirty_rect);
3945 }
3946 }
3947
3948 if total_dirty_rect.intersects(&dirty_test.prim_rect) {
3956 for y in dirty_test.tile_rect.min.y .. dirty_test.tile_rect.max.y {
3957 for x in dirty_test.tile_rect.min.x .. dirty_test.tile_rect.max.x {
3958 let key = TileOffset::new(x, y);
3959 let tile = sub_slice.tiles.get_mut(&key).expect("bug: no tile");
3960 tile.invalidate(
3961 Some(dirty_test.prim_rect),
3962 InvalidationReason::SurfaceContentChanged,
3963 );
3964 }
3965 }
3966 }
3967 }
3968 }
3969
3970 let mut ctx = TilePostUpdateContext {
3971 local_clip_rect: self.local_clip_rect,
3972 backdrop: None,
3973 current_tile_size: self.current_tile_size,
3974 z_id: ZBufferId::invalid(),
3975 underlays: &self.underlays,
3976 };
3977
3978 let mut state = TilePostUpdateState {
3979 resource_cache,
3980 composite_state,
3981 };
3982
3983 for (i, sub_slice) in self.sub_slices.iter_mut().enumerate().rev() {
3984 if i == 0 {
3986 ctx.backdrop = Some(self.backdrop);
3987 }
3988
3989 for compositor_surface in sub_slice.compositor_surfaces.iter_mut().rev() {
3990 compositor_surface.descriptor.z_id = state.composite_state.z_generator.next();
3991 }
3992
3993 ctx.z_id = state.composite_state.z_generator.next();
3994
3995 for tile in sub_slice.tiles.values_mut() {
3996 tile.post_update(&ctx, &mut state, frame_context);
3997 }
3998 }
3999
4000 for underlay in self.underlays.iter_mut().rev() {
4002 underlay.z_id = state.composite_state.z_generator.next();
4003 }
4004
4005 for underlay in &self.underlays {
4012 if let Some(world_surface_rect) = underlay.get_occluder_rect(
4013 &self.local_clip_rect,
4014 &map_pic_to_world,
4015 ) {
4016 composite_state.register_occluder(
4017 underlay.z_id,
4018 world_surface_rect,
4019 self.compositor_clip,
4020 );
4021 }
4022 }
4023
4024 for sub_slice in &self.sub_slices {
4025 for compositor_surface in &sub_slice.compositor_surfaces {
4026 if compositor_surface.is_opaque {
4027 if let Some(world_surface_rect) = compositor_surface.descriptor.get_occluder_rect(
4028 &self.local_clip_rect,
4029 &map_pic_to_world,
4030 ) {
4031 composite_state.register_occluder(
4032 compositor_surface.descriptor.z_id,
4033 world_surface_rect,
4034 self.compositor_clip,
4035 );
4036 }
4037 }
4038 }
4039 }
4040
4041 if !self.backdrop.opaque_rect.is_empty() {
4044 let z_id_backdrop = composite_state.z_generator.next();
4045
4046 let backdrop_rect = self.backdrop.opaque_rect
4047 .intersection(&self.local_rect)
4048 .and_then(|r| {
4049 r.intersection(&self.local_clip_rect)
4050 });
4051
4052 if let Some(backdrop_rect) = backdrop_rect {
4053 let world_backdrop_rect = map_pic_to_world
4054 .map(&backdrop_rect)
4055 .expect("bug: unable to map backdrop to world space");
4056
4057 composite_state.register_occluder(
4060 z_id_backdrop,
4061 world_backdrop_rect,
4062 self.compositor_clip,
4063 );
4064 }
4065 }
4066 }
4067}
4068
4069pub struct PictureScratchBuffer {
4070 surface_stack: Vec<SurfaceIndex>,
4071}
4072
4073impl Default for PictureScratchBuffer {
4074 fn default() -> Self {
4075 PictureScratchBuffer {
4076 surface_stack: Vec::new(),
4077 }
4078 }
4079}
4080
4081impl PictureScratchBuffer {
4082 pub fn begin_frame(&mut self) {
4083 self.surface_stack.clear();
4084 }
4085
4086 pub fn recycle(&mut self, recycler: &mut Recycler) {
4087 recycler.recycle_vec(&mut self.surface_stack);
4088 }
4089}
4090
4091#[derive(Debug, Copy, Clone, PartialEq)]
4092#[cfg_attr(feature = "capture", derive(Serialize))]
4093#[cfg_attr(feature = "replay", derive(Deserialize))]
4094pub struct SurfaceIndex(pub usize);
4095
4096pub struct SurfaceInfo {
4103 pub unclipped_local_rect: PictureRect,
4107 pub clipped_local_rect: PictureRect,
4110 pub clipping_rect: PictureRect,
4113 pub culling_rect: VisRect,
4115 pub map_local_to_picture: SpaceMapper<LayoutPixel, PicturePixel>,
4118 pub surface_spatial_node_index: SpatialNodeIndex,
4120 pub raster_spatial_node_index: SpatialNodeIndex,
4122 pub visibility_spatial_node_index: SpatialNodeIndex,
4125 pub device_pixel_scale: DevicePixelScale,
4127 pub world_scale_factors: (f32, f32),
4129 pub local_scale: (f32, f32),
4131 pub is_opaque: bool,
4133 pub allow_snapping: bool,
4135 pub force_scissor_rect: bool,
4137}
4138
4139impl SurfaceInfo {
4140 pub fn new(
4141 surface_spatial_node_index: SpatialNodeIndex,
4142 raster_spatial_node_index: SpatialNodeIndex,
4143 world_rect: WorldRect,
4144 spatial_tree: &SpatialTree,
4145 device_pixel_scale: DevicePixelScale,
4146 world_scale_factors: (f32, f32),
4147 local_scale: (f32, f32),
4148 allow_snapping: bool,
4149 force_scissor_rect: bool,
4150 ) -> Self {
4151 let map_surface_to_world = SpaceMapper::new_with_target(
4152 spatial_tree.root_reference_frame_index(),
4153 surface_spatial_node_index,
4154 world_rect,
4155 spatial_tree,
4156 );
4157
4158 let pic_bounds = map_surface_to_world
4159 .unmap(&map_surface_to_world.bounds)
4160 .unwrap_or_else(PictureRect::max_rect);
4161
4162 let map_local_to_picture = SpaceMapper::new(
4163 surface_spatial_node_index,
4164 pic_bounds,
4165 );
4166
4167 let visibility_spatial_node_index = spatial_tree.root_reference_frame_index();
4169
4170 SurfaceInfo {
4171 unclipped_local_rect: PictureRect::zero(),
4172 clipped_local_rect: PictureRect::zero(),
4173 is_opaque: false,
4174 clipping_rect: PictureRect::zero(),
4175 map_local_to_picture,
4176 raster_spatial_node_index,
4177 surface_spatial_node_index,
4178 visibility_spatial_node_index,
4179 device_pixel_scale,
4180 world_scale_factors,
4181 local_scale,
4182 allow_snapping,
4183 force_scissor_rect,
4184 culling_rect: world_rect.cast_unit(),
4187 }
4188 }
4189
4190 pub fn clamp_blur_radius(
4192 &self,
4193 x_blur_radius: f32,
4194 y_blur_radius: f32,
4195 ) -> (f32, f32) {
4196 let sx_blur_radius = x_blur_radius * self.local_scale.0;
4201 let sy_blur_radius = y_blur_radius * self.local_scale.1;
4202
4203 let largest_scaled_blur_radius = f32::max(
4204 sx_blur_radius * self.world_scale_factors.0,
4205 sy_blur_radius * self.world_scale_factors.1,
4206 );
4207
4208 if largest_scaled_blur_radius > MAX_BLUR_RADIUS {
4209 let sf = MAX_BLUR_RADIUS / largest_scaled_blur_radius;
4210 (x_blur_radius * sf, y_blur_radius * sf)
4211 } else {
4212 (x_blur_radius, y_blur_radius)
4214 }
4215 }
4216
4217 pub fn map_to_device_rect(
4218 &self,
4219 picture_rect: &PictureRect,
4220 spatial_tree: &SpatialTree,
4221 ) -> DeviceRect {
4222 let raster_rect = if self.raster_spatial_node_index != self.surface_spatial_node_index {
4223 assert_eq!(self.device_pixel_scale.0, 1.0);
4227 assert_eq!(self.raster_spatial_node_index, spatial_tree.root_reference_frame_index());
4228
4229 let pic_to_raster = SpaceMapper::new_with_target(
4230 self.raster_spatial_node_index,
4231 self.surface_spatial_node_index,
4232 WorldRect::max_rect(),
4233 spatial_tree,
4234 );
4235
4236 pic_to_raster.map(&picture_rect).unwrap()
4237 } else {
4238 picture_rect.cast_unit()
4239 };
4240
4241 raster_rect * self.device_pixel_scale
4242 }
4243
4244 pub fn get_surface_rect(
4247 &self,
4248 local_rect: &PictureRect,
4249 spatial_tree: &SpatialTree,
4250 ) -> Option<DeviceIntRect> {
4251 let local_rect = match local_rect.intersection(&self.clipping_rect) {
4252 Some(rect) => rect,
4253 None => return None,
4254 };
4255
4256 let raster_rect = if self.raster_spatial_node_index != self.surface_spatial_node_index {
4257 assert_eq!(self.device_pixel_scale.0, 1.0);
4258
4259 let local_to_world = SpaceMapper::new_with_target(
4260 spatial_tree.root_reference_frame_index(),
4261 self.surface_spatial_node_index,
4262 WorldRect::max_rect(),
4263 spatial_tree,
4264 );
4265
4266 local_to_world.map(&local_rect).unwrap()
4267 } else {
4268 assert!(self.device_pixel_scale.0 > 0.0);
4270
4271 local_rect.cast_unit()
4272 };
4273
4274 let surface_rect = (raster_rect * self.device_pixel_scale).round_out().to_i32();
4275 if surface_rect.is_empty() {
4276 return None;
4280 }
4281
4282 Some(surface_rect)
4283 }
4284}
4285
4286#[derive(Debug)]
4289struct SurfaceAllocInfo {
4290 task_size: DeviceIntSize,
4291 needs_scissor_rect: bool,
4292 clipped: DeviceRect,
4293 unclipped: DeviceRect,
4294 source: DeviceRect,
4297 clipped_notsnapped: DeviceRect,
4299 clipped_local: PictureRect,
4300 uv_rect_kind: UvRectKind,
4301}
4302
4303#[derive(Debug)]
4304#[cfg_attr(feature = "capture", derive(Serialize))]
4305pub struct RasterConfig {
4306 pub composite_mode: PictureCompositeMode,
4310 pub surface_index: SurfaceIndex,
4313}
4314
4315bitflags! {
4316 #[cfg_attr(feature = "capture", derive(Serialize))]
4318 #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
4319 pub struct BlitReason: u32 {
4320 const ISOLATE = 1;
4322 const CLIP = 2;
4324 const PRESERVE3D = 4;
4326 const BACKDROP = 8;
4328 const SNAPSHOT = 16;
4330 }
4331}
4332
4333#[allow(dead_code)]
4336#[derive(Debug, Clone)]
4337#[cfg_attr(feature = "capture", derive(Serialize))]
4338pub enum PictureCompositeMode {
4339 MixBlend(MixBlendMode),
4341 Filter(Filter),
4343 ComponentTransferFilter(FilterDataHandle),
4345 Blit(BlitReason),
4348 TileCache {
4350 slice_id: SliceId,
4351 },
4352 SvgFilter(Vec<FilterPrimitive>, Vec<SFilterData>),
4354 SVGFEGraph(Vec<(FilterGraphNode, FilterGraphOp)>),
4356 IntermediateSurface,
4358}
4359
4360impl PictureCompositeMode {
4361 pub fn get_rect(
4362 &self,
4363 surface: &SurfaceInfo,
4364 sub_rect: Option<LayoutRect>,
4365 ) -> LayoutRect {
4366 let surface_rect = match sub_rect {
4367 Some(sub_rect) => sub_rect,
4368 None => surface.clipped_local_rect.cast_unit(),
4369 };
4370
4371 match self {
4372 PictureCompositeMode::Filter(Filter::Blur { width, height, should_inflate }) => {
4373 if *should_inflate {
4374 let (width_factor, height_factor) = surface.clamp_blur_radius(*width, *height);
4375
4376 surface_rect.inflate(
4377 width_factor.ceil() * BLUR_SAMPLE_SCALE,
4378 height_factor.ceil() * BLUR_SAMPLE_SCALE,
4379 )
4380 } else {
4381 surface_rect
4382 }
4383 }
4384 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
4385 let mut max_blur_radius = 0.0;
4386 for shadow in shadows {
4387 max_blur_radius = f32::max(max_blur_radius, shadow.blur_radius);
4388 }
4389
4390 let (max_blur_radius_x, max_blur_radius_y) = surface.clamp_blur_radius(
4391 max_blur_radius,
4392 max_blur_radius,
4393 );
4394 let blur_inflation_x = max_blur_radius_x * BLUR_SAMPLE_SCALE;
4395 let blur_inflation_y = max_blur_radius_y * BLUR_SAMPLE_SCALE;
4396
4397 surface_rect.inflate(blur_inflation_x, blur_inflation_y)
4398 }
4399 PictureCompositeMode::SvgFilter(primitives, _) => {
4400 let mut result_rect = surface_rect;
4401 let mut output_rects = Vec::with_capacity(primitives.len());
4402
4403 for (cur_index, primitive) in primitives.iter().enumerate() {
4404 let output_rect = match primitive.kind {
4405 FilterPrimitiveKind::Blur(ref primitive) => {
4406 let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4407 let width_factor = primitive.width.round() * BLUR_SAMPLE_SCALE;
4408 let height_factor = primitive.height.round() * BLUR_SAMPLE_SCALE;
4409 input.inflate(width_factor, height_factor)
4410 }
4411 FilterPrimitiveKind::DropShadow(ref primitive) => {
4412 let inflation_factor = primitive.shadow.blur_radius.ceil() * BLUR_SAMPLE_SCALE;
4413 let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4414 let shadow_rect = input.inflate(inflation_factor, inflation_factor);
4415 input.union(&shadow_rect.translate(primitive.shadow.offset * Scale::new(1.0)))
4416 }
4417 FilterPrimitiveKind::Blend(ref primitive) => {
4418 primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect)
4419 .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect))
4420 }
4421 FilterPrimitiveKind::Composite(ref primitive) => {
4422 primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect)
4423 .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect))
4424 }
4425 FilterPrimitiveKind::Identity(ref primitive) =>
4426 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4427 FilterPrimitiveKind::Opacity(ref primitive) =>
4428 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4429 FilterPrimitiveKind::ColorMatrix(ref primitive) =>
4430 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4431 FilterPrimitiveKind::ComponentTransfer(ref primitive) =>
4432 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4433 FilterPrimitiveKind::Offset(ref primitive) => {
4434 let input_rect = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4435 input_rect.translate(primitive.offset * Scale::new(1.0))
4436 },
4437
4438 FilterPrimitiveKind::Flood(..) => surface_rect,
4439 };
4440 output_rects.push(output_rect);
4441 result_rect = result_rect.union(&output_rect);
4442 }
4443 result_rect
4444 }
4445 PictureCompositeMode::SVGFEGraph(ref filters) => {
4446 self.get_coverage_target_svgfe(filters, surface_rect.cast_unit())
4450 }
4451 _ => {
4452 surface_rect
4453 }
4454 }
4455 }
4456
4457 pub fn get_coverage(
4458 &self,
4459 surface: &SurfaceInfo,
4460 sub_rect: Option<LayoutRect>,
4461 ) -> LayoutRect {
4462 let surface_rect = match sub_rect {
4463 Some(sub_rect) => sub_rect,
4464 None => surface.clipped_local_rect.cast_unit(),
4465 };
4466
4467 match self {
4468 PictureCompositeMode::Filter(Filter::Blur { width, height, should_inflate }) => {
4469 if *should_inflate {
4470 let (width_factor, height_factor) = surface.clamp_blur_radius(*width, *height);
4471
4472 surface_rect.inflate(
4473 width_factor.ceil() * BLUR_SAMPLE_SCALE,
4474 height_factor.ceil() * BLUR_SAMPLE_SCALE,
4475 )
4476 } else {
4477 surface_rect
4478 }
4479 }
4480 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
4481 let mut rect = surface_rect;
4482
4483 for shadow in shadows {
4484 let (blur_radius_x, blur_radius_y) = surface.clamp_blur_radius(
4485 shadow.blur_radius,
4486 shadow.blur_radius,
4487 );
4488 let blur_inflation_x = blur_radius_x * BLUR_SAMPLE_SCALE;
4489 let blur_inflation_y = blur_radius_y * BLUR_SAMPLE_SCALE;
4490
4491 let shadow_rect = surface_rect
4492 .translate(shadow.offset)
4493 .inflate(blur_inflation_x, blur_inflation_y);
4494 rect = rect.union(&shadow_rect);
4495 }
4496
4497 rect
4498 }
4499 PictureCompositeMode::SvgFilter(primitives, _) => {
4500 let mut result_rect = surface_rect;
4501 let mut output_rects = Vec::with_capacity(primitives.len());
4502
4503 for (cur_index, primitive) in primitives.iter().enumerate() {
4504 let output_rect = match primitive.kind {
4505 FilterPrimitiveKind::Blur(ref primitive) => {
4506 let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4507 let width_factor = primitive.width.round() * BLUR_SAMPLE_SCALE;
4508 let height_factor = primitive.height.round() * BLUR_SAMPLE_SCALE;
4509
4510 input.inflate(width_factor, height_factor)
4511 }
4512 FilterPrimitiveKind::DropShadow(ref primitive) => {
4513 let inflation_factor = primitive.shadow.blur_radius.ceil() * BLUR_SAMPLE_SCALE;
4514 let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4515 let shadow_rect = input.inflate(inflation_factor, inflation_factor);
4516 input.union(&shadow_rect.translate(primitive.shadow.offset * Scale::new(1.0)))
4517 }
4518 FilterPrimitiveKind::Blend(ref primitive) => {
4519 primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect)
4520 .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect))
4521 }
4522 FilterPrimitiveKind::Composite(ref primitive) => {
4523 primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect)
4524 .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect))
4525 }
4526 FilterPrimitiveKind::Identity(ref primitive) =>
4527 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4528 FilterPrimitiveKind::Opacity(ref primitive) =>
4529 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4530 FilterPrimitiveKind::ColorMatrix(ref primitive) =>
4531 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4532 FilterPrimitiveKind::ComponentTransfer(ref primitive) =>
4533 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4534 FilterPrimitiveKind::Offset(ref primitive) => {
4535 let input_rect = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4536 input_rect.translate(primitive.offset * Scale::new(1.0))
4537 },
4538
4539 FilterPrimitiveKind::Flood(..) => surface_rect,
4540 };
4541 output_rects.push(output_rect);
4542 result_rect = result_rect.union(&output_rect);
4543 }
4544 result_rect
4545 }
4546 PictureCompositeMode::SVGFEGraph(ref filters) => {
4547 let target_subregion = self.get_coverage_source_svgfe(filters, surface_rect.cast());
4550 let source_subregion = self.get_coverage_target_svgfe(filters, surface_rect.cast());
4551 target_subregion.union(&source_subregion)
4552 }
4553 _ => {
4554 surface_rect
4555 }
4556 }
4557 }
4558
4559 pub fn kind(&self) -> &'static str {
4562 match *self {
4563 PictureCompositeMode::Blit(..) => "Blit",
4564 PictureCompositeMode::ComponentTransferFilter(..) => "ComponentTransferFilter",
4565 PictureCompositeMode::IntermediateSurface => "IntermediateSurface",
4566 PictureCompositeMode::MixBlend(..) => "MixBlend",
4567 PictureCompositeMode::SVGFEGraph(..) => "SVGFEGraph",
4568 PictureCompositeMode::SvgFilter(..) => "SvgFilter",
4569 PictureCompositeMode::TileCache{..} => "TileCache",
4570 PictureCompositeMode::Filter(Filter::Blur{..}) => "Filter::Blur",
4571 PictureCompositeMode::Filter(Filter::Brightness(..)) => "Filter::Brightness",
4572 PictureCompositeMode::Filter(Filter::ColorMatrix(..)) => "Filter::ColorMatrix",
4573 PictureCompositeMode::Filter(Filter::ComponentTransfer) => "Filter::ComponentTransfer",
4574 PictureCompositeMode::Filter(Filter::Contrast(..)) => "Filter::Contrast",
4575 PictureCompositeMode::Filter(Filter::DropShadows(..)) => "Filter::DropShadows",
4576 PictureCompositeMode::Filter(Filter::Flood(..)) => "Filter::Flood",
4577 PictureCompositeMode::Filter(Filter::Grayscale(..)) => "Filter::Grayscale",
4578 PictureCompositeMode::Filter(Filter::HueRotate(..)) => "Filter::HueRotate",
4579 PictureCompositeMode::Filter(Filter::Identity) => "Filter::Identity",
4580 PictureCompositeMode::Filter(Filter::Invert(..)) => "Filter::Invert",
4581 PictureCompositeMode::Filter(Filter::LinearToSrgb) => "Filter::LinearToSrgb",
4582 PictureCompositeMode::Filter(Filter::Opacity(..)) => "Filter::Opacity",
4583 PictureCompositeMode::Filter(Filter::Saturate(..)) => "Filter::Saturate",
4584 PictureCompositeMode::Filter(Filter::Sepia(..)) => "Filter::Sepia",
4585 PictureCompositeMode::Filter(Filter::SrgbToLinear) => "Filter::SrgbToLinear",
4586 PictureCompositeMode::Filter(Filter::SVGGraphNode(..)) => "Filter::SVGGraphNode",
4587 }
4588 }
4589
4590 pub fn get_coverage_target_svgfe(
4603 &self,
4604 filters: &[(FilterGraphNode, FilterGraphOp)],
4605 surface_rect: LayoutRect,
4606 ) -> LayoutRect {
4607
4608 const BUFFER_LIMIT: usize = SVGFE_GRAPH_MAX;
4611
4612 let mut subregion_by_buffer_id: [LayoutRect; BUFFER_LIMIT] = [LayoutRect::zero(); BUFFER_LIMIT];
4615 for (id, (node, op)) in filters.iter().enumerate() {
4616 let full_subregion = node.subregion;
4617 let mut used_subregion = LayoutRect::zero();
4618 for input in &node.inputs {
4619 match input.buffer_id {
4620 FilterOpGraphPictureBufferId::BufferId(id) => {
4621 assert!((id as usize) < BUFFER_LIMIT, "BUFFER_LIMIT must be the same in frame building and scene building");
4622 let input_subregion = subregion_by_buffer_id[id as usize];
4624 let input_subregion =
4628 LayoutRect::new(
4629 LayoutPoint::new(
4630 input_subregion.min.x + input.target_padding.min.x,
4631 input_subregion.min.y + input.target_padding.min.y,
4632 ),
4633 LayoutPoint::new(
4634 input_subregion.max.x + input.target_padding.max.x,
4635 input_subregion.max.y + input.target_padding.max.y,
4636 ),
4637 );
4638 used_subregion = used_subregion
4639 .union(&input_subregion);
4640 }
4641 FilterOpGraphPictureBufferId::None => {
4642 panic!("Unsupported BufferId type");
4643 }
4644 }
4645 }
4646 used_subregion = used_subregion
4648 .intersection(&full_subregion)
4649 .unwrap_or(LayoutRect::zero());
4650 match op {
4651 FilterGraphOp::SVGFEBlendColor => {}
4652 FilterGraphOp::SVGFEBlendColorBurn => {}
4653 FilterGraphOp::SVGFEBlendColorDodge => {}
4654 FilterGraphOp::SVGFEBlendDarken => {}
4655 FilterGraphOp::SVGFEBlendDifference => {}
4656 FilterGraphOp::SVGFEBlendExclusion => {}
4657 FilterGraphOp::SVGFEBlendHardLight => {}
4658 FilterGraphOp::SVGFEBlendHue => {}
4659 FilterGraphOp::SVGFEBlendLighten => {}
4660 FilterGraphOp::SVGFEBlendLuminosity => {}
4661 FilterGraphOp::SVGFEBlendMultiply => {}
4662 FilterGraphOp::SVGFEBlendNormal => {}
4663 FilterGraphOp::SVGFEBlendOverlay => {}
4664 FilterGraphOp::SVGFEBlendSaturation => {}
4665 FilterGraphOp::SVGFEBlendScreen => {}
4666 FilterGraphOp::SVGFEBlendSoftLight => {}
4667 FilterGraphOp::SVGFEColorMatrix { values } => {
4668 if values[3] != 0.0 ||
4669 values[7] != 0.0 ||
4670 values[11] != 0.0 ||
4671 values[19] != 0.0 {
4672 used_subregion = full_subregion;
4675 }
4676 }
4677 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
4678 FilterGraphOp::SVGFEComponentTransferInterned{handle: _, creates_pixels} => {
4679 if *creates_pixels {
4683 used_subregion = full_subregion;
4684 }
4685 }
4686 FilterGraphOp::SVGFECompositeArithmetic { k1, k2, k3, k4 } => {
4687 if *k1 <= 0.0 &&
4699 *k2 <= 0.0 &&
4700 *k3 <= 0.0 {
4701 used_subregion = LayoutRect::zero();
4702 }
4703 if *k4 > 0.0 {
4706 used_subregion = full_subregion;
4707 }
4708 }
4709 FilterGraphOp::SVGFECompositeATop => {}
4710 FilterGraphOp::SVGFECompositeIn => {}
4711 FilterGraphOp::SVGFECompositeLighter => {}
4712 FilterGraphOp::SVGFECompositeOut => {}
4713 FilterGraphOp::SVGFECompositeOver => {}
4714 FilterGraphOp::SVGFECompositeXOR => {}
4715 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{..} => {}
4716 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{..} => {}
4717 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{..} => {}
4718 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {}
4719 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {}
4720 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {}
4721 FilterGraphOp::SVGFEDisplacementMap{..} => {}
4722 FilterGraphOp::SVGFEDropShadow{..} => {}
4723 FilterGraphOp::SVGFEFlood { color } => {
4724 if color.a > 0.0 {
4727 used_subregion = full_subregion;
4728 }
4729 }
4730 FilterGraphOp::SVGFEGaussianBlur{..} => {}
4731 FilterGraphOp::SVGFEIdentity => {}
4732 FilterGraphOp::SVGFEImage { sampling_filter: _sampling_filter, matrix: _matrix } => {
4733 used_subregion = full_subregion;
4735 }
4736 FilterGraphOp::SVGFEMorphologyDilate{..} => {}
4737 FilterGraphOp::SVGFEMorphologyErode{..} => {}
4738 FilterGraphOp::SVGFEOpacity { valuebinding: _valuebinding, value } => {
4739 if *value <= 0.0 {
4741 used_subregion = LayoutRect::zero();
4742 }
4743 }
4744 FilterGraphOp::SVGFESourceAlpha |
4745 FilterGraphOp::SVGFESourceGraphic => {
4746 used_subregion = surface_rect;
4747 }
4748 FilterGraphOp::SVGFESpecularLightingDistant{..} => {}
4749 FilterGraphOp::SVGFESpecularLightingPoint{..} => {}
4750 FilterGraphOp::SVGFESpecularLightingSpot{..} => {}
4751 FilterGraphOp::SVGFETile => {
4752 used_subregion = full_subregion;
4755 }
4756 FilterGraphOp::SVGFEToAlpha => {}
4757 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} |
4758 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} |
4759 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} |
4760 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {
4761 used_subregion = full_subregion;
4764 }
4765 }
4766 assert!((id as usize) < BUFFER_LIMIT, "BUFFER_LIMIT must be the same in frame building and scene building");
4769 subregion_by_buffer_id[id] = used_subregion;
4770 }
4771 subregion_by_buffer_id[filters.len() - 1]
4772 }
4773
4774 pub fn get_coverage_source_svgfe(
4787 &self,
4788 filters: &[(FilterGraphNode, FilterGraphOp)],
4789 surface_rect: LayoutRect,
4790 ) -> LayoutRect {
4791
4792 const BUFFER_LIMIT: usize = SVGFE_GRAPH_MAX;
4795
4796 let mut source_subregion = LayoutRect::zero();
4803 let mut subregion_by_buffer_id: [LayoutRect; BUFFER_LIMIT] =
4804 [LayoutRect::zero(); BUFFER_LIMIT];
4805 let final_buffer_id = filters.len() - 1;
4806 assert!(final_buffer_id < BUFFER_LIMIT, "BUFFER_LIMIT must be the same in frame building and scene building");
4807 subregion_by_buffer_id[final_buffer_id] = surface_rect;
4808 for (node_buffer_id, (node, op)) in filters.iter().enumerate().rev() {
4809 assert!(node_buffer_id < BUFFER_LIMIT, "BUFFER_LIMIT must be the same in frame building and scene building");
4813 let full_subregion = node.subregion;
4814 let mut used_subregion =
4815 subregion_by_buffer_id[node_buffer_id];
4816 used_subregion = used_subregion
4819 .intersection(&full_subregion)
4820 .unwrap_or(LayoutRect::zero());
4821 if !used_subregion.is_empty() {
4822 for input in &node.inputs {
4823 let input_subregion = LayoutRect::new(
4824 LayoutPoint::new(
4825 used_subregion.min.x + input.source_padding.min.x,
4826 used_subregion.min.y + input.source_padding.min.y,
4827 ),
4828 LayoutPoint::new(
4829 used_subregion.max.x + input.source_padding.max.x,
4830 used_subregion.max.y + input.source_padding.max.y,
4831 ),
4832 );
4833 match input.buffer_id {
4834 FilterOpGraphPictureBufferId::BufferId(id) => {
4835 subregion_by_buffer_id[id as usize] =
4839 subregion_by_buffer_id[id as usize]
4840 .union(&input_subregion);
4841 }
4842 FilterOpGraphPictureBufferId::None => {}
4843 }
4844 }
4845 }
4846 match op {
4850 FilterGraphOp::SVGFESourceAlpha |
4851 FilterGraphOp::SVGFESourceGraphic => {
4852 source_subregion = source_subregion.union(&used_subregion);
4853 }
4854 _ => {}
4855 }
4856 }
4857
4858 source_subregion
4861 }
4862}
4863
4864#[derive(Clone, Debug)]
4866#[cfg_attr(feature = "capture", derive(Serialize))]
4867pub enum Picture3DContext<C> {
4868 Out,
4870 In {
4872 root_data: Option<Vec<C>>,
4874 ancestor_index: SpatialNodeIndex,
4880 plane_splitter_index: PlaneSplitterIndex,
4882 },
4883}
4884
4885#[derive(Clone, Debug)]
4888#[cfg_attr(feature = "capture", derive(Serialize))]
4889pub struct OrderedPictureChild {
4890 pub anchor: PlaneSplitAnchor,
4891 pub gpu_address: GpuCacheAddress,
4892}
4893
4894bitflags! {
4895 #[cfg_attr(feature = "capture", derive(Serialize))]
4897 #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
4898 pub struct ClusterFlags: u32 {
4899 const IS_BACKFACE_VISIBLE = 1;
4901 const IS_VISIBLE = 2;
4905 }
4906}
4907
4908#[cfg_attr(feature = "capture", derive(Serialize))]
4911pub struct PrimitiveCluster {
4912 pub spatial_node_index: SpatialNodeIndex,
4914 bounding_rect: LayoutRect,
4919 pub opaque_rect: LayoutRect,
4923 pub prim_range: Range<usize>,
4925 pub flags: ClusterFlags,
4927}
4928
4929impl PrimitiveCluster {
4930 fn new(
4932 spatial_node_index: SpatialNodeIndex,
4933 flags: ClusterFlags,
4934 first_instance_index: usize,
4935 ) -> Self {
4936 PrimitiveCluster {
4937 bounding_rect: LayoutRect::zero(),
4938 opaque_rect: LayoutRect::zero(),
4939 spatial_node_index,
4940 flags,
4941 prim_range: first_instance_index..first_instance_index
4942 }
4943 }
4944
4945 pub fn is_compatible(
4947 &self,
4948 spatial_node_index: SpatialNodeIndex,
4949 flags: ClusterFlags,
4950 instance_index: usize,
4951 ) -> bool {
4952 self.flags == flags &&
4953 self.spatial_node_index == spatial_node_index &&
4954 instance_index == self.prim_range.end
4955 }
4956
4957 pub fn prim_range(&self) -> Range<usize> {
4958 self.prim_range.clone()
4959 }
4960
4961 fn add_instance(
4963 &mut self,
4964 culling_rect: &LayoutRect,
4965 instance_index: usize,
4966 ) {
4967 debug_assert_eq!(instance_index, self.prim_range.end);
4968 self.bounding_rect = self.bounding_rect.union(culling_rect);
4969 self.prim_range.end += 1;
4970 }
4971}
4972
4973#[cfg_attr(feature = "capture", derive(Serialize))]
4978pub struct PrimitiveList {
4979 pub clusters: Vec<PrimitiveCluster>,
4981 pub child_pictures: Vec<PictureIndex>,
4982 pub image_surface_count: usize,
4985 pub yuv_image_surface_count: usize,
4988 pub needs_scissor_rect: bool,
4989}
4990
4991impl PrimitiveList {
4992 pub fn empty() -> Self {
4997 PrimitiveList {
4998 clusters: Vec::new(),
4999 child_pictures: Vec::new(),
5000 image_surface_count: 0,
5001 yuv_image_surface_count: 0,
5002 needs_scissor_rect: false,
5003 }
5004 }
5005
5006 pub fn merge(&mut self, other: PrimitiveList) {
5007 self.clusters.extend(other.clusters);
5008 self.child_pictures.extend(other.child_pictures);
5009 self.image_surface_count += other.image_surface_count;
5010 self.yuv_image_surface_count += other.yuv_image_surface_count;
5011 self.needs_scissor_rect |= other.needs_scissor_rect;
5012 }
5013
5014 pub fn add_prim(
5016 &mut self,
5017 prim_instance: PrimitiveInstance,
5018 prim_rect: LayoutRect,
5019 spatial_node_index: SpatialNodeIndex,
5020 prim_flags: PrimitiveFlags,
5021 prim_instances: &mut Vec<PrimitiveInstance>,
5022 clip_tree_builder: &ClipTreeBuilder,
5023 ) {
5024 let mut flags = ClusterFlags::empty();
5025
5026 match prim_instance.kind {
5029 PrimitiveInstanceKind::Picture { pic_index, .. } => {
5030 self.child_pictures.push(pic_index);
5031 }
5032 PrimitiveInstanceKind::TextRun { .. } => {
5033 self.needs_scissor_rect = true;
5034 }
5035 PrimitiveInstanceKind::YuvImage { .. } => {
5036 if prim_flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
5043 self.yuv_image_surface_count += 1;
5044 }
5045 }
5046 PrimitiveInstanceKind::Image { .. } => {
5047 if prim_flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
5053 self.image_surface_count += 1;
5054 }
5055 }
5056 _ => {}
5057 }
5058
5059 if prim_flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE) {
5060 flags.insert(ClusterFlags::IS_BACKFACE_VISIBLE);
5061 }
5062
5063 let clip_leaf = clip_tree_builder.get_leaf(prim_instance.clip_leaf_id);
5064 let culling_rect = clip_leaf.local_clip_rect
5065 .intersection(&prim_rect)
5066 .unwrap_or_else(LayoutRect::zero);
5067
5068 let instance_index = prim_instances.len();
5069 prim_instances.push(prim_instance);
5070
5071 if let Some(cluster) = self.clusters.last_mut() {
5072 if cluster.is_compatible(spatial_node_index, flags, instance_index) {
5073 cluster.add_instance(&culling_rect, instance_index);
5074 return;
5075 }
5076 }
5077
5078 let clusters_len = self.clusters.len();
5080 if clusters_len == self.clusters.capacity() {
5081 let next_alloc = match clusters_len {
5082 1 ..= 15 => 16 - clusters_len,
5083 16 ..= 127 => 128 - clusters_len,
5084 _ => clusters_len * 2,
5085 };
5086
5087 self.clusters.reserve(next_alloc);
5088 }
5089
5090 let mut cluster = PrimitiveCluster::new(
5091 spatial_node_index,
5092 flags,
5093 instance_index,
5094 );
5095
5096 cluster.add_instance(&culling_rect, instance_index);
5097 self.clusters.push(cluster);
5098 }
5099
5100 pub fn is_empty(&self) -> bool {
5102 self.clusters.is_empty()
5103 }
5104}
5105
5106bitflags! {
5107 #[cfg_attr(feature = "capture", derive(Serialize))]
5108 #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
5110 pub struct PictureFlags : u8 {
5111 const IS_RESOLVE_TARGET = 1 << 0;
5114 const IS_SUB_GRAPH = 1 << 1;
5117 const DISABLE_SNAPPING = 1 << 2;
5119 }
5120}
5121
5122#[cfg_attr(feature = "capture", derive(Serialize))]
5123pub struct PicturePrimitive {
5124 pub prim_list: PrimitiveList,
5126
5127 pub is_backface_visible: bool,
5130
5131 pub primary_render_task_id: Option<RenderTaskId>,
5133 pub secondary_render_task_id: Option<RenderTaskId>,
5142 pub composite_mode: Option<PictureCompositeMode>,
5145
5146 pub raster_config: Option<RasterConfig>,
5147 pub context_3d: Picture3DContext<OrderedPictureChild>,
5148
5149 pub extra_gpu_data_handles: SmallVec<[GpuCacheHandle; 1]>,
5153
5154 pub spatial_node_index: SpatialNodeIndex,
5157
5158 pub prev_local_rect: LayoutRect,
5162
5163 pub segments_are_valid: bool,
5168
5169 pub is_opaque: bool,
5171
5172 pub raster_space: RasterSpace,
5174
5175 pub flags: PictureFlags,
5177
5178 pub clip_root: Option<ClipNodeId>,
5182
5183 pub snapshot: Option<SnapshotInfo>,
5186}
5187
5188impl PicturePrimitive {
5189 pub fn print<T: PrintTreePrinter>(
5190 &self,
5191 pictures: &[Self],
5192 self_index: PictureIndex,
5193 pt: &mut T,
5194 ) {
5195 pt.new_level(format!("{:?}", self_index));
5196 pt.add_item(format!("cluster_count: {:?}", self.prim_list.clusters.len()));
5197 pt.add_item(format!("spatial_node_index: {:?}", self.spatial_node_index));
5198 pt.add_item(format!("raster_config: {:?}", self.raster_config));
5199 pt.add_item(format!("composite_mode: {:?}", self.composite_mode));
5200 pt.add_item(format!("flags: {:?}", self.flags));
5201
5202 for child_pic_index in &self.prim_list.child_pictures {
5203 pictures[child_pic_index.0].print(pictures, *child_pic_index, pt);
5204 }
5205
5206 pt.end_level();
5207 }
5208
5209 fn resolve_scene_properties(&mut self, properties: &SceneProperties) {
5210 match self.composite_mode {
5211 Some(PictureCompositeMode::Filter(ref mut filter)) => {
5212 match *filter {
5213 Filter::Opacity(ref binding, ref mut value) => {
5214 *value = properties.resolve_float(binding);
5215 }
5216 _ => {}
5217 }
5218 }
5219 _ => {}
5220 }
5221 }
5222
5223 pub fn is_visible(
5224 &self,
5225 spatial_tree: &SpatialTree,
5226 ) -> bool {
5227 if let Some(PictureCompositeMode::Filter(ref filter)) = self.composite_mode {
5228 if !filter.is_visible() {
5229 return false;
5230 }
5231 }
5232
5233 if !self.is_backface_visible {
5238 if let Picture3DContext::Out = self.context_3d {
5239 match spatial_tree.get_local_visible_face(self.spatial_node_index) {
5240 VisibleFace::Front => {}
5241 VisibleFace::Back => return false,
5242 }
5243 }
5244 }
5245
5246 true
5247 }
5248
5249 pub fn new_image(
5250 composite_mode: Option<PictureCompositeMode>,
5251 context_3d: Picture3DContext<OrderedPictureChild>,
5252 prim_flags: PrimitiveFlags,
5253 prim_list: PrimitiveList,
5254 spatial_node_index: SpatialNodeIndex,
5255 raster_space: RasterSpace,
5256 flags: PictureFlags,
5257 snapshot: Option<SnapshotInfo>,
5258 ) -> Self {
5259 PicturePrimitive {
5260 prim_list,
5261 primary_render_task_id: None,
5262 secondary_render_task_id: None,
5263 composite_mode,
5264 raster_config: None,
5265 context_3d,
5266 extra_gpu_data_handles: SmallVec::new(),
5267 is_backface_visible: prim_flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE),
5268 spatial_node_index,
5269 prev_local_rect: LayoutRect::zero(),
5270 segments_are_valid: false,
5271 is_opaque: false,
5272 raster_space,
5273 flags,
5274 clip_root: None,
5275 snapshot,
5276 }
5277 }
5278
5279 pub fn take_context(
5280 &mut self,
5281 pic_index: PictureIndex,
5282 parent_surface_index: Option<SurfaceIndex>,
5283 parent_subpixel_mode: SubpixelMode,
5284 frame_state: &mut FrameBuildingState,
5285 frame_context: &FrameBuildingContext,
5286 data_stores: &mut DataStores,
5287 scratch: &mut PrimitiveScratchBuffer,
5288 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
5289 ) -> Option<(PictureContext, PictureState, PrimitiveList)> {
5290 frame_state.visited_pictures[pic_index.0] = true;
5291 self.primary_render_task_id = None;
5292 self.secondary_render_task_id = None;
5293
5294 let dbg_flags = DebugFlags::PICTURE_CACHING_DBG | DebugFlags::PICTURE_BORDERS;
5295 if frame_context.debug_flags.intersects(dbg_flags) {
5296 self.draw_debug_overlay(
5297 parent_surface_index,
5298 frame_state,
5299 frame_context,
5300 tile_caches,
5301 scratch,
5302 );
5303 }
5304
5305 if !self.is_visible(frame_context.spatial_tree) {
5306 return None;
5307 }
5308
5309 profile_scope!("take_context");
5310
5311 let surface_index = match self.raster_config {
5312 Some(ref raster_config) => raster_config.surface_index,
5313 None => parent_surface_index.expect("bug: no parent"),
5314 };
5315 let surface = &frame_state.surfaces[surface_index.0];
5316 let surface_spatial_node_index = surface.surface_spatial_node_index;
5317
5318 let map_pic_to_world = SpaceMapper::new_with_target(
5319 frame_context.root_spatial_node_index,
5320 surface_spatial_node_index,
5321 frame_context.global_screen_world_rect,
5322 frame_context.spatial_tree,
5323 );
5324
5325 let map_pic_to_vis = SpaceMapper::new_with_target(
5326 frame_context.root_spatial_node_index,
5328 surface_spatial_node_index,
5329 surface.culling_rect,
5330 frame_context.spatial_tree,
5331 );
5332
5333 let pic_bounds = map_pic_to_world
5337 .unmap(&map_pic_to_world.bounds)
5338 .unwrap_or_else(PictureRect::max_rect);
5339
5340 let map_local_to_pic = SpaceMapper::new(
5341 surface_spatial_node_index,
5342 pic_bounds,
5343 );
5344
5345 match self.raster_config {
5346 Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) => {
5347 let tile_cache = tile_caches.get_mut(&slice_id).unwrap();
5348 let mut debug_info = SliceDebugInfo::new();
5349 let mut surface_render_tasks = FastHashMap::default();
5350 let mut surface_local_dirty_rect = PictureRect::zero();
5351 let device_pixel_scale = frame_state
5352 .surfaces[surface_index.0]
5353 .device_pixel_scale;
5354 let mut at_least_one_tile_visible = false;
5355
5356 let world_clip_rect = map_pic_to_world
5359 .map(&tile_cache.local_clip_rect)
5360 .expect("bug: unable to map clip rect")
5361 .round();
5362 let device_clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round();
5363
5364 for (sub_slice_index, sub_slice) in tile_cache.sub_slices.iter_mut().enumerate() {
5365 for tile in sub_slice.tiles.values_mut() {
5366 tile.local_dirty_rect = tile.local_dirty_rect
5368 .intersection(&tile.current_descriptor.local_valid_rect)
5369 .unwrap_or_else(|| { tile.is_valid = true; PictureRect::zero() });
5370
5371 let valid_rect = frame_state.composite_state.get_surface_rect(
5372 &tile.current_descriptor.local_valid_rect,
5373 &tile.local_tile_rect,
5374 tile_cache.transform_index,
5375 ).to_i32();
5376
5377 let scissor_rect = frame_state.composite_state.get_surface_rect(
5378 &tile.local_dirty_rect,
5379 &tile.local_tile_rect,
5380 tile_cache.transform_index,
5381 ).to_i32().intersection(&valid_rect).unwrap_or_else(|| { Box2D::zero() });
5382
5383 if tile.is_visible {
5384 let world_draw_rect = world_clip_rect.intersection(&tile.world_valid_rect);
5386
5387 match world_draw_rect {
5392 Some(world_draw_rect) => {
5393 if tile_cache.spatial_node_index == frame_context.root_spatial_node_index &&
5395 frame_state.composite_state.occluders.is_tile_occluded(tile.z_id, world_draw_rect) {
5396 let surface = tile.surface.as_mut().expect("no tile surface set!");
5401
5402 if let TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { id, .. }, .. } = surface {
5403 if let Some(id) = id.take() {
5404 frame_state.resource_cache.destroy_compositor_tile(id);
5405 }
5406 }
5407
5408 tile.is_visible = false;
5409
5410 if frame_context.fb_config.testing {
5411 debug_info.tiles.insert(
5412 tile.tile_offset,
5413 TileDebugInfo::Occluded,
5414 );
5415 }
5416
5417 continue;
5418 }
5419 }
5420 None => {
5421 tile.is_visible = false;
5422 }
5423 }
5424
5425 if !tile.is_valid && (scissor_rect.is_empty() || valid_rect.is_empty()) {
5433 tile.is_visible = false;
5434 }
5435 }
5436
5437 if let Some(TileSurface::Texture { descriptor, .. }) = tile.surface.as_ref() {
5442 if let SurfaceTextureDescriptor::TextureCache { handle: Some(handle), .. } = descriptor {
5443 frame_state.resource_cache
5444 .picture_textures.request(handle, frame_state.gpu_cache);
5445 }
5446 }
5447
5448 if !tile.is_visible {
5450 if frame_context.fb_config.testing {
5451 debug_info.tiles.insert(
5452 tile.tile_offset,
5453 TileDebugInfo::Culled,
5454 );
5455 }
5456
5457 continue;
5458 }
5459
5460 at_least_one_tile_visible = true;
5461
5462 if let TileSurface::Texture { descriptor, .. } = tile.surface.as_mut().unwrap() {
5463 match descriptor {
5464 SurfaceTextureDescriptor::TextureCache { ref handle, .. } => {
5465 let exists = handle.as_ref().map_or(false,
5466 |handle| frame_state.resource_cache.picture_textures.entry_exists(handle)
5467 );
5468 if exists {
5470 frame_state.resource_cache
5479 .picture_textures
5480 .request(handle.as_ref().unwrap(), frame_state.gpu_cache);
5481 } else {
5482 tile.invalidate(None, InvalidationReason::NoTexture);
5485 }
5486 }
5487 SurfaceTextureDescriptor::Native { id, .. } => {
5488 if id.is_none() {
5489 tile.invalidate(None, InvalidationReason::NoSurface);
5491 }
5492 }
5493 }
5494 }
5495
5496 tile.local_dirty_rect = tile.local_dirty_rect
5499 .intersection(&tile.current_descriptor.local_valid_rect)
5500 .unwrap_or_else(|| { tile.is_valid = true; PictureRect::zero() });
5501
5502 surface_local_dirty_rect = surface_local_dirty_rect.union(&tile.local_dirty_rect);
5503
5504 let world_dirty_rect = map_pic_to_world.map(&tile.local_dirty_rect).expect("bug");
5506
5507 let device_rect = (tile.world_tile_rect * frame_context.global_device_pixel_scale).round();
5508 tile.device_dirty_rect = (world_dirty_rect * frame_context.global_device_pixel_scale)
5509 .round_out()
5510 .intersection(&device_rect)
5511 .unwrap_or_else(DeviceRect::zero);
5512
5513 if tile.is_valid {
5514 if frame_context.fb_config.testing {
5515 debug_info.tiles.insert(
5516 tile.tile_offset,
5517 TileDebugInfo::Valid,
5518 );
5519 }
5520 } else {
5521 tile_cache.dirty_region.add_dirty_region(
5525 tile.local_dirty_rect,
5526 frame_context.spatial_tree,
5527 );
5528
5529 if let TileSurface::Texture { ref mut descriptor } = tile.surface.as_mut().unwrap() {
5531 match descriptor {
5532 SurfaceTextureDescriptor::TextureCache { ref mut handle } => {
5533
5534 frame_state.resource_cache.picture_textures.update(
5535 tile_cache.current_tile_size,
5536 handle,
5537 frame_state.gpu_cache,
5538 &mut frame_state.resource_cache.texture_cache.next_id,
5539 &mut frame_state.resource_cache.texture_cache.pending_updates,
5540 );
5541 }
5542 SurfaceTextureDescriptor::Native { id } => {
5543 if id.is_none() {
5544 if sub_slice.native_surface.is_none() {
5548 let opaque = frame_state
5549 .resource_cache
5550 .create_compositor_surface(
5551 tile_cache.virtual_offset,
5552 tile_cache.current_tile_size,
5553 true,
5554 );
5555
5556 let alpha = frame_state
5557 .resource_cache
5558 .create_compositor_surface(
5559 tile_cache.virtual_offset,
5560 tile_cache.current_tile_size,
5561 false,
5562 );
5563
5564 sub_slice.native_surface = Some(NativeSurface {
5565 opaque,
5566 alpha,
5567 });
5568 }
5569
5570 let surface_id = if tile.is_opaque {
5572 sub_slice.native_surface.as_ref().unwrap().opaque
5573 } else {
5574 sub_slice.native_surface.as_ref().unwrap().alpha
5575 };
5576
5577 let tile_id = NativeTileId {
5578 surface_id,
5579 x: tile.tile_offset.x,
5580 y: tile.tile_offset.y,
5581 };
5582
5583 frame_state.resource_cache.create_compositor_tile(tile_id);
5584
5585 *id = Some(tile_id);
5586 }
5587 }
5588 }
5589
5590 let content_origin_f = tile.local_tile_rect.min.cast_unit() * device_pixel_scale;
5597 let content_origin = content_origin_f.round();
5598 debug_assert!((content_origin_f.x - content_origin.x).abs() < 0.15);
5603 debug_assert!((content_origin_f.y - content_origin.y).abs() < 0.15);
5604
5605 let surface = descriptor.resolve(
5606 frame_state.resource_cache,
5607 tile_cache.current_tile_size,
5608 );
5609
5610 let scissor_rect = frame_state.composite_state.get_surface_rect(
5612 &tile.local_dirty_rect,
5613 &tile.local_tile_rect,
5614 tile_cache.transform_index,
5615 ).to_i32();
5616
5617 let composite_task_size = tile_cache.current_tile_size;
5618
5619 let tile_key = TileKey {
5620 sub_slice_index: SubSliceIndex::new(sub_slice_index),
5621 tile_offset: tile.tile_offset,
5622 };
5623
5624 let mut clear_color = ColorF::TRANSPARENT;
5625
5626 if SubSliceIndex::new(sub_slice_index).is_primary() {
5627 if let Some(background_color) = tile_cache.background_color {
5628 clear_color = background_color;
5629 }
5630
5631 if let Some(color) = tile_cache.backdrop.spanning_opaque_color {
5637 clear_color = color;
5638 }
5639 }
5640
5641 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
5642
5643 let use_tile_composite = !tile.sub_graphs.is_empty();
5647
5648 if use_tile_composite {
5649 let mut local_content_rect = tile.local_dirty_rect;
5650
5651 for (sub_graph_rect, surface_stack) in &tile.sub_graphs {
5652 if let Some(dirty_sub_graph_rect) = sub_graph_rect.intersection(&tile.local_dirty_rect) {
5653 for (composite_mode, surface_index) in surface_stack {
5654 let surface = &frame_state.surfaces[surface_index.0];
5655
5656 let rect = composite_mode.get_coverage(
5657 surface,
5658 Some(dirty_sub_graph_rect.cast_unit()),
5659 ).cast_unit();
5660
5661 local_content_rect = local_content_rect.union(&rect);
5662 }
5663 }
5664 }
5665
5666 let max_content_rect = (tile.local_dirty_rect.cast_unit() * device_pixel_scale)
5670 .inflate(
5671 MAX_BLUR_RADIUS * BLUR_SAMPLE_SCALE,
5672 MAX_BLUR_RADIUS * BLUR_SAMPLE_SCALE,
5673 )
5674 .round_out()
5675 .to_i32();
5676
5677 let content_device_rect = (local_content_rect.cast_unit() * device_pixel_scale)
5678 .round_out()
5679 .to_i32();
5680
5681 let content_device_rect = content_device_rect
5682 .intersection(&max_content_rect)
5683 .expect("bug: no intersection with tile dirty rect: {content_device_rect:?} / {max_content_rect:?}");
5684
5685 let content_task_size = content_device_rect.size();
5686 let normalized_content_rect = content_task_size.into();
5687
5688 let inner_offset = content_origin + scissor_rect.min.to_vector().to_f32();
5689 let outer_offset = content_device_rect.min.to_f32();
5690 let sub_rect_offset = (inner_offset - outer_offset).round().to_i32();
5691
5692 let render_task_id = frame_state.rg_builder.add().init(
5693 RenderTask::new_dynamic(
5694 content_task_size,
5695 RenderTaskKind::new_picture(
5696 content_task_size,
5697 true,
5698 content_device_rect.min.to_f32(),
5699 surface_spatial_node_index,
5700 surface_spatial_node_index,
5702 device_pixel_scale,
5703 Some(normalized_content_rect),
5704 None,
5705 Some(clear_color),
5706 cmd_buffer_index,
5707 false,
5708 )
5709 ),
5710 );
5711
5712 let composite_task_id = frame_state.rg_builder.add().init(
5713 RenderTask::new(
5714 RenderTaskLocation::Static {
5715 surface: StaticRenderTaskSurface::PictureCache {
5716 surface,
5717 },
5718 rect: composite_task_size.into(),
5719 },
5720 RenderTaskKind::new_tile_composite(
5721 sub_rect_offset,
5722 scissor_rect,
5723 valid_rect,
5724 clear_color,
5725 ),
5726 ),
5727 );
5728
5729 surface_render_tasks.insert(
5730 tile_key,
5731 SurfaceTileDescriptor {
5732 current_task_id: render_task_id,
5733 composite_task_id: Some(composite_task_id),
5734 dirty_rect: tile.local_dirty_rect,
5735 },
5736 );
5737 } else {
5738 let render_task_id = frame_state.rg_builder.add().init(
5739 RenderTask::new(
5740 RenderTaskLocation::Static {
5741 surface: StaticRenderTaskSurface::PictureCache {
5742 surface,
5743 },
5744 rect: composite_task_size.into(),
5745 },
5746 RenderTaskKind::new_picture(
5747 composite_task_size,
5748 true,
5749 content_origin,
5750 surface_spatial_node_index,
5751 surface_spatial_node_index,
5753 device_pixel_scale,
5754 Some(scissor_rect),
5755 Some(valid_rect),
5756 Some(clear_color),
5757 cmd_buffer_index,
5758 false,
5759 )
5760 ),
5761 );
5762
5763 surface_render_tasks.insert(
5764 tile_key,
5765 SurfaceTileDescriptor {
5766 current_task_id: render_task_id,
5767 composite_task_id: None,
5768 dirty_rect: tile.local_dirty_rect,
5769 },
5770 );
5771 }
5772 }
5773
5774 if frame_context.fb_config.testing {
5775 debug_info.tiles.insert(
5776 tile.tile_offset,
5777 TileDebugInfo::Dirty(DirtyTileDebugInfo {
5778 local_valid_rect: tile.current_descriptor.local_valid_rect,
5779 local_dirty_rect: tile.local_dirty_rect,
5780 }),
5781 );
5782 }
5783 }
5784
5785 let surface = tile.surface.as_ref().expect("no tile surface set!");
5786
5787 let descriptor = CompositeTileDescriptor {
5788 surface_kind: surface.into(),
5789 tile_id: tile.id,
5790 };
5791
5792 let (surface, is_opaque) = match surface {
5793 TileSurface::Color { color } => {
5794 (CompositeTileSurface::Color { color: *color }, true)
5795 }
5796 TileSurface::Clear => {
5797 (CompositeTileSurface::Clear, false)
5799 }
5800 TileSurface::Texture { descriptor, .. } => {
5801 let surface = descriptor.resolve(frame_state.resource_cache, tile_cache.current_tile_size);
5802 (
5803 CompositeTileSurface::Texture { surface },
5804 tile.is_opaque
5805 )
5806 }
5807 };
5808
5809 if is_opaque {
5810 sub_slice.opaque_tile_descriptors.push(descriptor);
5811 } else {
5812 sub_slice.alpha_tile_descriptors.push(descriptor);
5813 }
5814
5815 let composite_tile = CompositeTile {
5816 kind: tile_kind(&surface, is_opaque),
5817 surface,
5818 local_rect: tile.local_tile_rect,
5819 local_valid_rect: tile.current_descriptor.local_valid_rect,
5820 local_dirty_rect: tile.local_dirty_rect,
5821 device_clip_rect,
5822 z_id: tile.z_id,
5823 transform_index: tile_cache.transform_index,
5824 clip_index: tile_cache.compositor_clip,
5825 };
5826
5827 sub_slice.composite_tiles.push(composite_tile);
5828
5829 tile.local_dirty_rect = PictureRect::zero();
5831 tile.is_valid = true;
5832 }
5833
5834 sub_slice.opaque_tile_descriptors.sort_by_key(|desc| desc.tile_id);
5839 sub_slice.alpha_tile_descriptors.sort_by_key(|desc| desc.tile_id);
5840 }
5841
5842 let backdrop_rect = tile_cache.backdrop.backdrop_rect
5844 .intersection(&tile_cache.local_rect)
5845 .and_then(|r| {
5846 r.intersection(&tile_cache.local_clip_rect)
5847 });
5848
5849 let mut backdrop_in_use_and_visible = false;
5850 if let Some(backdrop_rect) = backdrop_rect {
5851 let supports_surface_for_backdrop = match frame_state.composite_state.compositor_kind {
5852 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
5853 false
5854 }
5855 CompositorKind::Native { capabilities, .. } => {
5856 capabilities.supports_surface_for_backdrop
5857 }
5858 };
5859 if supports_surface_for_backdrop && !tile_cache.found_prims_after_backdrop && at_least_one_tile_visible {
5860 if let Some(BackdropKind::Color { color }) = tile_cache.backdrop.kind {
5861 backdrop_in_use_and_visible = true;
5862
5863 for sub_slice in &mut tile_cache.sub_slices {
5866 for tile in sub_slice.tiles.values_mut() {
5867 tile.is_visible = false;
5868 }
5869 }
5870
5871 if let Some(backdrop_surface) = &tile_cache.backdrop_surface {
5874 if backdrop_surface.color != color {
5875 frame_state.resource_cache.destroy_compositor_surface(backdrop_surface.id);
5876 tile_cache.backdrop_surface = None;
5877 }
5878 }
5879
5880 let world_backdrop_rect = map_pic_to_world.map(&backdrop_rect).expect("bug: unable to map backdrop rect");
5883 let device_rect = (world_backdrop_rect * frame_context.global_device_pixel_scale).round();
5884
5885 if let Some(backdrop_surface) = &mut tile_cache.backdrop_surface {
5888 backdrop_surface.device_rect = device_rect;
5889 } else {
5890 tile_cache.backdrop_surface = Some(BackdropSurface {
5892 id: frame_state.resource_cache.create_compositor_backdrop_surface(color),
5893 color,
5894 device_rect,
5895 });
5896 }
5897 }
5898 }
5899 }
5900
5901 if !backdrop_in_use_and_visible {
5902 if let Some(backdrop_surface) = &tile_cache.backdrop_surface {
5903 frame_state.resource_cache.destroy_compositor_surface(backdrop_surface.id);
5906 tile_cache.backdrop_surface = None;
5907 }
5908 }
5909
5910 if frame_context.debug_flags.contains(DebugFlags::INVALIDATION_DBG) {
5912 tile_cache.print();
5913 }
5914
5915 if frame_context.fb_config.testing {
5918 frame_state.composite_state
5919 .picture_cache_debug
5920 .slices
5921 .insert(
5922 tile_cache.slice,
5923 debug_info,
5924 );
5925 }
5926
5927 let descriptor = SurfaceDescriptor::new_tiled(surface_render_tasks);
5928
5929 frame_state.surface_builder.push_surface(
5930 surface_index,
5931 false,
5932 surface_local_dirty_rect,
5933 Some(descriptor),
5934 frame_state.surfaces,
5935 frame_state.rg_builder,
5936 );
5937 }
5938 Some(ref mut raster_config) => {
5939 let (pic_rect, force_scissor_rect) = {
5940 let surface = &frame_state.surfaces[raster_config.surface_index.0];
5941 (surface.clipped_local_rect, surface.force_scissor_rect)
5942 };
5943
5944 let parent_surface_index = parent_surface_index.expect("bug: no parent for child surface");
5945
5946 let local_rect = pic_rect * Scale::new(1.0);
5949
5950 if local_rect != self.prev_local_rect {
5959 match raster_config.composite_mode {
5960 PictureCompositeMode::Filter(Filter::DropShadows(..)) => {
5961 for handle in &self.extra_gpu_data_handles {
5962 frame_state.gpu_cache.invalidate(handle);
5963 }
5964 }
5965 _ => {}
5966 }
5967 self.segments_are_valid = false;
5970 self.prev_local_rect = local_rect;
5971 }
5972
5973 let max_surface_size = frame_context
5974 .fb_config
5975 .max_surface_override
5976 .unwrap_or(MAX_SURFACE_SIZE) as f32;
5977
5978 let surface_rects = match get_surface_rects(
5979 raster_config.surface_index,
5980 &raster_config.composite_mode,
5981 parent_surface_index,
5982 &mut frame_state.surfaces,
5983 frame_context.spatial_tree,
5984 max_surface_size,
5985 force_scissor_rect,
5986 ) {
5987 Some(rects) => rects,
5988 None => return None,
5989 };
5990
5991 let (raster_spatial_node_index, device_pixel_scale) = {
5992 let surface = &frame_state.surfaces[surface_index.0];
5993 (surface.raster_spatial_node_index, surface.device_pixel_scale)
5994 };
5995 let can_use_shared_surface = !self.flags.contains(PictureFlags::IS_RESOLVE_TARGET);
5996
5997 let primary_render_task_id;
5998 let surface_descriptor;
5999 match raster_config.composite_mode {
6000 PictureCompositeMode::TileCache { .. } => {
6001 unreachable!("handled above");
6002 }
6003 PictureCompositeMode::Filter(Filter::Blur { width, height, .. }) => {
6004 let surface = &frame_state.surfaces[raster_config.surface_index.0];
6005 let (width, height) = surface.clamp_blur_radius(width, height);
6006
6007 let width_std_deviation = width * surface.local_scale.0 * device_pixel_scale.0;
6008 let height_std_deviation = height * surface.local_scale.1 * device_pixel_scale.0;
6009 let blur_std_deviation = DeviceSize::new(
6010 width_std_deviation,
6011 height_std_deviation,
6012 );
6013
6014 let original_size = surface_rects.clipped.size();
6015
6016 let adjusted_size = BlurTask::adjusted_blur_source_size(
6020 original_size,
6021 blur_std_deviation,
6022 );
6023
6024 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6025
6026 let uv_rect_kind = calculate_uv_rect_kind(
6029 DeviceRect::from_origin_and_size(surface_rects.clipped.min, adjusted_size.to_f32()),
6030 surface_rects.unclipped,
6031 );
6032
6033 let picture_task_id = frame_state.rg_builder.add().init(
6034 RenderTask::new_dynamic(
6035 adjusted_size,
6036 RenderTaskKind::new_picture(
6037 adjusted_size,
6038 surface_rects.needs_scissor_rect,
6039 surface_rects.clipped.min,
6040 surface_spatial_node_index,
6041 raster_spatial_node_index,
6042 device_pixel_scale,
6043 None,
6044 None,
6045 None,
6046 cmd_buffer_index,
6047 can_use_shared_surface,
6048 )
6049 ).with_uv_rect_kind(uv_rect_kind)
6050 );
6051
6052
6053 let blur_render_task_id = request_render_task(
6054 frame_state,
6055 &self.snapshot,
6056 &surface_rects,
6057 false,
6058 &mut|rg_builder, _, _| {
6059 RenderTask::new_blur(
6060 blur_std_deviation,
6061 picture_task_id,
6062 rg_builder,
6063 RenderTargetKind::Color,
6064 None,
6065 original_size.to_i32(),
6066 )
6067 }
6068 );
6069 primary_render_task_id = blur_render_task_id;
6070
6071 surface_descriptor = SurfaceDescriptor::new_chained(
6072 picture_task_id,
6073 blur_render_task_id,
6074 surface_rects.clipped_local,
6075 );
6076 }
6077 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
6078 let surface = &frame_state.surfaces[raster_config.surface_index.0];
6079
6080 let device_rect = surface_rects.clipped;
6081
6082 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6083
6084 let picture_task_id = frame_state.rg_builder.add().init(
6085 RenderTask::new_dynamic(
6086 surface_rects.task_size,
6087 RenderTaskKind::new_picture(
6088 surface_rects.task_size,
6089 surface_rects.needs_scissor_rect,
6090 device_rect.min,
6091 surface_spatial_node_index,
6092 raster_spatial_node_index,
6093 device_pixel_scale,
6094 None,
6095 None,
6096 None,
6097 cmd_buffer_index,
6098 can_use_shared_surface,
6099 ),
6100 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6101 );
6102
6103 let mut blur_tasks = BlurTaskCache::default();
6104
6105 self.extra_gpu_data_handles.resize(shadows.len(), GpuCacheHandle::new());
6106
6107 let mut blur_render_task_id = picture_task_id;
6108 for shadow in shadows {
6109 let (blur_radius_x, blur_radius_y) = surface.clamp_blur_radius(
6110 shadow.blur_radius,
6111 shadow.blur_radius,
6112 );
6113
6114 blur_render_task_id = RenderTask::new_blur(
6115 DeviceSize::new(
6116 blur_radius_x * surface.local_scale.0 * device_pixel_scale.0,
6117 blur_radius_y * surface.local_scale.1 * device_pixel_scale.0,
6118 ),
6119 picture_task_id,
6120 frame_state.rg_builder,
6121 RenderTargetKind::Color,
6122 Some(&mut blur_tasks),
6123 device_rect.size().to_i32(),
6124 );
6125 }
6126
6127 frame_state.surface_builder.add_picture_render_task(picture_task_id);
6132
6133 primary_render_task_id = blur_render_task_id;
6134 self.secondary_render_task_id = Some(picture_task_id);
6135
6136 surface_descriptor = SurfaceDescriptor::new_chained(
6137 picture_task_id,
6138 blur_render_task_id,
6139 surface_rects.clipped_local,
6140 );
6141 }
6142 PictureCompositeMode::MixBlend(mode) if BlendMode::from_mix_blend_mode(
6143 mode,
6144 frame_context.fb_config.gpu_supports_advanced_blend,
6145 frame_context.fb_config.advanced_blend_is_coherent,
6146 frame_context.fb_config.dual_source_blending_is_supported,
6147 ).is_none() => {
6148 let parent_surface = &frame_state.surfaces[parent_surface_index.0];
6149
6150 let map_pic_to_parent = SpaceMapper::new_with_target(
6156 parent_surface.surface_spatial_node_index,
6157 surface_spatial_node_index,
6158 parent_surface.clipping_rect,
6159 frame_context.spatial_tree,
6160 );
6161 let pic_in_raster_space = map_pic_to_parent
6162 .map(&pic_rect)
6163 .expect("bug: unable to map mix-blend content into parent");
6164
6165 let backdrop_rect = pic_in_raster_space;
6168 let parent_surface_rect = parent_surface.clipping_rect;
6169
6170 let readback_task_id = match backdrop_rect.intersection(&parent_surface_rect) {
6177 Some(available_rect) => {
6178 let backdrop_rect = parent_surface.map_to_device_rect(
6184 &backdrop_rect,
6185 frame_context.spatial_tree,
6186 );
6187
6188 let available_rect = parent_surface.map_to_device_rect(
6189 &available_rect,
6190 frame_context.spatial_tree,
6191 ).round_out();
6192
6193 let backdrop_uv = calculate_uv_rect_kind(
6194 available_rect,
6195 backdrop_rect,
6196 );
6197
6198 frame_state.rg_builder.add().init(
6199 RenderTask::new_dynamic(
6200 available_rect.size().to_i32(),
6201 RenderTaskKind::new_readback(Some(available_rect.min)),
6202 ).with_uv_rect_kind(backdrop_uv)
6203 )
6204 }
6205 None => {
6206 frame_state.rg_builder.add().init(
6207 RenderTask::new_dynamic(
6208 DeviceIntSize::new(16, 16),
6209 RenderTaskKind::new_readback(None),
6210 )
6211 )
6212 }
6213 };
6214
6215 frame_state.surface_builder.add_child_render_task(
6216 readback_task_id,
6217 frame_state.rg_builder,
6218 );
6219
6220 self.secondary_render_task_id = Some(readback_task_id);
6221
6222 let task_size = surface_rects.clipped.size().to_i32();
6223
6224 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6225
6226 let is_opaque = false; let render_task_id = request_render_task(
6228 frame_state,
6229 &self.snapshot,
6230 &surface_rects,
6231 is_opaque,
6232 &mut|rg_builder, _, _| {
6233 rg_builder.add().init(
6234 RenderTask::new_dynamic(
6235 task_size,
6236 RenderTaskKind::new_picture(
6237 task_size,
6238 surface_rects.needs_scissor_rect,
6239 surface_rects.clipped.min,
6240 surface_spatial_node_index,
6241 raster_spatial_node_index,
6242 device_pixel_scale,
6243 None,
6244 None,
6245 None,
6246 cmd_buffer_index,
6247 can_use_shared_surface,
6248 )
6249 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6250 )
6251 }
6252 );
6253
6254 primary_render_task_id = render_task_id;
6255
6256 surface_descriptor = SurfaceDescriptor::new_simple(
6257 render_task_id,
6258 surface_rects.clipped_local,
6259 );
6260 }
6261 PictureCompositeMode::Filter(..) => {
6262 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6263
6264 let is_opaque = false; let render_task_id = request_render_task(
6266 frame_state,
6267 &self.snapshot,
6268 &surface_rects,
6269 is_opaque,
6270 &mut|rg_builder, _, _| {
6271 rg_builder.add().init(
6272 RenderTask::new_dynamic(
6273 surface_rects.task_size,
6274 RenderTaskKind::new_picture(
6275 surface_rects.task_size,
6276 surface_rects.needs_scissor_rect,
6277 surface_rects.clipped.min,
6278 surface_spatial_node_index,
6279 raster_spatial_node_index,
6280 device_pixel_scale,
6281 None,
6282 None,
6283 None,
6284 cmd_buffer_index,
6285 can_use_shared_surface,
6286 )
6287 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6288 )
6289 },
6290 );
6291
6292 primary_render_task_id = render_task_id;
6293
6294 surface_descriptor = SurfaceDescriptor::new_simple(
6295 render_task_id,
6296 surface_rects.clipped_local,
6297 );
6298 }
6299 PictureCompositeMode::ComponentTransferFilter(..) => {
6300 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6301
6302 let is_opaque = false; let render_task_id = request_render_task(
6304 frame_state,
6305 &self.snapshot,
6306 &surface_rects,
6307 is_opaque,
6308 &mut|rg_builder, _, _| {
6309 rg_builder.add().init(
6310 RenderTask::new_dynamic(
6311 surface_rects.task_size,
6312 RenderTaskKind::new_picture(
6313 surface_rects.task_size,
6314 surface_rects.needs_scissor_rect,
6315 surface_rects.clipped.min,
6316 surface_spatial_node_index,
6317 raster_spatial_node_index,
6318 device_pixel_scale,
6319 None,
6320 None,
6321 None,
6322 cmd_buffer_index,
6323 can_use_shared_surface,
6324 )
6325 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6326 )
6327 }
6328 );
6329
6330 primary_render_task_id = render_task_id;
6331
6332 surface_descriptor = SurfaceDescriptor::new_simple(
6333 render_task_id,
6334 surface_rects.clipped_local,
6335 );
6336 }
6337 PictureCompositeMode::MixBlend(..) |
6338 PictureCompositeMode::Blit(_) => {
6339 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6340
6341 let is_opaque = false; let render_task_id = request_render_task(
6343 frame_state,
6344 &self.snapshot,
6345 &surface_rects,
6346 is_opaque,
6347 &mut|rg_builder, _, _| {
6348 rg_builder.add().init(
6349 RenderTask::new_dynamic(
6350 surface_rects.task_size,
6351 RenderTaskKind::new_picture(
6352 surface_rects.task_size,
6353 surface_rects.needs_scissor_rect,
6354 surface_rects.clipped.min,
6355 surface_spatial_node_index,
6356 raster_spatial_node_index,
6357 device_pixel_scale,
6358 None,
6359 None,
6360 None,
6361 cmd_buffer_index,
6362 can_use_shared_surface,
6363 )
6364 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6365 )
6366 }
6367 );
6368
6369 primary_render_task_id = render_task_id;
6370
6371 surface_descriptor = SurfaceDescriptor::new_simple(
6372 render_task_id,
6373 surface_rects.clipped_local,
6374 );
6375 }
6376 PictureCompositeMode::IntermediateSurface => {
6377 if !scratch.required_sub_graphs.contains(&pic_index) {
6378 return None;
6379 }
6380
6381 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6384
6385 let is_opaque = false; let render_task_id = request_render_task(
6387 frame_state,
6388 &self.snapshot,
6389 &surface_rects,
6390 is_opaque,
6391 &mut|rg_builder, _, _| {
6392 rg_builder.add().init(
6393 RenderTask::new_dynamic(
6394 surface_rects.task_size,
6395 RenderTaskKind::new_picture(
6396 surface_rects.task_size,
6397 surface_rects.needs_scissor_rect,
6398 surface_rects.clipped.min,
6399 surface_spatial_node_index,
6400 raster_spatial_node_index,
6401 device_pixel_scale,
6402 None,
6403 None,
6404 None,
6405 cmd_buffer_index,
6406 can_use_shared_surface,
6407 )
6408 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6409 )
6410 }
6411 );
6412
6413 primary_render_task_id = render_task_id;
6414
6415 surface_descriptor = SurfaceDescriptor::new_simple(
6416 render_task_id,
6417 surface_rects.clipped_local,
6418 );
6419 }
6420 PictureCompositeMode::SvgFilter(ref primitives, ref filter_datas) => {
6421 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6422
6423 let picture_task_id = frame_state.rg_builder.add().init(
6424 RenderTask::new_dynamic(
6425 surface_rects.task_size,
6426 RenderTaskKind::new_picture(
6427 surface_rects.task_size,
6428 surface_rects.needs_scissor_rect,
6429 surface_rects.clipped.min,
6430 surface_spatial_node_index,
6431 raster_spatial_node_index,
6432 device_pixel_scale,
6433 None,
6434 None,
6435 None,
6436 cmd_buffer_index,
6437 can_use_shared_surface,
6438 )
6439 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6440 );
6441
6442 let is_opaque = false; let filter_task_id = request_render_task(
6444 frame_state,
6445 &self.snapshot,
6446 &surface_rects,
6447 is_opaque,
6448 &mut|rg_builder, _, _| {
6449 RenderTask::new_svg_filter(
6450 primitives,
6451 filter_datas,
6452 rg_builder,
6453 surface_rects.clipped.size().to_i32(),
6454 surface_rects.uv_rect_kind,
6455 picture_task_id,
6456 device_pixel_scale,
6457 )
6458 }
6459 );
6460
6461 primary_render_task_id = filter_task_id;
6462
6463 surface_descriptor = SurfaceDescriptor::new_chained(
6464 picture_task_id,
6465 filter_task_id,
6466 surface_rects.clipped_local,
6467 );
6468 }
6469 PictureCompositeMode::SVGFEGraph(ref filters) => {
6470 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6471
6472 let prim_subregion = surface_rects.unclipped;
6474 let target_subregion = surface_rects.clipped;
6476 let source_subregion = surface_rects.source;
6479
6480 let source_task_size = source_subregion.round_out().size().to_i32();
6483 let source_task_size = if source_task_size.width > 0 && source_task_size.height > 0 {
6484 source_task_size
6485 } else {
6486 DeviceIntSize::new(1,1)
6487 };
6488 let picture_task_id = frame_state.rg_builder.add().init(
6489 RenderTask::new_dynamic(
6490 source_task_size,
6491 RenderTaskKind::new_picture(
6492 source_task_size,
6493 surface_rects.needs_scissor_rect,
6494 source_subregion.min,
6495 surface_spatial_node_index,
6496 raster_spatial_node_index,
6497 device_pixel_scale,
6498 None,
6499 None,
6500 None,
6501 cmd_buffer_index,
6502 can_use_shared_surface,
6503 )
6504 )
6505 );
6506
6507 let subregion_to_device_scale_x = surface_rects.clipped_notsnapped.width() / surface_rects.clipped_local.width();
6511 let subregion_to_device_scale_y = surface_rects.clipped_notsnapped.height() / surface_rects.clipped_local.height();
6512 let subregion_to_device_offset_x = surface_rects.clipped_notsnapped.min.x - (surface_rects.clipped_local.min.x * subregion_to_device_scale_x).floor();
6513 let subregion_to_device_offset_y = surface_rects.clipped_notsnapped.min.y - (surface_rects.clipped_local.min.y * subregion_to_device_scale_y).floor();
6514
6515 let filter_task_id = request_render_task(
6518 frame_state,
6519 &self.snapshot,
6520 &surface_rects,
6521 false,
6522 &mut|rg_builder, _, gpu_cache| {
6523 RenderTask::new_svg_filter_graph(
6524 filters,
6525 rg_builder,
6526 gpu_cache,
6527 data_stores,
6528 surface_rects.uv_rect_kind,
6529 picture_task_id,
6530 source_subregion.cast_unit(),
6531 target_subregion.cast_unit(),
6532 prim_subregion.cast_unit(),
6533 subregion_to_device_scale_x,
6534 subregion_to_device_scale_y,
6535 subregion_to_device_offset_x,
6536 subregion_to_device_offset_y,
6537 )
6538 }
6539 );
6540
6541 primary_render_task_id = filter_task_id;
6542
6543 surface_descriptor = SurfaceDescriptor::new_chained(
6544 picture_task_id,
6545 filter_task_id,
6546 surface_rects.clipped_local,
6547 );
6548 }
6549 }
6550
6551 let is_sub_graph = self.flags.contains(PictureFlags::IS_SUB_GRAPH);
6552
6553 frame_state.surface_builder.push_surface(
6554 raster_config.surface_index,
6555 is_sub_graph,
6556 surface_rects.clipped_local,
6557 Some(surface_descriptor),
6558 frame_state.surfaces,
6559 frame_state.rg_builder,
6560 );
6561
6562 self.primary_render_task_id = Some(primary_render_task_id);
6563 }
6564 None => {}
6565 };
6566
6567 let state = PictureState {
6568 map_local_to_pic,
6569 map_pic_to_vis,
6570 };
6571
6572 let mut dirty_region_count = 0;
6573
6574 if let Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) = self.raster_config {
6577 let dirty_region = tile_caches[&slice_id].dirty_region.clone();
6578 frame_state.push_dirty_region(dirty_region);
6579
6580 dirty_region_count += 1;
6581 }
6582
6583 let subpixel_mode = match self.raster_config {
6586 Some(RasterConfig { ref composite_mode, .. }) => {
6587 let subpixel_mode = match composite_mode {
6588 PictureCompositeMode::TileCache { slice_id } => {
6589 tile_caches[&slice_id].subpixel_mode
6590 }
6591 PictureCompositeMode::Blit(..) |
6592 PictureCompositeMode::ComponentTransferFilter(..) |
6593 PictureCompositeMode::Filter(..) |
6594 PictureCompositeMode::MixBlend(..) |
6595 PictureCompositeMode::IntermediateSurface |
6596 PictureCompositeMode::SvgFilter(..) |
6597 PictureCompositeMode::SVGFEGraph(..) => {
6598 SubpixelMode::Deny
6603 }
6604 };
6605
6606 subpixel_mode
6607 }
6608 None => {
6609 SubpixelMode::Allow
6610 }
6611 };
6612
6613 let subpixel_mode = match (parent_subpixel_mode, subpixel_mode) {
6615 (SubpixelMode::Allow, SubpixelMode::Allow) => {
6616 SubpixelMode::Allow
6618 }
6619 (SubpixelMode::Allow, SubpixelMode::Conditional { allowed_rect, prohibited_rect }) => {
6620 SubpixelMode::Conditional {
6622 allowed_rect,
6623 prohibited_rect,
6624 }
6625 }
6626 (SubpixelMode::Conditional { allowed_rect, prohibited_rect }, SubpixelMode::Allow) => {
6627 SubpixelMode::Conditional {
6629 allowed_rect,
6630 prohibited_rect,
6631 }
6632 }
6633 (SubpixelMode::Conditional { .. }, SubpixelMode::Conditional { ..}) => {
6634 unreachable!("bug: only top level picture caches have conditional subpixel");
6635 }
6636 (SubpixelMode::Deny, _) | (_, SubpixelMode::Deny) => {
6637 SubpixelMode::Deny
6639 }
6640 };
6641
6642 let context = PictureContext {
6643 pic_index,
6644 raster_spatial_node_index: frame_state.surfaces[surface_index.0].raster_spatial_node_index,
6645 visibility_spatial_node_index: frame_context.root_spatial_node_index,
6647 surface_spatial_node_index,
6648 surface_index,
6649 dirty_region_count,
6650 subpixel_mode,
6651 };
6652
6653 let prim_list = mem::replace(&mut self.prim_list, PrimitiveList::empty());
6654
6655 Some((context, state, prim_list))
6656 }
6657
6658 pub fn restore_context(
6659 &mut self,
6660 pic_index: PictureIndex,
6661 prim_list: PrimitiveList,
6662 context: PictureContext,
6663 prim_instances: &[PrimitiveInstance],
6664 frame_context: &FrameBuildingContext,
6665 frame_state: &mut FrameBuildingState,
6666 ) {
6667 for _ in 0 .. context.dirty_region_count {
6669 frame_state.pop_dirty_region();
6670 }
6671
6672 if self.raster_config.is_some() {
6673 frame_state.surface_builder.pop_surface(
6674 pic_index,
6675 frame_state.rg_builder,
6676 frame_state.cmd_buffers,
6677 );
6678 }
6679
6680 if let Picture3DContext::In { root_data: Some(ref mut list), plane_splitter_index, .. } = self.context_3d {
6681 let splitter = &mut frame_state.plane_splitters[plane_splitter_index.0];
6682
6683 PicturePrimitive::resolve_split_planes(
6685 splitter,
6686 list,
6687 &mut frame_state.gpu_cache,
6688 &frame_context.spatial_tree,
6689 );
6690
6691 let mut cmd_buffer_targets = Vec::new();
6693 for child in list {
6694 let child_prim_instance = &prim_instances[child.anchor.instance_index.0 as usize];
6695
6696 if frame_state.surface_builder.get_cmd_buffer_targets_for_prim(
6697 &child_prim_instance.vis,
6698 &mut cmd_buffer_targets,
6699 ) {
6700 let prim_cmd = PrimitiveCommand::complex(
6701 child.anchor.instance_index,
6702 child.gpu_address
6703 );
6704
6705 frame_state.push_prim(
6706 &prim_cmd,
6707 child.anchor.spatial_node_index,
6708 &cmd_buffer_targets,
6709 );
6710 }
6711 }
6712 }
6713
6714 self.prim_list = prim_list;
6715 }
6716
6717 pub fn add_split_plane(
6721 splitter: &mut PlaneSplitter,
6722 spatial_tree: &SpatialTree,
6723 prim_spatial_node_index: SpatialNodeIndex,
6724 visibility_spatial_node_index: SpatialNodeIndex,
6727 original_local_rect: LayoutRect,
6728 combined_local_clip_rect: &LayoutRect,
6729 dirty_rect: VisRect,
6730 plane_split_anchor: PlaneSplitAnchor,
6731 ) -> bool {
6732 let transform = spatial_tree.get_relative_transform(
6733 prim_spatial_node_index,
6734 visibility_spatial_node_index
6735 );
6736
6737 let matrix = transform.clone().into_transform().cast().to_untyped();
6738
6739 let local_rect = match original_local_rect
6746 .intersection(combined_local_clip_rect)
6747 {
6748 Some(rect) => rect.cast(),
6749 None => return false,
6750 };
6751 let dirty_rect = dirty_rect.cast();
6752
6753 match transform {
6754 CoordinateSpaceMapping::Local => {
6755 let polygon = Polygon::from_rect(
6756 local_rect.to_rect() * Scale::new(1.0),
6757 plane_split_anchor,
6758 );
6759 splitter.add(polygon);
6760 }
6761 CoordinateSpaceMapping::ScaleOffset(scale_offset) if scale_offset.scale == Vector2D::new(1.0, 1.0) => {
6762 let inv_matrix = scale_offset.inverse().to_transform().cast();
6763 let polygon = Polygon::from_transformed_rect_with_inverse(
6764 local_rect.to_rect().to_untyped(),
6765 &matrix,
6766 &inv_matrix,
6767 plane_split_anchor,
6768 ).unwrap();
6769 splitter.add(polygon);
6770 }
6771 CoordinateSpaceMapping::ScaleOffset(_) |
6772 CoordinateSpaceMapping::Transform(_) => {
6773 let mut clipper = Clipper::new();
6774 let results = clipper.clip_transformed(
6775 Polygon::from_rect(
6776 local_rect.to_rect().to_untyped(),
6777 plane_split_anchor,
6778 ),
6779 &matrix,
6780 Some(dirty_rect.to_rect().to_untyped()),
6781 );
6782 if let Ok(results) = results {
6783 for poly in results {
6784 splitter.add(poly);
6785 }
6786 }
6787 }
6788 }
6789
6790 true
6791 }
6792
6793 fn resolve_split_planes(
6794 splitter: &mut PlaneSplitter,
6795 ordered: &mut Vec<OrderedPictureChild>,
6796 gpu_cache: &mut GpuCache,
6797 spatial_tree: &SpatialTree,
6798 ) {
6799 ordered.clear();
6800
6801 let sorted = splitter.sort(vec3(0.0, 0.0, 1.0));
6804 ordered.reserve(sorted.len());
6805 for poly in sorted {
6806 let transform = match spatial_tree
6807 .get_world_transform(poly.anchor.spatial_node_index)
6808 .inverse()
6809 {
6810 Some(transform) => transform.into_transform(),
6811 None => continue,
6813 };
6814
6815 let local_points = [
6816 transform.transform_point3d(poly.points[0].cast_unit().to_f32()),
6817 transform.transform_point3d(poly.points[1].cast_unit().to_f32()),
6818 transform.transform_point3d(poly.points[2].cast_unit().to_f32()),
6819 transform.transform_point3d(poly.points[3].cast_unit().to_f32()),
6820 ];
6821
6822 if local_points.iter().any(|p| p.is_none()) {
6825 continue;
6826 }
6827
6828 let p0 = local_points[0].unwrap();
6829 let p1 = local_points[1].unwrap();
6830 let p2 = local_points[2].unwrap();
6831 let p3 = local_points[3].unwrap();
6832 let gpu_blocks = [
6833 [p0.x, p0.y, p1.x, p1.y].into(),
6834 [p2.x, p2.y, p3.x, p3.y].into(),
6835 ];
6836 let gpu_handle = gpu_cache.push_per_frame_blocks(&gpu_blocks);
6837 let gpu_address = gpu_cache.get_address(&gpu_handle);
6838
6839 ordered.push(OrderedPictureChild {
6840 anchor: poly.anchor,
6841 gpu_address,
6842 });
6843 }
6844 }
6845
6846 pub fn pre_update(
6849 &mut self,
6850 frame_context: &FrameBuildingContext,
6851 ) {
6852 self.resolve_scene_properties(frame_context.scene_properties);
6854 }
6855
6856 pub fn assign_surface(
6860 &mut self,
6861 frame_context: &FrameBuildingContext,
6862 parent_surface_index: Option<SurfaceIndex>,
6863 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
6864 surfaces: &mut Vec<SurfaceInfo>,
6865 ) -> Option<SurfaceIndex> {
6866 self.raster_config = None;
6868
6869 match self.composite_mode {
6870 Some(ref composite_mode) => {
6871 let surface_spatial_node_index = self.spatial_node_index;
6872
6873 let mut min_scale;
6875 let mut max_scale = 1.0e32;
6876
6877 let world_scale_factors = match parent_surface_index {
6881 Some(parent_surface_index) => {
6882 let parent_surface = &surfaces[parent_surface_index.0];
6883
6884 let local_to_surface = frame_context
6885 .spatial_tree
6886 .get_relative_transform(
6887 surface_spatial_node_index,
6888 parent_surface.surface_spatial_node_index,
6889 );
6890
6891 let scale_factors = if local_to_surface.is_perspective() {
6898 (1.0, 1.0)
6899 } else {
6900 local_to_surface.scale_factors()
6901 };
6902
6903 let scale_factors = (
6904 scale_factors.0 * parent_surface.world_scale_factors.0,
6905 scale_factors.1 * parent_surface.world_scale_factors.1,
6906 );
6907
6908 scale_factors
6909 }
6910 None => {
6911 let local_to_surface_scale_factors = frame_context
6912 .spatial_tree
6913 .get_relative_transform(
6914 surface_spatial_node_index,
6915 frame_context.spatial_tree.root_reference_frame_index(),
6916 )
6917 .scale_factors();
6918
6919 let scale_factors = (
6920 local_to_surface_scale_factors.0,
6921 local_to_surface_scale_factors.1,
6922 );
6923
6924 scale_factors
6925 }
6926 };
6927
6928 let allow_snapping = !self.flags.contains(PictureFlags::DISABLE_SNAPPING);
6935
6936 let force_scissor_rect = self.prim_list.needs_scissor_rect;
6945
6946 let (device_pixel_scale, raster_spatial_node_index, local_scale, world_scale_factors) = match composite_mode {
6949 PictureCompositeMode::TileCache { slice_id } => {
6950 let tile_cache = tile_caches.get_mut(&slice_id).unwrap();
6951
6952 let local_to_device = get_relative_scale_offset(
6954 tile_cache.spatial_node_index,
6955 frame_context.root_spatial_node_index,
6956 frame_context.spatial_tree,
6957 );
6958 let local_to_cur_raster_scale = local_to_device.scale.x / tile_cache.current_raster_scale;
6959
6960 if !frame_context.fb_config.low_quality_pinch_zoom
6968 || !frame_context
6969 .spatial_tree.get_spatial_node(tile_cache.spatial_node_index)
6970 .is_ancestor_or_self_zooming
6971 || local_to_cur_raster_scale <= 0.5
6972 || local_to_cur_raster_scale >= 2.0
6973 {
6974 tile_cache.current_raster_scale = local_to_device.scale.x;
6975 }
6976
6977 min_scale = 0.0;
6979
6980 if frame_context.fb_config.low_quality_pinch_zoom {
6981 min_scale = tile_cache.current_raster_scale;
6985 max_scale = tile_cache.current_raster_scale;
6986 }
6987
6988 let scaling_factor = world_scale_factors.0.max(world_scale_factors.1).max(min_scale).min(max_scale);
6990
6991 let device_pixel_scale = Scale::new(scaling_factor);
6992
6993 (device_pixel_scale, surface_spatial_node_index, (1.0, 1.0), world_scale_factors)
6994 }
6995 _ => {
6996 let surface_spatial_node = frame_context.spatial_tree.get_spatial_node(surface_spatial_node_index);
6997
6998 let enable_snapping =
6999 allow_snapping &&
7000 surface_spatial_node.coordinate_system_id == CoordinateSystemId::root() &&
7001 surface_spatial_node.snapping_transform.is_some();
7002
7003 if enable_snapping {
7004 let raster_spatial_node_index = frame_context.spatial_tree.root_reference_frame_index();
7005
7006 let local_to_raster_transform = frame_context
7007 .spatial_tree
7008 .get_relative_transform(
7009 self.spatial_node_index,
7010 raster_spatial_node_index,
7011 );
7012
7013 let local_scale = local_to_raster_transform.scale_factors();
7014
7015 (Scale::new(1.0), raster_spatial_node_index, local_scale, (1.0, 1.0))
7016 } else {
7017 let world_scale_factors = match self.raster_space {
7020 RasterSpace::Screen => world_scale_factors,
7021 RasterSpace::Local(scale) => (scale, scale),
7022 };
7023
7024 let device_pixel_scale = Scale::new(
7025 world_scale_factors.0.max(world_scale_factors.1).min(max_scale)
7026 );
7027
7028 (device_pixel_scale, surface_spatial_node_index, (1.0, 1.0), world_scale_factors)
7029 }
7030 }
7031 };
7032
7033 let surface = SurfaceInfo::new(
7034 surface_spatial_node_index,
7035 raster_spatial_node_index,
7036 frame_context.global_screen_world_rect,
7037 &frame_context.spatial_tree,
7038 device_pixel_scale,
7039 world_scale_factors,
7040 local_scale,
7041 allow_snapping,
7042 force_scissor_rect,
7043 );
7044
7045 let surface_index = SurfaceIndex(surfaces.len());
7046
7047 surfaces.push(surface);
7048
7049 self.raster_config = Some(RasterConfig {
7050 composite_mode: composite_mode.clone(),
7051 surface_index,
7052 });
7053
7054 Some(surface_index)
7055 }
7056 None => {
7057 None
7058 }
7059 }
7060 }
7061
7062 pub fn propagate_bounding_rect(
7067 &mut self,
7068 surface_index: SurfaceIndex,
7069 parent_surface_index: Option<SurfaceIndex>,
7070 surfaces: &mut [SurfaceInfo],
7071 frame_context: &FrameBuildingContext,
7072 ) {
7073 let surface = &mut surfaces[surface_index.0];
7074
7075 for cluster in &mut self.prim_list.clusters {
7076 cluster.flags.remove(ClusterFlags::IS_VISIBLE);
7077
7078 if !cluster.flags.contains(ClusterFlags::IS_BACKFACE_VISIBLE) {
7080 if let Picture3DContext::In { ancestor_index, .. } = self.context_3d {
7083 let mut face = VisibleFace::Front;
7084 frame_context.spatial_tree.get_relative_transform_with_face(
7085 cluster.spatial_node_index,
7086 ancestor_index,
7087 Some(&mut face),
7088 );
7089 if face == VisibleFace::Back {
7090 continue
7091 }
7092 }
7093 }
7094
7095 let spatial_node = &frame_context
7097 .spatial_tree
7098 .get_spatial_node(cluster.spatial_node_index);
7099 if !spatial_node.invertible {
7100 continue;
7101 }
7102
7103 surface.map_local_to_picture.set_target_spatial_node(
7106 cluster.spatial_node_index,
7107 frame_context.spatial_tree,
7108 );
7109
7110 cluster.flags.insert(ClusterFlags::IS_VISIBLE);
7113 if let Some(cluster_rect) = surface.map_local_to_picture.map(&cluster.bounding_rect) {
7114 surface.unclipped_local_rect = surface.unclipped_local_rect.union(&cluster_rect);
7115 }
7116 }
7117
7118 if let Some(ref mut raster_config) = self.raster_config {
7122 if let Some(parent_surface_index) = parent_surface_index {
7124 let surface_rect = raster_config.composite_mode.get_coverage(
7125 surface,
7126 Some(surface.unclipped_local_rect.cast_unit()),
7127 );
7128
7129 let parent_surface = &mut surfaces[parent_surface_index.0];
7130 parent_surface.map_local_to_picture.set_target_spatial_node(
7131 self.spatial_node_index,
7132 frame_context.spatial_tree,
7133 );
7134
7135 if let Some(parent_surface_rect) = parent_surface
7139 .map_local_to_picture
7140 .map(&surface_rect)
7141 {
7142 parent_surface.unclipped_local_rect =
7143 parent_surface.unclipped_local_rect.union(&parent_surface_rect);
7144 }
7145 }
7146 }
7147 }
7148
7149 pub fn prepare_for_render(
7150 &mut self,
7151 frame_state: &mut FrameBuildingState,
7152 data_stores: &mut DataStores,
7153 ) -> bool {
7154 let raster_config = match self.raster_config {
7155 Some(ref mut raster_config) => raster_config,
7156 None => {
7157 return true
7158 }
7159 };
7160
7161 match raster_config.composite_mode {
7169 PictureCompositeMode::TileCache { .. } => {}
7170 PictureCompositeMode::Filter(Filter::Blur { .. }) => {}
7171 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
7172 self.extra_gpu_data_handles.resize(shadows.len(), GpuCacheHandle::new());
7173 for (shadow, extra_handle) in shadows.iter().zip(self.extra_gpu_data_handles.iter_mut()) {
7174 if let Some(mut request) = frame_state.gpu_cache.request(extra_handle) {
7175 let surface = &frame_state.surfaces[raster_config.surface_index.0];
7176 let prim_rect = surface.clipped_local_rect.cast_unit();
7177
7178 let (blur_inflation_x, blur_inflation_y) = surface.clamp_blur_radius(
7182 shadow.blur_radius,
7183 shadow.blur_radius,
7184 );
7185
7186 let shadow_rect = prim_rect.inflate(
7187 blur_inflation_x * BLUR_SAMPLE_SCALE,
7188 blur_inflation_y * BLUR_SAMPLE_SCALE,
7189 ).translate(shadow.offset);
7190
7191 request.push(shadow.color.premultiplied());
7193 request.push(PremultipliedColorF::WHITE);
7194 request.push([
7195 shadow_rect.width(),
7196 shadow_rect.height(),
7197 0.0,
7198 0.0,
7199 ]);
7200
7201 request.push(shadow_rect);
7203 request.push([0.0, 0.0, 0.0, 0.0]);
7204 }
7205 }
7206 }
7207 PictureCompositeMode::Filter(ref filter) => {
7208 match *filter {
7209 Filter::ColorMatrix(ref m) => {
7210 if self.extra_gpu_data_handles.is_empty() {
7211 self.extra_gpu_data_handles.push(GpuCacheHandle::new());
7212 }
7213 if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handles[0]) {
7214 for i in 0..5 {
7215 request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
7216 }
7217 }
7218 }
7219 Filter::Flood(ref color) => {
7220 if self.extra_gpu_data_handles.is_empty() {
7221 self.extra_gpu_data_handles.push(GpuCacheHandle::new());
7222 }
7223 if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handles[0]) {
7224 request.push(color.to_array());
7225 }
7226 }
7227 _ => {}
7228 }
7229 }
7230 PictureCompositeMode::ComponentTransferFilter(handle) => {
7231 let filter_data = &mut data_stores.filter_data[handle];
7232 filter_data.update(&mut frame_state.gpu_cache);
7233 }
7234 PictureCompositeMode::MixBlend(..) |
7235 PictureCompositeMode::Blit(_) |
7236 PictureCompositeMode::IntermediateSurface |
7237 PictureCompositeMode::SvgFilter(..) => {}
7238 PictureCompositeMode::SVGFEGraph(ref filters) => {
7239 for (_node, op) in filters {
7241 match op {
7242 FilterGraphOp::SVGFEComponentTransferInterned { handle, creates_pixels: _ } => {
7243 let filter_data = &mut data_stores.filter_data[*handle];
7244 filter_data.update(&mut frame_state.gpu_cache);
7245 }
7246 _ => {}
7247 }
7248 }
7249 }
7250 }
7251
7252 true
7253 }
7254
7255 #[cold]
7256 fn draw_debug_overlay(
7257 &self,
7258 parent_surface_index: Option<SurfaceIndex>,
7259 frame_state: &FrameBuildingState,
7260 frame_context: &FrameBuildingContext,
7261 tile_caches: &FastHashMap<SliceId, Box<TileCacheInstance>>,
7262 scratch: &mut PrimitiveScratchBuffer,
7263 ) {
7264 fn draw_debug_border(
7265 local_rect: &PictureRect,
7266 thickness: i32,
7267 pic_to_world_mapper: &SpaceMapper<PicturePixel, WorldPixel>,
7268 global_device_pixel_scale: DevicePixelScale,
7269 color: ColorF,
7270 scratch: &mut PrimitiveScratchBuffer,
7271 ) {
7272 if let Some(world_rect) = pic_to_world_mapper.map(&local_rect) {
7273 let device_rect = world_rect * global_device_pixel_scale;
7274 scratch.push_debug_rect(
7275 device_rect,
7276 thickness,
7277 color,
7278 ColorF::TRANSPARENT,
7279 );
7280 }
7281 }
7282
7283 let flags = frame_context.debug_flags;
7284 let draw_borders = flags.contains(DebugFlags::PICTURE_BORDERS);
7285 let draw_tile_dbg = flags.contains(DebugFlags::PICTURE_CACHING_DBG);
7286
7287 let surface_index = match &self.raster_config {
7288 Some(raster_config) => raster_config.surface_index,
7289 None => parent_surface_index.expect("bug: no parent"),
7290 };
7291 let surface_spatial_node_index = frame_state
7292 .surfaces[surface_index.0]
7293 .surface_spatial_node_index;
7294
7295 let map_pic_to_world = SpaceMapper::new_with_target(
7296 frame_context.root_spatial_node_index,
7297 surface_spatial_node_index,
7298 frame_context.global_screen_world_rect,
7299 frame_context.spatial_tree,
7300 );
7301
7302 let Some(raster_config) = &self.raster_config else {
7303 return;
7304 };
7305
7306 if draw_borders {
7307 let layer_color;
7308 if let PictureCompositeMode::TileCache { slice_id } = &raster_config.composite_mode {
7309 layer_color = ColorF::new(0.0, 1.0, 0.0, 0.8);
7311
7312 let Some(tile_cache) = tile_caches.get(&slice_id) else {
7313 return;
7314 };
7315
7316 for (_, sub_slice) in tile_cache.sub_slices.iter().enumerate() {
7318 for tile in sub_slice.tiles.values() {
7319 if !tile.is_visible {
7320 continue;
7321 }
7322 let rect = tile.local_tile_rect.intersection(&tile_cache.local_rect);
7323 if let Some(rect) = rect {
7324 draw_debug_border(
7325 &rect,
7326 1,
7327 &map_pic_to_world,
7328 frame_context.global_device_pixel_scale,
7329 ColorF::new(0.0, 1.0, 0.0, 0.2),
7330 scratch,
7331 );
7332 }
7333 }
7334 }
7335 } else {
7336 layer_color = ColorF::new(1.0, 0.0, 0.0, 0.5);
7338 }
7339
7340 let pic_rect = frame_state
7342 .surfaces[raster_config.surface_index.0]
7343 .unclipped_local_rect;
7344
7345 draw_debug_border(
7346 &pic_rect,
7347 3,
7348 &map_pic_to_world,
7349 frame_context.global_device_pixel_scale,
7350 layer_color,
7351 scratch,
7352 );
7353 }
7354
7355 if draw_tile_dbg && self.is_visible(frame_context.spatial_tree) {
7356 if let PictureCompositeMode::TileCache { slice_id } = &raster_config.composite_mode {
7357 let Some(tile_cache) = tile_caches.get(&slice_id) else {
7358 return;
7359 };
7360 for (sub_slice_index, sub_slice) in tile_cache.sub_slices.iter().enumerate() {
7361 for tile in sub_slice.tiles.values() {
7362 if !tile.is_visible {
7363 continue;
7364 }
7365 tile.root.draw_debug_rects(
7366 &map_pic_to_world,
7367 tile.is_opaque,
7368 tile.current_descriptor.local_valid_rect,
7369 scratch,
7370 frame_context.global_device_pixel_scale,
7371 );
7372
7373 let label_offset = DeviceVector2D::new(
7374 20.0 + sub_slice_index as f32 * 20.0,
7375 30.0 + sub_slice_index as f32 * 20.0,
7376 );
7377 let tile_device_rect = tile.world_tile_rect
7378 * frame_context.global_device_pixel_scale;
7379
7380 if tile_device_rect.height() >= label_offset.y {
7381 let surface = tile.surface.as_ref().expect("no tile surface set!");
7382
7383 scratch.push_debug_string(
7384 tile_device_rect.min + label_offset,
7385 debug_colors::RED,
7386 format!("{:?}: s={} is_opaque={} surface={} sub={}",
7387 tile.id,
7388 tile_cache.slice,
7389 tile.is_opaque,
7390 surface.kind(),
7391 sub_slice_index,
7392 ),
7393 );
7394 }
7395 }
7396 }
7397 }
7398 }
7399 }
7400}
7401
7402fn get_transform_key(
7403 spatial_node_index: SpatialNodeIndex,
7404 cache_spatial_node_index: SpatialNodeIndex,
7405 spatial_tree: &SpatialTree,
7406) -> TransformKey {
7407 spatial_tree.get_relative_transform(
7408 spatial_node_index,
7409 cache_spatial_node_index,
7410 ).into()
7411}
7412
7413#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
7415struct PrimitiveComparisonKey {
7416 prev_index: PrimitiveDependencyIndex,
7417 curr_index: PrimitiveDependencyIndex,
7418}
7419
7420#[derive(Debug, Copy, Clone, PartialEq, PeekPoke, Default)]
7422#[cfg_attr(feature = "capture", derive(Serialize))]
7423#[cfg_attr(feature = "replay", derive(Deserialize))]
7424pub struct ImageDependency {
7425 pub key: ImageKey,
7426 pub generation: ImageGeneration,
7427}
7428
7429impl ImageDependency {
7430 pub const INVALID: ImageDependency = ImageDependency {
7431 key: ImageKey::DUMMY,
7432 generation: ImageGeneration::INVALID,
7433 };
7434}
7435
7436#[derive(Debug)]
7439struct DeferredDirtyTest {
7440 tile_rect: TileRect,
7442 prim_rect: PictureRect,
7444}
7445
7446struct PrimitiveComparer<'a> {
7448 prev_data: &'a [u8],
7449 curr_data: &'a [u8],
7450 prev_frame_id: FrameId,
7451 curr_frame_id: FrameId,
7452 resource_cache: &'a ResourceCache,
7453 spatial_node_comparer: &'a mut SpatialNodeComparer,
7454 opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
7455 color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
7456}
7457
7458impl<'a> PrimitiveComparer<'a> {
7459 fn new(
7460 prev: &'a TileDescriptor,
7461 curr: &'a TileDescriptor,
7462 resource_cache: &'a ResourceCache,
7463 spatial_node_comparer: &'a mut SpatialNodeComparer,
7464 opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
7465 color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
7466 ) -> Self {
7467 PrimitiveComparer {
7468 prev_data: &prev.dep_data,
7469 curr_data: &curr.dep_data,
7470 prev_frame_id: prev.last_updated_frame_id,
7471 curr_frame_id: curr.last_updated_frame_id,
7472 resource_cache,
7473 spatial_node_comparer,
7474 opacity_bindings,
7475 color_bindings,
7476 }
7477 }
7478
7479 fn compare_prim(
7481 &mut self,
7482 prev_desc: &PrimitiveDescriptor,
7483 curr_desc: &PrimitiveDescriptor,
7484 ) -> PrimitiveCompareResult {
7485 let resource_cache = self.resource_cache;
7486 let spatial_node_comparer = &mut self.spatial_node_comparer;
7487 let opacity_bindings = self.opacity_bindings;
7488 let color_bindings = self.color_bindings;
7489
7490 if prev_desc != curr_desc {
7492 return PrimitiveCompareResult::Descriptor;
7493 }
7494
7495 let mut prev_dep_data = &self.prev_data[prev_desc.dep_offset as usize ..];
7496 let mut curr_dep_data = &self.curr_data[curr_desc.dep_offset as usize ..];
7497
7498 let mut prev_dep = PrimitiveDependency::SpatialNode { index: SpatialNodeIndex::INVALID };
7499 let mut curr_dep = PrimitiveDependency::SpatialNode { index: SpatialNodeIndex::INVALID };
7500
7501 debug_assert_eq!(prev_desc.dep_count, curr_desc.dep_count);
7502
7503 for _ in 0 .. prev_desc.dep_count {
7504 prev_dep_data = peek_from_slice(prev_dep_data, &mut prev_dep);
7505 curr_dep_data = peek_from_slice(curr_dep_data, &mut curr_dep);
7506
7507 match (&prev_dep, &curr_dep) {
7508 (PrimitiveDependency::Clip { clip: prev }, PrimitiveDependency::Clip { clip: curr }) => {
7509 if prev != curr {
7510 return PrimitiveCompareResult::Clip;
7511 }
7512 }
7513 (PrimitiveDependency::SpatialNode { index: prev }, PrimitiveDependency::SpatialNode { index: curr }) => {
7514 let prev_key = SpatialNodeKey {
7515 spatial_node_index: *prev,
7516 frame_id: self.prev_frame_id,
7517 };
7518 let curr_key = SpatialNodeKey {
7519 spatial_node_index: *curr,
7520 frame_id: self.curr_frame_id,
7521 };
7522 if !spatial_node_comparer.are_transforms_equivalent(&prev_key, &curr_key) {
7523 return PrimitiveCompareResult::Transform;
7524 }
7525 }
7526 (PrimitiveDependency::OpacityBinding { binding: prev }, PrimitiveDependency::OpacityBinding { binding: curr }) => {
7527 if prev != curr {
7528 return PrimitiveCompareResult::OpacityBinding;
7529 }
7530
7531 if let OpacityBinding::Binding(id) = curr {
7532 if opacity_bindings
7533 .get(id)
7534 .map_or(true, |info| info.changed) {
7535 return PrimitiveCompareResult::OpacityBinding;
7536 }
7537 }
7538 }
7539 (PrimitiveDependency::ColorBinding { binding: prev }, PrimitiveDependency::ColorBinding { binding: curr }) => {
7540 if prev != curr {
7541 return PrimitiveCompareResult::ColorBinding;
7542 }
7543
7544 if let ColorBinding::Binding(id) = curr {
7545 if color_bindings
7546 .get(id)
7547 .map_or(true, |info| info.changed) {
7548 return PrimitiveCompareResult::ColorBinding;
7549 }
7550 }
7551 }
7552 (PrimitiveDependency::Image { image: prev }, PrimitiveDependency::Image { image: curr }) => {
7553 if prev != curr {
7554 return PrimitiveCompareResult::Image;
7555 }
7556
7557 if resource_cache.get_image_generation(curr.key) != curr.generation {
7558 return PrimitiveCompareResult::Image;
7559 }
7560 }
7561 _ => {
7562 return PrimitiveCompareResult::Descriptor;
7564 }
7565 }
7566 }
7567
7568 PrimitiveCompareResult::Equal
7569 }
7570}
7571
7572#[cfg_attr(any(feature="capture",feature="replay"), derive(Clone))]
7574#[cfg_attr(feature = "capture", derive(Serialize))]
7575#[cfg_attr(feature = "replay", derive(Deserialize))]
7576pub enum TileNodeKind {
7577 Leaf {
7578 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
7580 prev_indices: Vec<PrimitiveDependencyIndex>,
7581 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
7583 curr_indices: Vec<PrimitiveDependencyIndex>,
7584 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
7586 dirty_tracker: u64,
7587 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
7589 frames_since_modified: usize,
7590 },
7591 Node {
7592 children: Vec<TileNode>,
7594 },
7595}
7596
7597#[derive(Copy, Clone, PartialEq, Debug)]
7599enum TileModification {
7600 Split,
7601 Merge,
7602}
7603
7604#[cfg_attr(any(feature="capture",feature="replay"), derive(Clone))]
7606#[cfg_attr(feature = "capture", derive(Serialize))]
7607#[cfg_attr(feature = "replay", derive(Deserialize))]
7608pub struct TileNode {
7609 pub kind: TileNodeKind,
7611 pub rect: PictureBox2D,
7613}
7614
7615impl TileNode {
7616 fn new_leaf(curr_indices: Vec<PrimitiveDependencyIndex>) -> Self {
7618 TileNode {
7619 kind: TileNodeKind::Leaf {
7620 prev_indices: Vec::new(),
7621 curr_indices,
7622 dirty_tracker: 0,
7623 frames_since_modified: 0,
7624 },
7625 rect: PictureBox2D::zero(),
7626 }
7627 }
7628
7629 fn draw_debug_rects(
7631 &self,
7632 pic_to_world_mapper: &SpaceMapper<PicturePixel, WorldPixel>,
7633 is_opaque: bool,
7634 local_valid_rect: PictureRect,
7635 scratch: &mut PrimitiveScratchBuffer,
7636 global_device_pixel_scale: DevicePixelScale,
7637 ) {
7638 match self.kind {
7639 TileNodeKind::Leaf { dirty_tracker, .. } => {
7640 let color = if (dirty_tracker & 1) != 0 {
7641 debug_colors::RED
7642 } else if is_opaque {
7643 debug_colors::GREEN
7644 } else {
7645 debug_colors::YELLOW
7646 };
7647
7648 if let Some(local_rect) = local_valid_rect.intersection(&self.rect) {
7649 let world_rect = pic_to_world_mapper
7650 .map(&local_rect)
7651 .unwrap();
7652 let device_rect = world_rect * global_device_pixel_scale;
7653
7654 let outer_color = color.scale_alpha(0.3);
7655 let inner_color = outer_color.scale_alpha(0.5);
7656 scratch.push_debug_rect(
7657 device_rect.inflate(-3.0, -3.0),
7658 1,
7659 outer_color,
7660 inner_color
7661 );
7662 }
7663 }
7664 TileNodeKind::Node { ref children, .. } => {
7665 for child in children.iter() {
7666 child.draw_debug_rects(
7667 pic_to_world_mapper,
7668 is_opaque,
7669 local_valid_rect,
7670 scratch,
7671 global_device_pixel_scale,
7672 );
7673 }
7674 }
7675 }
7676 }
7677
7678 fn get_child_rects(
7680 rect: &PictureBox2D,
7681 result: &mut [PictureBox2D; 4],
7682 ) {
7683 let p0 = rect.min;
7684 let p1 = rect.max;
7685 let pc = p0 + rect.size() * 0.5;
7686
7687 *result = [
7688 PictureBox2D::new(
7689 p0,
7690 pc,
7691 ),
7692 PictureBox2D::new(
7693 PicturePoint::new(pc.x, p0.y),
7694 PicturePoint::new(p1.x, pc.y),
7695 ),
7696 PictureBox2D::new(
7697 PicturePoint::new(p0.x, pc.y),
7698 PicturePoint::new(pc.x, p1.y),
7699 ),
7700 PictureBox2D::new(
7701 pc,
7702 p1,
7703 ),
7704 ];
7705 }
7706
7707 fn clear(
7709 &mut self,
7710 rect: PictureBox2D,
7711 ) {
7712 self.rect = rect;
7713
7714 match self.kind {
7715 TileNodeKind::Leaf { ref mut prev_indices, ref mut curr_indices, ref mut dirty_tracker, ref mut frames_since_modified } => {
7716 mem::swap(prev_indices, curr_indices);
7718 curr_indices.clear();
7719 *dirty_tracker = *dirty_tracker << 1;
7721 *frames_since_modified += 1;
7722 }
7723 TileNodeKind::Node { ref mut children, .. } => {
7724 let mut child_rects = [PictureBox2D::zero(); 4];
7725 TileNode::get_child_rects(&rect, &mut child_rects);
7726 assert_eq!(child_rects.len(), children.len());
7727
7728 for (child, rect) in children.iter_mut().zip(child_rects.iter()) {
7729 child.clear(*rect);
7730 }
7731 }
7732 }
7733 }
7734
7735 fn add_prim(
7737 &mut self,
7738 index: PrimitiveDependencyIndex,
7739 prim_rect: &PictureBox2D,
7740 ) {
7741 match self.kind {
7742 TileNodeKind::Leaf { ref mut curr_indices, .. } => {
7743 curr_indices.push(index);
7744 }
7745 TileNodeKind::Node { ref mut children, .. } => {
7746 for child in children.iter_mut() {
7747 if child.rect.intersects(prim_rect) {
7748 child.add_prim(index, prim_rect);
7749 }
7750 }
7751 }
7752 }
7753 }
7754
7755 fn maybe_merge_or_split(
7757 &mut self,
7758 level: i32,
7759 curr_prims: &[PrimitiveDescriptor],
7760 max_split_levels: i32,
7761 ) {
7762 let mut tile_mod = None;
7764
7765 fn get_dirty_frames(
7766 dirty_tracker: u64,
7767 frames_since_modified: usize,
7768 ) -> Option<u32> {
7769 if frames_since_modified > 64 {
7771 Some(dirty_tracker.count_ones())
7773 } else {
7774 None
7775 }
7776 }
7777
7778 match self.kind {
7779 TileNodeKind::Leaf { dirty_tracker, frames_since_modified, .. } => {
7780 if level < max_split_levels {
7782 if let Some(dirty_frames) = get_dirty_frames(dirty_tracker, frames_since_modified) {
7783 if dirty_frames > 32 {
7785 tile_mod = Some(TileModification::Split);
7786 }
7787 }
7788 }
7789 }
7790 TileNodeKind::Node { ref children, .. } => {
7791 let mut static_count = 0;
7798 let mut changing_count = 0;
7799
7800 for child in children {
7801 if let TileNodeKind::Leaf { dirty_tracker, frames_since_modified, .. } = child.kind {
7803 if let Some(dirty_frames) = get_dirty_frames(dirty_tracker, frames_since_modified) {
7804 if dirty_frames == 0 {
7805 static_count += 1;
7807 } else if dirty_frames == 64 {
7808 changing_count += 1;
7810 }
7811 }
7812 }
7813
7814 if static_count == 4 || changing_count == 4 {
7818 tile_mod = Some(TileModification::Merge);
7819 }
7820 }
7821 }
7822 }
7823
7824 match tile_mod {
7825 Some(TileModification::Split) => {
7826 let curr_indices = match self.kind {
7829 TileNodeKind::Node { .. } => {
7830 unreachable!("bug - only leaves can split");
7831 }
7832 TileNodeKind::Leaf { ref mut curr_indices, .. } => {
7833 curr_indices.take()
7834 }
7835 };
7836
7837 let mut child_rects = [PictureBox2D::zero(); 4];
7838 TileNode::get_child_rects(&self.rect, &mut child_rects);
7839
7840 let mut child_indices = [
7841 Vec::new(),
7842 Vec::new(),
7843 Vec::new(),
7844 Vec::new(),
7845 ];
7846
7847 for index in curr_indices {
7850 let prim = &curr_prims[index.0 as usize];
7851 for (child_rect, indices) in child_rects.iter().zip(child_indices.iter_mut()) {
7852 if prim.prim_clip_box.intersects(child_rect) {
7853 indices.push(index);
7854 }
7855 }
7856 }
7857
7858 let children = child_indices
7860 .iter_mut()
7861 .map(|i| TileNode::new_leaf(mem::replace(i, Vec::new())))
7862 .collect();
7863
7864 self.kind = TileNodeKind::Node {
7865 children,
7866 };
7867 }
7868 Some(TileModification::Merge) => {
7869 let merged_indices = match self.kind {
7872 TileNodeKind::Node { ref mut children, .. } => {
7873 let mut merged_indices = Vec::new();
7874
7875 for child in children.iter() {
7876 let child_indices = match child.kind {
7877 TileNodeKind::Leaf { ref curr_indices, .. } => {
7878 curr_indices
7879 }
7880 TileNodeKind::Node { .. } => {
7881 unreachable!("bug: child is not a leaf");
7882 }
7883 };
7884 merged_indices.extend_from_slice(child_indices);
7885 }
7886
7887 merged_indices.sort();
7888 merged_indices.dedup();
7889
7890 merged_indices
7891 }
7892 TileNodeKind::Leaf { .. } => {
7893 unreachable!("bug - trying to merge a leaf");
7894 }
7895 };
7896
7897 self.kind = TileNodeKind::Leaf {
7899 prev_indices: Vec::new(),
7900 curr_indices: merged_indices,
7901 dirty_tracker: 0,
7902 frames_since_modified: 0,
7903 };
7904 }
7905 None => {
7906 if let TileNodeKind::Node { ref mut children, .. } = self.kind {
7909 for child in children.iter_mut() {
7910 child.maybe_merge_or_split(
7911 level+1,
7912 curr_prims,
7913 max_split_levels,
7914 );
7915 }
7916 }
7917 }
7918 }
7919 }
7920
7921 fn update_dirty_rects(
7923 &mut self,
7924 prev_prims: &[PrimitiveDescriptor],
7925 curr_prims: &[PrimitiveDescriptor],
7926 prim_comparer: &mut PrimitiveComparer,
7927 dirty_rect: &mut PictureBox2D,
7928 compare_cache: &mut FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
7929 invalidation_reason: &mut Option<InvalidationReason>,
7930 frame_context: &FrameVisibilityContext,
7931 ) {
7932 match self.kind {
7933 TileNodeKind::Node { ref mut children, .. } => {
7934 for child in children.iter_mut() {
7935 child.update_dirty_rects(
7936 prev_prims,
7937 curr_prims,
7938 prim_comparer,
7939 dirty_rect,
7940 compare_cache,
7941 invalidation_reason,
7942 frame_context,
7943 );
7944 }
7945 }
7946 TileNodeKind::Leaf { ref prev_indices, ref curr_indices, ref mut dirty_tracker, .. } => {
7947 if prev_indices.len() == curr_indices.len() {
7949 for (prev_index, curr_index) in prev_indices.iter().zip(curr_indices.iter()) {
7951 let i0 = prev_index.0 as usize;
7952 let i1 = curr_index.0 as usize;
7953
7954 let key = PrimitiveComparisonKey {
7957 prev_index: *prev_index,
7958 curr_index: *curr_index,
7959 };
7960
7961 let prim_compare_result = *compare_cache
7962 .entry(key)
7963 .or_insert_with(|| {
7964 let prev = &prev_prims[i0];
7965 let curr = &curr_prims[i1];
7966 prim_comparer.compare_prim(prev, curr)
7967 });
7968
7969 if prim_compare_result != PrimitiveCompareResult::Equal {
7971 if invalidation_reason.is_none() {
7972 *invalidation_reason = Some(InvalidationReason::Content);
7973 }
7974 *dirty_rect = self.rect.union(dirty_rect);
7975 *dirty_tracker = *dirty_tracker | 1;
7976 break;
7977 }
7978 }
7979 } else {
7980 if invalidation_reason.is_none() {
7981 *invalidation_reason = Some(InvalidationReason::PrimCount);
7982 }
7983 *dirty_rect = self.rect.union(dirty_rect);
7984 *dirty_tracker = *dirty_tracker | 1;
7985 }
7986 }
7987 }
7988 }
7989}
7990
7991impl CompositeState {
7992 pub fn destroy_native_tiles<'a, I: Iterator<Item = &'a mut Box<Tile>>>(
7994 &mut self,
7995 tiles_iter: I,
7996 resource_cache: &mut ResourceCache,
7997 ) {
7998 if let CompositorKind::Native { .. } = self.compositor_kind {
8003 for tile in tiles_iter {
8004 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
8008 if let Some(id) = id.take() {
8009 resource_cache.destroy_compositor_tile(id);
8010 }
8011 }
8012 }
8013 }
8014 }
8015}
8016
8017fn get_relative_scale_offset(
8018 child_spatial_node_index: SpatialNodeIndex,
8019 parent_spatial_node_index: SpatialNodeIndex,
8020 spatial_tree: &SpatialTree,
8021) -> ScaleOffset {
8022 let transform = spatial_tree.get_relative_transform(
8023 child_spatial_node_index,
8024 parent_spatial_node_index,
8025 );
8026 let mut scale_offset = match transform {
8027 CoordinateSpaceMapping::Local => ScaleOffset::identity(),
8028 CoordinateSpaceMapping::ScaleOffset(scale_offset) => scale_offset,
8029 CoordinateSpaceMapping::Transform(m) => {
8030 ScaleOffset::from_transform(&m).expect("bug: pictures caches don't support complex transforms")
8031 }
8032 };
8033
8034 scale_offset.offset = scale_offset.offset.round();
8038
8039 scale_offset
8040}
8041
8042pub fn calculate_screen_uv(
8043 p: DevicePoint,
8044 clipped: DeviceRect,
8045) -> DeviceHomogeneousVector {
8046 DeviceHomogeneousVector::new(
8048 (p.x - clipped.min.x) / (clipped.max.x - clipped.min.x),
8049 (p.y - clipped.min.y) / (clipped.max.y - clipped.min.y),
8050 0.0,
8051 1.0,
8052 )
8053}
8054
8055fn get_surface_rects(
8056 surface_index: SurfaceIndex,
8057 composite_mode: &PictureCompositeMode,
8058 parent_surface_index: SurfaceIndex,
8059 surfaces: &mut [SurfaceInfo],
8060 spatial_tree: &SpatialTree,
8061 max_surface_size: f32,
8062 force_scissor_rect: bool,
8063) -> Option<SurfaceAllocInfo> {
8064 let parent_surface = &surfaces[parent_surface_index.0];
8065
8066 let local_to_parent = SpaceMapper::new_with_target(
8067 parent_surface.surface_spatial_node_index,
8068 surfaces[surface_index.0].surface_spatial_node_index,
8069 parent_surface.clipping_rect,
8070 spatial_tree,
8071 );
8072
8073 let local_clip_rect = local_to_parent
8074 .unmap(&parent_surface.clipping_rect)
8075 .unwrap_or(PictureRect::max_rect())
8076 .cast_unit();
8077
8078 let surface = &mut surfaces[surface_index.0];
8079
8080 let (clipped_local, unclipped_local, source_local) = match composite_mode {
8081 PictureCompositeMode::SVGFEGraph(ref filters) => {
8082 let prim_subregion = composite_mode.get_rect(surface, None);
8094
8095 let visible_subregion: LayoutRect =
8098 prim_subregion.cast_unit()
8099 .intersection(&local_clip_rect)
8100 .unwrap_or(PictureRect::zero())
8101 .cast_unit();
8102
8103 if visible_subregion.is_empty() {
8107 return None;
8108 }
8109
8110 let source_potential_subregion = composite_mode.get_coverage_source_svgfe(
8115 filters, visible_subregion.cast_unit());
8116 let source_subregion =
8117 source_potential_subregion
8118 .intersection(&surface.unclipped_local_rect.cast_unit())
8119 .unwrap_or(LayoutRect::zero());
8120
8121 let coverage_subregion = source_subregion.union(&visible_subregion);
8127
8128 (coverage_subregion.cast_unit(), prim_subregion.cast_unit(), source_subregion.cast_unit())
8129 }
8130 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
8131 let local_prim_rect = surface.clipped_local_rect;
8132
8133 let mut required_local_rect = local_prim_rect
8134 .intersection(&local_clip_rect)
8135 .unwrap_or(PictureRect::zero());
8136
8137 for shadow in shadows {
8138 let (blur_radius_x, blur_radius_y) = surface.clamp_blur_radius(
8139 shadow.blur_radius,
8140 shadow.blur_radius,
8141 );
8142 let blur_inflation_x = blur_radius_x * BLUR_SAMPLE_SCALE;
8143 let blur_inflation_y = blur_radius_y * BLUR_SAMPLE_SCALE;
8144
8145 let local_shadow_rect = local_prim_rect
8146 .translate(shadow.offset.cast_unit())
8147 .inflate(blur_inflation_x, blur_inflation_y);
8148
8149 if let Some(clipped_shadow_rect) = local_clip_rect.intersection(&local_shadow_rect) {
8150 let required_shadow_rect = clipped_shadow_rect.inflate(blur_inflation_x, blur_inflation_y);
8151
8152 let local_clipped_shadow_rect = required_shadow_rect.translate(-shadow.offset.cast_unit());
8153
8154 required_local_rect = required_local_rect.union(&local_clipped_shadow_rect);
8155 }
8156 }
8157
8158 let unclipped = composite_mode.get_rect(surface, None);
8159 let clipped = required_local_rect;
8160
8161 let clipped = match clipped.intersection(&unclipped.cast_unit()) {
8162 Some(rect) => rect,
8163 None => return None,
8164 };
8165
8166 (clipped, unclipped, clipped)
8167 }
8168 _ => {
8169 let surface_origin = surface.clipped_local_rect.min.to_vector().cast_unit();
8170
8171 let normalized_prim_rect = composite_mode
8172 .get_rect(surface, None)
8173 .translate(-surface_origin);
8174
8175 let normalized_clip_rect = local_clip_rect
8176 .cast_unit()
8177 .translate(-surface_origin);
8178
8179 let norm_clipped_rect = match normalized_prim_rect.intersection(&normalized_clip_rect) {
8180 Some(rect) => rect,
8181 None => return None,
8182 };
8183
8184 let norm_clipped_rect = composite_mode.get_rect(surface, Some(norm_clipped_rect));
8185
8186 let norm_clipped_rect = match norm_clipped_rect.intersection(&normalized_prim_rect) {
8187 Some(rect) => rect,
8188 None => return None,
8189 };
8190
8191 let unclipped = normalized_prim_rect.translate(surface_origin);
8192 let clipped = norm_clipped_rect.translate(surface_origin);
8193
8194 (clipped.cast_unit(), unclipped.cast_unit(), clipped.cast_unit())
8195 }
8196 };
8197
8198 let (mut clipped, mut unclipped, mut source) = if surface.raster_spatial_node_index != surface.surface_spatial_node_index {
8202 assert_eq!(surface.device_pixel_scale.0, 1.0);
8204
8205 let local_to_world = SpaceMapper::new_with_target(
8206 spatial_tree.root_reference_frame_index(),
8207 surface.surface_spatial_node_index,
8208 WorldRect::max_rect(),
8209 spatial_tree,
8210 );
8211
8212 let clipped = local_to_world.map(&clipped_local.cast_unit()).unwrap() * surface.device_pixel_scale;
8213 let unclipped = local_to_world.map(&unclipped_local).unwrap() * surface.device_pixel_scale;
8214 let source = local_to_world.map(&source_local.cast_unit()).unwrap() * surface.device_pixel_scale;
8215
8216 (clipped, unclipped, source)
8217 } else {
8218 let clipped = clipped_local.cast_unit() * surface.device_pixel_scale;
8220 let unclipped = unclipped_local.cast_unit() * surface.device_pixel_scale;
8221 let source = source_local.cast_unit() * surface.device_pixel_scale;
8222
8223 (clipped, unclipped, source)
8224 };
8225 let mut clipped_snapped = clipped.round_out();
8226 let mut source_snapped = source.round_out();
8227
8228 let max_dimension =
8241 clipped_snapped.width().max(
8242 clipped_snapped.height().max(
8243 source_snapped.width().max(
8244 source_snapped.height()
8245 ))).ceil();
8246 if max_dimension > max_surface_size {
8247 let max_dimension =
8250 clipped_local.width().max(
8251 clipped_local.height().max(
8252 source_local.width().max(
8253 source_local.height()
8254 ))).ceil();
8255 surface.raster_spatial_node_index = surface.surface_spatial_node_index;
8256 surface.device_pixel_scale = Scale::new(max_surface_size / max_dimension);
8257 surface.local_scale = (1.0, 1.0);
8258
8259 let add_markers = profiler::thread_is_being_profiled();
8260 if add_markers {
8261 let new_clipped = (clipped_local.cast_unit() * surface.device_pixel_scale).round();
8262 let new_source = (source_local.cast_unit() * surface.device_pixel_scale).round();
8263 profiler::add_text_marker("SurfaceSizeLimited",
8264 format!("Surface for {:?} reduced from raster {:?} (source {:?}) to local {:?} (source {:?})",
8265 composite_mode.kind(),
8266 clipped.size(), source.size(),
8267 new_clipped, new_source).as_str(),
8268 Duration::from_secs_f32(new_clipped.width() * new_clipped.height() / 1000000000.0));
8269 }
8270
8271 clipped = clipped_local.cast_unit() * surface.device_pixel_scale;
8272 unclipped = unclipped_local.cast_unit() * surface.device_pixel_scale;
8273 source = source_local.cast_unit() * surface.device_pixel_scale;
8274 clipped_snapped = clipped.round();
8275 source_snapped = source.round();
8276 }
8277
8278 let task_size = clipped_snapped.size().to_i32();
8279 let task_size = task_size.min(DeviceIntSize::new(max_surface_size as i32, max_surface_size as i32));
8285 debug_assert!(
8286 task_size.width <= max_surface_size as i32 &&
8287 task_size.height <= max_surface_size as i32,
8288 "task_size {:?} for {:?} must be within max_surface_size {}",
8289 task_size,
8290 composite_mode.kind(),
8291 max_surface_size);
8292
8293 let uv_rect_kind = calculate_uv_rect_kind(
8294 clipped_snapped,
8295 unclipped,
8296 );
8297
8298 if task_size.width == 0 || task_size.height == 0 {
8300 return None;
8301 }
8302
8303 let needs_scissor_rect = force_scissor_rect || !clipped_local.contains_box(&surface.unclipped_local_rect);
8310
8311 Some(SurfaceAllocInfo {
8312 task_size,
8313 needs_scissor_rect,
8314 clipped: clipped_snapped,
8315 unclipped,
8316 source: source_snapped,
8317 clipped_notsnapped: clipped,
8318 clipped_local,
8319 uv_rect_kind,
8320 })
8321}
8322
8323pub fn calculate_uv_rect_kind(
8324 clipped: DeviceRect,
8325 unclipped: DeviceRect,
8326) -> UvRectKind {
8327 let top_left = calculate_screen_uv(
8328 unclipped.top_left().cast_unit(),
8329 clipped,
8330 );
8331
8332 let top_right = calculate_screen_uv(
8333 unclipped.top_right().cast_unit(),
8334 clipped,
8335 );
8336
8337 let bottom_left = calculate_screen_uv(
8338 unclipped.bottom_left().cast_unit(),
8339 clipped,
8340 );
8341
8342 let bottom_right = calculate_screen_uv(
8343 unclipped.bottom_right().cast_unit(),
8344 clipped,
8345 );
8346
8347 UvRectKind::Quad {
8348 top_left,
8349 top_right,
8350 bottom_left,
8351 bottom_right,
8352 }
8353}
8354
8355#[test]
8356fn test_large_surface_scale_1() {
8357 use crate::spatial_tree::{SceneSpatialTree, SpatialTree};
8358
8359 let mut cst = SceneSpatialTree::new();
8360 let root_reference_frame_index = cst.root_reference_frame_index();
8361
8362 let mut spatial_tree = SpatialTree::new();
8363 spatial_tree.apply_updates(cst.end_frame_and_get_pending_updates());
8364 spatial_tree.update_tree(&SceneProperties::new());
8365
8366 let map_local_to_picture = SpaceMapper::new_with_target(
8367 root_reference_frame_index,
8368 root_reference_frame_index,
8369 PictureRect::max_rect(),
8370 &spatial_tree,
8371 );
8372
8373 let mut surfaces = vec![
8374 SurfaceInfo {
8375 unclipped_local_rect: PictureRect::max_rect(),
8376 clipped_local_rect: PictureRect::max_rect(),
8377 is_opaque: true,
8378 clipping_rect: PictureRect::max_rect(),
8379 culling_rect: VisRect::max_rect(),
8380 map_local_to_picture: map_local_to_picture.clone(),
8381 raster_spatial_node_index: root_reference_frame_index,
8382 surface_spatial_node_index: root_reference_frame_index,
8383 visibility_spatial_node_index: root_reference_frame_index,
8384 device_pixel_scale: DevicePixelScale::new(1.0),
8385 world_scale_factors: (1.0, 1.0),
8386 local_scale: (1.0, 1.0),
8387 allow_snapping: true,
8388 force_scissor_rect: false,
8389 },
8390 SurfaceInfo {
8391 unclipped_local_rect: PictureRect::new(
8392 PicturePoint::new(52.76350021362305, 0.0),
8393 PicturePoint::new(159.6738739013672, 35.0),
8394 ),
8395 clipped_local_rect: PictureRect::max_rect(),
8396 is_opaque: true,
8397 clipping_rect: PictureRect::max_rect(),
8398 culling_rect: VisRect::max_rect(),
8399 map_local_to_picture,
8400 raster_spatial_node_index: root_reference_frame_index,
8401 surface_spatial_node_index: root_reference_frame_index,
8402 visibility_spatial_node_index: root_reference_frame_index,
8403 device_pixel_scale: DevicePixelScale::new(43.82798767089844),
8404 world_scale_factors: (1.0, 1.0),
8405 local_scale: (1.0, 1.0),
8406 allow_snapping: true,
8407 force_scissor_rect: false,
8408 },
8409 ];
8410
8411 get_surface_rects(
8412 SurfaceIndex(1),
8413 &PictureCompositeMode::Blit(BlitReason::ISOLATE),
8414 SurfaceIndex(0),
8415 &mut surfaces,
8416 &spatial_tree,
8417 MAX_SURFACE_SIZE as f32,
8418 false,
8419 );
8420}
8421
8422#[test]
8423fn test_drop_filter_dirty_region_outside_prim() {
8424 use api::Shadow;
8430 use crate::spatial_tree::{SceneSpatialTree, SpatialTree};
8431
8432 let mut cst = SceneSpatialTree::new();
8433 let root_reference_frame_index = cst.root_reference_frame_index();
8434
8435 let mut spatial_tree = SpatialTree::new();
8436 spatial_tree.apply_updates(cst.end_frame_and_get_pending_updates());
8437 spatial_tree.update_tree(&SceneProperties::new());
8438
8439 let map_local_to_picture = SpaceMapper::new_with_target(
8440 root_reference_frame_index,
8441 root_reference_frame_index,
8442 PictureRect::max_rect(),
8443 &spatial_tree,
8444 );
8445
8446 let mut surfaces = vec![
8447 SurfaceInfo {
8448 unclipped_local_rect: PictureRect::max_rect(),
8449 clipped_local_rect: PictureRect::max_rect(),
8450 is_opaque: true,
8451 clipping_rect: PictureRect::max_rect(),
8452 map_local_to_picture: map_local_to_picture.clone(),
8453 raster_spatial_node_index: root_reference_frame_index,
8454 surface_spatial_node_index: root_reference_frame_index,
8455 visibility_spatial_node_index: root_reference_frame_index,
8456 device_pixel_scale: DevicePixelScale::new(1.0),
8457 world_scale_factors: (1.0, 1.0),
8458 local_scale: (1.0, 1.0),
8459 allow_snapping: true,
8460 force_scissor_rect: false,
8461 culling_rect: VisRect::max_rect(),
8462 },
8463 SurfaceInfo {
8464 unclipped_local_rect: PictureRect::new(
8465 PicturePoint::new(0.0, 0.0),
8466 PicturePoint::new(750.0, 450.0),
8467 ),
8468 clipped_local_rect: PictureRect::new(
8469 PicturePoint::new(0.0, 0.0),
8470 PicturePoint::new(750.0, 450.0),
8471 ),
8472 is_opaque: true,
8473 clipping_rect: PictureRect::max_rect(),
8474 map_local_to_picture,
8475 raster_spatial_node_index: root_reference_frame_index,
8476 surface_spatial_node_index: root_reference_frame_index,
8477 visibility_spatial_node_index: root_reference_frame_index,
8478 device_pixel_scale: DevicePixelScale::new(1.0),
8479 world_scale_factors: (1.0, 1.0),
8480 local_scale: (1.0, 1.0),
8481 allow_snapping: true,
8482 force_scissor_rect: false,
8483 culling_rect: VisRect::max_rect(),
8484 },
8485 ];
8486
8487 let shadows = smallvec![
8488 Shadow {
8489 offset: LayoutVector2D::zero(),
8490 color: ColorF::BLACK,
8491 blur_radius: 75.0,
8492 },
8493 ];
8494
8495 let composite_mode = PictureCompositeMode::Filter(Filter::DropShadows(shadows));
8496
8497 let info = get_surface_rects(
8499 SurfaceIndex(1),
8500 &composite_mode,
8501 SurfaceIndex(0),
8502 &mut surfaces,
8503 &spatial_tree,
8504 MAX_SURFACE_SIZE as f32,
8505 false,
8506 ).expect("No surface rect");
8507 assert_eq!(info.task_size, DeviceIntSize::new(1200, 900));
8508
8509 surfaces[0].clipping_rect = PictureRect::new(
8511 PicturePoint::new(768.0, 128.0),
8512 PicturePoint::new(1024.0, 256.0),
8513 );
8514 let info = get_surface_rects(
8515 SurfaceIndex(1),
8516 &composite_mode,
8517 SurfaceIndex(0),
8518 &mut surfaces,
8519 &spatial_tree,
8520 MAX_SURFACE_SIZE as f32,
8521 false,
8522 ).expect("No surface rect");
8523 assert_eq!(info.task_size, DeviceIntSize::new(432, 578));
8524}
8525
8526fn request_render_task(
8527 frame_state: &mut FrameBuildingState,
8528 snapshot: &Option<SnapshotInfo>,
8529 surface_rects: &SurfaceAllocInfo,
8530 is_opaque: bool,
8531 f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF, &mut GpuCache) -> RenderTaskId,
8532) -> RenderTaskId {
8533
8534 let task_id = match snapshot {
8535 Some(info) => {
8536 let adjustment = AdjustedImageSource::from_rects(
8537 &info.area,
8538 &surface_rects.clipped_local.cast_unit()
8539 );
8540 let task_id = frame_state.resource_cache.render_as_image(
8541 info.key.as_image(),
8542 surface_rects.task_size,
8543 frame_state.rg_builder,
8544 &mut frame_state.frame_gpu_data.f32,
8545 frame_state.gpu_cache,
8546 is_opaque,
8547 &adjustment,
8548 f
8549 );
8550
8551 frame_state.surface_builder.add_child_render_task(
8556 task_id,
8557 frame_state.rg_builder,
8558 );
8559
8560 frame_state.image_dependencies.insert(info.key.as_image(), task_id);
8561
8562 task_id
8563 }
8564 None => {
8565 f(
8566 frame_state.rg_builder,
8567 &mut frame_state.frame_gpu_data.f32,
8568 frame_state.gpu_cache
8569 )
8570 }
8571 };
8572
8573 task_id
8574}