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, add_text_marker, 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, BlurEdgeMode};
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))]
600#[derive(Hash)]
601pub struct TileId(pub usize);
602
603#[cfg_attr(feature = "capture", derive(Serialize))]
605#[cfg_attr(feature = "replay", derive(Deserialize))]
606#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)]
607pub struct TileKey {
608 pub tile_offset: TileOffset,
610 pub sub_slice_index: SubSliceIndex,
612}
613
614#[derive(Debug)]
617pub enum SurfaceTextureDescriptor {
618 TextureCache {
621 handle: Option<PictureCacheTextureHandle>,
622 },
623 Native {
626 id: Option<NativeTileId>,
628 },
629}
630
631#[derive(Clone, Debug, Eq, PartialEq, Hash)]
635#[cfg_attr(feature = "capture", derive(Serialize))]
636#[cfg_attr(feature = "replay", derive(Deserialize))]
637pub enum ResolvedSurfaceTexture {
638 TextureCache {
639 texture: TextureSource,
641 },
642 Native {
643 id: NativeTileId,
645 size: DeviceIntSize,
647 }
648}
649
650impl SurfaceTextureDescriptor {
651 pub fn resolve(
653 &self,
654 resource_cache: &ResourceCache,
655 size: DeviceIntSize,
656 ) -> ResolvedSurfaceTexture {
657 match self {
658 SurfaceTextureDescriptor::TextureCache { handle } => {
659 let texture = resource_cache
660 .picture_textures
661 .get_texture_source(handle.as_ref().unwrap());
662
663 ResolvedSurfaceTexture::TextureCache { texture }
664 }
665 SurfaceTextureDescriptor::Native { id } => {
666 ResolvedSurfaceTexture::Native {
667 id: id.expect("bug: native surface not allocated"),
668 size,
669 }
670 }
671 }
672 }
673}
674
675#[derive(Debug)]
677pub enum TileSurface {
678 Texture {
679 descriptor: SurfaceTextureDescriptor,
681 },
682 Color {
683 color: ColorF,
684 },
685 Clear,
686}
687
688impl TileSurface {
689 fn kind(&self) -> &'static str {
690 match *self {
691 TileSurface::Color { .. } => "Color",
692 TileSurface::Texture { .. } => "Texture",
693 TileSurface::Clear => "Clear",
694 }
695 }
696}
697
698#[derive(Debug, Copy, Clone, PartialEq)]
701#[cfg_attr(feature = "capture", derive(Serialize))]
702#[cfg_attr(feature = "replay", derive(Deserialize))]
703pub enum CompareHelperResult<T> {
704 Equal,
706 Count {
708 prev_count: u8,
709 curr_count: u8,
710 },
711 Sentinel,
713 NotEqual {
715 prev: T,
716 curr: T,
717 },
718 PredicateTrue {
720 curr: T
721 },
722}
723
724#[derive(Debug, Copy, Clone, PartialEq)]
728#[cfg_attr(feature = "capture", derive(Serialize))]
729#[cfg_attr(feature = "replay", derive(Deserialize))]
730#[repr(u8)]
731pub enum PrimitiveCompareResult {
732 Equal,
734 Descriptor,
736 Clip,
738 Transform,
740 Image,
742 OpacityBinding,
744 ColorBinding,
746}
747
748#[derive(Debug,Clone)]
750#[cfg_attr(feature = "capture", derive(Serialize))]
751#[cfg_attr(feature = "replay", derive(Deserialize))]
752pub enum InvalidationReason {
753 BackgroundColor,
755 SurfaceOpacityChanged,
757 NoTexture,
759 NoSurface,
761 PrimCount,
763 Content,
765 CompositorKindChanged,
767 ValidRectChanged,
769 ScaleChanged,
771 SurfaceContentChanged,
773}
774
775pub struct Tile {
777 pub tile_offset: TileOffset,
779 pub world_tile_rect: WorldRect,
781 pub local_tile_rect: PictureRect,
783 pub local_dirty_rect: PictureRect,
785 pub device_dirty_rect: DeviceRect,
789 pub world_valid_rect: WorldRect,
791 pub device_valid_rect: DeviceRect,
793 pub current_descriptor: TileDescriptor,
796 pub prev_descriptor: TileDescriptor,
798 pub surface: Option<TileSurface>,
800 pub is_valid: bool,
804 pub is_visible: bool,
807 pub id: TileId,
810 pub is_opaque: bool,
813 root: TileNode,
815 background_color: Option<ColorF>,
817 invalidation_reason: Option<InvalidationReason>,
819 pub local_valid_rect: PictureBox2D,
821 pub z_id: ZBufferId,
823 pub sub_graphs: Vec<(PictureRect, Vec<(PictureCompositeMode, SurfaceIndex)>)>,
824}
825
826impl Tile {
827 fn new(tile_offset: TileOffset) -> Self {
829 let id = TileId(NEXT_TILE_ID.fetch_add(1, Ordering::Relaxed));
830
831 Tile {
832 tile_offset,
833 local_tile_rect: PictureRect::zero(),
834 world_tile_rect: WorldRect::zero(),
835 world_valid_rect: WorldRect::zero(),
836 device_valid_rect: DeviceRect::zero(),
837 local_dirty_rect: PictureRect::zero(),
838 device_dirty_rect: DeviceRect::zero(),
839 surface: None,
840 current_descriptor: TileDescriptor::new(),
841 prev_descriptor: TileDescriptor::new(),
842 is_valid: false,
843 is_visible: false,
844 id,
845 is_opaque: false,
846 root: TileNode::new_leaf(Vec::new()),
847 background_color: None,
848 invalidation_reason: None,
849 local_valid_rect: PictureBox2D::zero(),
850 z_id: ZBufferId::invalid(),
851 sub_graphs: Vec::new(),
852 }
853 }
854
855 fn print(&self, pt: &mut dyn PrintTreePrinter) {
857 pt.new_level(format!("Tile {:?}", self.id));
858 pt.add_item(format!("local_tile_rect: {:?}", self.local_tile_rect));
859 pt.add_item(format!("background_color: {:?}", self.background_color));
860 pt.add_item(format!("invalidation_reason: {:?}", self.invalidation_reason));
861 self.current_descriptor.print(pt);
862 pt.end_level();
863 }
864
865 fn update_dirty_rects(
867 &mut self,
868 ctx: &TileUpdateDirtyContext,
869 state: &mut TileUpdateDirtyState,
870 invalidation_reason: &mut Option<InvalidationReason>,
871 frame_context: &FrameVisibilityContext,
872 ) -> PictureRect {
873 let mut prim_comparer = PrimitiveComparer::new(
874 &self.prev_descriptor,
875 &self.current_descriptor,
876 state.resource_cache,
877 state.spatial_node_comparer,
878 ctx.opacity_bindings,
879 ctx.color_bindings,
880 );
881
882 let mut dirty_rect = PictureBox2D::zero();
883 self.root.update_dirty_rects(
884 &self.prev_descriptor.prims,
885 &self.current_descriptor.prims,
886 &mut prim_comparer,
887 &mut dirty_rect,
888 state.compare_cache,
889 invalidation_reason,
890 frame_context,
891 );
892
893 dirty_rect
894 }
895
896 fn update_content_validity(
901 &mut self,
902 ctx: &TileUpdateDirtyContext,
903 state: &mut TileUpdateDirtyState,
904 frame_context: &FrameVisibilityContext,
905 ) {
906 state.compare_cache.clear();
909 let mut invalidation_reason = None;
910 let dirty_rect = self.update_dirty_rects(
911 ctx,
912 state,
913 &mut invalidation_reason,
914 frame_context,
915 );
916 if !dirty_rect.is_empty() {
917 self.invalidate(
918 Some(dirty_rect),
919 invalidation_reason.expect("bug: no invalidation_reason"),
920 );
921 }
922 if ctx.invalidate_all {
923 self.invalidate(None, InvalidationReason::ScaleChanged);
924 }
925 if self.current_descriptor.local_valid_rect != self.prev_descriptor.local_valid_rect {
928 self.invalidate(None, InvalidationReason::ValidRectChanged);
929 state.composite_state.dirty_rects_are_valid = false;
930 }
931 }
932
933 fn invalidate(
936 &mut self,
937 invalidation_rect: Option<PictureRect>,
938 reason: InvalidationReason,
939 ) {
940 self.is_valid = false;
941
942 match invalidation_rect {
943 Some(rect) => {
944 self.local_dirty_rect = self.local_dirty_rect.union(&rect);
945 }
946 None => {
947 self.local_dirty_rect = self.local_tile_rect;
948 }
949 }
950
951 if self.invalidation_reason.is_none() {
952 self.invalidation_reason = Some(reason);
953 }
954 }
955
956 fn pre_update(
959 &mut self,
960 ctx: &TilePreUpdateContext,
961 ) {
962 self.local_tile_rect = PictureRect::new(
963 PicturePoint::new(
964 self.tile_offset.x as f32 * ctx.tile_size.width,
965 self.tile_offset.y as f32 * ctx.tile_size.height,
966 ),
967 PicturePoint::new(
968 (self.tile_offset.x + 1) as f32 * ctx.tile_size.width,
969 (self.tile_offset.y + 1) as f32 * ctx.tile_size.height,
970 ),
971 );
972 self.local_valid_rect = PictureBox2D::new(
976 PicturePoint::new( 1.0e32, 1.0e32),
977 PicturePoint::new(-1.0e32, -1.0e32),
978 );
979 self.invalidation_reason = None;
980 self.sub_graphs.clear();
981
982 self.world_tile_rect = ctx.pic_to_world_mapper
983 .map(&self.local_tile_rect)
984 .expect("bug: map local tile rect");
985
986 self.is_visible = self.world_tile_rect.intersects(&ctx.global_screen_world_rect);
988
989 if !self.is_visible {
993 return;
994 }
995
996 if ctx.background_color != self.background_color {
997 self.invalidate(None, InvalidationReason::BackgroundColor);
998 self.background_color = ctx.background_color;
999 }
1000
1001 mem::swap(
1004 &mut self.current_descriptor,
1005 &mut self.prev_descriptor,
1006 );
1007 self.current_descriptor.clear();
1008 self.root.clear(self.local_tile_rect);
1009
1010 self.current_descriptor.last_updated_frame_id = ctx.frame_id;
1013 }
1014
1015 fn add_prim_dependency(
1017 &mut self,
1018 info: &PrimitiveDependencyInfo,
1019 ) {
1020 if !self.is_visible {
1023 return;
1024 }
1025
1026 self.local_valid_rect = self.local_valid_rect.union(&info.prim_clip_box);
1030
1031 let tile_p0 = self.local_tile_rect.min;
1045 let tile_p1 = self.local_tile_rect.max;
1046
1047 let prim_clip_box = PictureBox2D::new(
1048 PicturePoint::new(
1049 clampf(info.prim_clip_box.min.x, tile_p0.x, tile_p1.x),
1050 clampf(info.prim_clip_box.min.y, tile_p0.y, tile_p1.y),
1051 ),
1052 PicturePoint::new(
1053 clampf(info.prim_clip_box.max.x, tile_p0.x, tile_p1.x),
1054 clampf(info.prim_clip_box.max.y, tile_p0.y, tile_p1.y),
1055 ),
1056 );
1057
1058 let prim_index = PrimitiveDependencyIndex(self.current_descriptor.prims.len() as u32);
1060
1061 let dep_offset = self.current_descriptor.dep_data.len() as u32;
1063 let mut dep_count = 0;
1064
1065 for clip in &info.clips {
1066 dep_count += 1;
1067 poke_into_vec(
1068 &PrimitiveDependency::Clip {
1069 clip: *clip,
1070 },
1071 &mut self.current_descriptor.dep_data,
1072 );
1073 }
1074
1075 for spatial_node_index in &info.spatial_nodes {
1076 dep_count += 1;
1077 poke_into_vec(
1078 &PrimitiveDependency::SpatialNode {
1079 index: *spatial_node_index,
1080 },
1081 &mut self.current_descriptor.dep_data,
1082 );
1083 }
1084
1085 for image in &info.images {
1086 dep_count += 1;
1087 poke_into_vec(
1088 &PrimitiveDependency::Image {
1089 image: *image,
1090 },
1091 &mut self.current_descriptor.dep_data,
1092 );
1093 }
1094
1095 for binding in &info.opacity_bindings {
1096 dep_count += 1;
1097 poke_into_vec(
1098 &PrimitiveDependency::OpacityBinding {
1099 binding: *binding,
1100 },
1101 &mut self.current_descriptor.dep_data,
1102 );
1103 }
1104
1105 if let Some(ref binding) = info.color_binding {
1106 dep_count += 1;
1107 poke_into_vec(
1108 &PrimitiveDependency::ColorBinding {
1109 binding: *binding,
1110 },
1111 &mut self.current_descriptor.dep_data,
1112 );
1113 }
1114
1115 self.current_descriptor.prims.push(PrimitiveDescriptor {
1116 prim_uid: info.prim_uid,
1117 prim_clip_box,
1118 dep_offset,
1119 dep_count,
1120 });
1121
1122 self.root.add_prim(prim_index, &info.prim_clip_box);
1124 }
1125
1126 fn update_dirty_and_valid_rects(
1129 &mut self,
1130 ctx: &TileUpdateDirtyContext,
1131 state: &mut TileUpdateDirtyState,
1132 frame_context: &FrameVisibilityContext,
1133 ) {
1134 ensure_red_zone::<PrimitiveDependency>(&mut self.current_descriptor.dep_data);
1136
1137 state.spatial_node_comparer.retain_for_frame(self.current_descriptor.last_updated_frame_id);
1142
1143 if !self.is_visible {
1147 return;
1148 }
1149
1150 self.current_descriptor.local_valid_rect = self.local_valid_rect;
1152
1153 self.current_descriptor.local_valid_rect = self.local_tile_rect
1164 .intersection(&ctx.local_rect)
1165 .and_then(|r| r.intersection(&self.current_descriptor.local_valid_rect))
1166 .unwrap_or_else(PictureRect::zero);
1167
1168 self.world_valid_rect = ctx.pic_to_world_mapper
1171 .map(&self.current_descriptor.local_valid_rect)
1172 .expect("bug: map local valid rect");
1173
1174 let device_rect = (self.world_tile_rect * ctx.global_device_pixel_scale).round();
1179 self.device_valid_rect = (self.world_valid_rect * ctx.global_device_pixel_scale)
1180 .round_out()
1181 .intersection(&device_rect)
1182 .unwrap_or_else(DeviceRect::zero);
1183
1184 self.update_content_validity(ctx, state, frame_context);
1186 }
1187
1188 fn post_update(
1191 &mut self,
1192 ctx: &TilePostUpdateContext,
1193 state: &mut TilePostUpdateState,
1194 frame_context: &FrameVisibilityContext,
1195 ) {
1196 if !self.is_visible {
1200 return;
1201 }
1202
1203 if self.current_descriptor.prims.is_empty() || self.device_valid_rect.is_empty() {
1207 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { mut id, .. }, .. }) = self.surface.take() {
1212 if let Some(id) = id.take() {
1213 state.resource_cache.destroy_compositor_tile(id);
1214 }
1215 }
1216
1217 self.is_visible = false;
1218 return;
1219 }
1220
1221 let clipped_rect = self.current_descriptor.local_valid_rect
1225 .intersection(&ctx.local_clip_rect)
1226 .unwrap_or_else(PictureRect::zero);
1227
1228 let has_opaque_bg_color = self.background_color.map_or(false, |c| c.a >= 1.0);
1229 let has_opaque_backdrop = ctx.backdrop.map_or(false, |b| b.opaque_rect.contains_box(&clipped_rect));
1230 let mut is_opaque = has_opaque_bg_color || has_opaque_backdrop;
1231
1232 for underlay in ctx.underlays {
1235 if clipped_rect.intersects(&underlay.local_rect) {
1236 is_opaque = false;
1237 break;
1238 }
1239 }
1240
1241 self.z_id = ctx.z_id;
1243
1244 if is_opaque != self.is_opaque {
1245 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = self.surface {
1253 if let Some(id) = id.take() {
1254 state.resource_cache.destroy_compositor_tile(id);
1255 }
1256 }
1257
1258 self.invalidate(None, InvalidationReason::SurfaceOpacityChanged);
1260 self.is_opaque = is_opaque;
1261 }
1262
1263 let (supports_dirty_rects, supports_simple_prims) = match state.composite_state.compositor_kind {
1268 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
1269 (frame_context.config.gpu_supports_render_target_partial_update, true)
1270 }
1271 CompositorKind::Native { capabilities, .. } => {
1272 (capabilities.max_update_rects > 0, false)
1273 }
1274 };
1275
1276 if supports_dirty_rects {
1279 if ctx.current_tile_size == state.resource_cache.picture_textures.default_tile_size() {
1281 let max_split_level = 3;
1282
1283 self.root.maybe_merge_or_split(
1285 0,
1286 &self.current_descriptor.prims,
1287 max_split_level,
1288 );
1289 }
1290 }
1291
1292 if !self.is_valid && !supports_dirty_rects {
1296 self.local_dirty_rect = self.local_tile_rect;
1297 }
1298
1299 let is_simple_prim =
1305 ctx.backdrop.map_or(false, |b| b.kind.is_some()) &&
1306 self.current_descriptor.prims.len() == 1 &&
1307 self.is_opaque &&
1308 supports_simple_prims;
1309
1310 let surface = if is_simple_prim {
1312 match ctx.backdrop.unwrap().kind {
1316 Some(BackdropKind::Color { color }) => {
1317 TileSurface::Color {
1318 color,
1319 }
1320 }
1321 Some(BackdropKind::Clear) => {
1322 TileSurface::Clear
1323 }
1324 None => {
1325 unreachable!();
1327 }
1328 }
1329 } else {
1330 match self.surface.take() {
1335 Some(TileSurface::Texture { descriptor }) => {
1336 TileSurface::Texture {
1338 descriptor,
1339 }
1340 }
1341 Some(TileSurface::Color { .. }) | Some(TileSurface::Clear) | None => {
1342 let descriptor = match state.composite_state.compositor_kind {
1347 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
1348 SurfaceTextureDescriptor::TextureCache {
1351 handle: None,
1352 }
1353 }
1354 CompositorKind::Native { .. } => {
1355 SurfaceTextureDescriptor::Native {
1359 id: None,
1360 }
1361 }
1362 };
1363
1364 TileSurface::Texture {
1365 descriptor,
1366 }
1367 }
1368 }
1369 };
1370
1371 self.surface = Some(surface);
1373 }
1374}
1375
1376#[derive(Debug, Clone)]
1378#[cfg_attr(feature = "capture", derive(Serialize))]
1379#[cfg_attr(feature = "replay", derive(Deserialize))]
1380pub struct PrimitiveDescriptor {
1381 pub prim_uid: ItemUid,
1382 pub prim_clip_box: PictureBox2D,
1383 pub dep_offset: u32,
1385 pub dep_count: u32,
1386}
1387
1388impl PartialEq for PrimitiveDescriptor {
1389 fn eq(&self, other: &Self) -> bool {
1390 const EPSILON: f32 = 0.001;
1391
1392 if self.prim_uid != other.prim_uid {
1393 return false;
1394 }
1395
1396 if !self.prim_clip_box.min.x.approx_eq_eps(&other.prim_clip_box.min.x, &EPSILON) {
1397 return false;
1398 }
1399 if !self.prim_clip_box.min.y.approx_eq_eps(&other.prim_clip_box.min.y, &EPSILON) {
1400 return false;
1401 }
1402 if !self.prim_clip_box.max.x.approx_eq_eps(&other.prim_clip_box.max.x, &EPSILON) {
1403 return false;
1404 }
1405 if !self.prim_clip_box.max.y.approx_eq_eps(&other.prim_clip_box.max.y, &EPSILON) {
1406 return false;
1407 }
1408
1409 if self.dep_count != other.dep_count {
1410 return false;
1411 }
1412
1413 true
1414 }
1415}
1416
1417#[cfg_attr(any(feature="capture",feature="replay"), derive(Clone))]
1420#[cfg_attr(feature = "capture", derive(Serialize))]
1421#[cfg_attr(feature = "replay", derive(Deserialize))]
1422pub struct TileDescriptor {
1423 prims: Vec<PrimitiveDescriptor>,
1427
1428 pub local_valid_rect: PictureRect,
1430
1431 last_updated_frame_id: FrameId,
1434
1435 dep_data: Vec<u8>,
1437}
1438
1439impl TileDescriptor {
1440 fn new() -> Self {
1441 TileDescriptor {
1442 local_valid_rect: PictureRect::zero(),
1443 dep_data: Vec::new(),
1444 prims: Vec::new(),
1445 last_updated_frame_id: FrameId::INVALID,
1446 }
1447 }
1448
1449 fn print(&self, pt: &mut dyn PrintTreePrinter) {
1451 pt.new_level("current_descriptor".to_string());
1452
1453 pt.new_level("prims".to_string());
1454 for prim in &self.prims {
1455 pt.new_level(format!("prim uid={}", prim.prim_uid.get_uid()));
1456 pt.add_item(format!("clip: p0={},{} p1={},{}",
1457 prim.prim_clip_box.min.x,
1458 prim.prim_clip_box.min.y,
1459 prim.prim_clip_box.max.x,
1460 prim.prim_clip_box.max.y,
1461 ));
1462 pt.end_level();
1463 }
1464 pt.end_level();
1465
1466 pt.end_level();
1467 }
1468
1469 fn clear(&mut self) {
1472 self.local_valid_rect = PictureRect::zero();
1473 self.prims.clear();
1474 self.dep_data.clear();
1475 }
1476}
1477
1478#[derive(Clone)]
1485pub struct DirtyRegion {
1486 pub combined: VisRect,
1488
1489 pub visibility_spatial_node: SpatialNodeIndex,
1492 local_spatial_node: SpatialNodeIndex,
1494}
1495
1496impl DirtyRegion {
1497 pub fn new(
1499 visibility_spatial_node: SpatialNodeIndex,
1500 local_spatial_node: SpatialNodeIndex,
1501 ) -> Self {
1502 DirtyRegion {
1503 combined: VisRect::zero(),
1504 visibility_spatial_node,
1505 local_spatial_node,
1506 }
1507 }
1508
1509 pub fn reset(
1511 &mut self,
1512 visibility_spatial_node: SpatialNodeIndex,
1513 local_spatial_node: SpatialNodeIndex,
1514 ) {
1515 self.combined = VisRect::zero();
1516 self.visibility_spatial_node = visibility_spatial_node;
1517 self.local_spatial_node = local_spatial_node;
1518 }
1519
1520 pub fn add_dirty_region(
1523 &mut self,
1524 rect_in_pic_space: PictureRect,
1525 spatial_tree: &SpatialTree,
1526 ) {
1527 let map_pic_to_raster = SpaceMapper::new_with_target(
1528 self.visibility_spatial_node,
1529 self.local_spatial_node,
1530 VisRect::max_rect(),
1531 spatial_tree,
1532 );
1533
1534 let raster_rect = map_pic_to_raster
1535 .map(&rect_in_pic_space)
1536 .expect("bug");
1537
1538 self.combined = self.combined.union(&raster_rect);
1540 }
1541}
1542
1543#[derive(Debug, Copy, Clone)]
1547pub enum BackdropKind {
1548 Color {
1549 color: ColorF,
1550 },
1551 Clear,
1552}
1553
1554#[derive(Debug, Copy, Clone)]
1556pub struct BackdropInfo {
1557 pub opaque_rect: PictureRect,
1561 pub spanning_opaque_color: Option<ColorF>,
1564 pub kind: Option<BackdropKind>,
1566 pub backdrop_rect: PictureRect,
1568}
1569
1570impl BackdropInfo {
1571 fn empty() -> Self {
1572 BackdropInfo {
1573 opaque_rect: PictureRect::zero(),
1574 spanning_opaque_color: None,
1575 kind: None,
1576 backdrop_rect: PictureRect::zero(),
1577 }
1578 }
1579}
1580
1581pub struct NativeSurface {
1593 pub opaque: NativeSurfaceId,
1595 pub alpha: NativeSurfaceId,
1597}
1598
1599#[derive(PartialEq, Eq, Hash)]
1601pub struct ExternalNativeSurfaceKey {
1602 pub image_keys: [ImageKey; 3],
1604 pub size: Option<DeviceIntSize>,
1608}
1609
1610pub struct ExternalNativeSurface {
1612 pub used_this_frame: bool,
1615 pub native_surface_id: NativeSurfaceId,
1617 pub image_dependencies: [ImageDependency; 3],
1621}
1622
1623#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1626#[cfg_attr(feature = "capture", derive(Serialize))]
1627#[cfg_attr(feature = "replay", derive(Deserialize))]
1628pub struct SliceId(usize);
1629
1630impl SliceId {
1631 pub fn new(index: usize) -> Self {
1632 SliceId(index)
1633 }
1634}
1635
1636pub struct TileCacheParams {
1639 pub debug_flags: DebugFlags,
1641 pub slice: usize,
1643 pub slice_flags: SliceFlags,
1645 pub spatial_node_index: SpatialNodeIndex,
1647 pub visibility_node_index: SpatialNodeIndex,
1649 pub background_color: Option<ColorF>,
1652 pub shared_clip_node_id: ClipNodeId,
1654 pub shared_clip_leaf_id: Option<ClipLeafId>,
1656 pub virtual_surface_size: i32,
1658 pub image_surface_count: usize,
1662 pub yuv_image_surface_count: usize,
1666}
1667
1668#[cfg_attr(feature = "capture", derive(Serialize))]
1671#[cfg_attr(feature = "replay", derive(Deserialize))]
1672#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1673pub struct SubSliceIndex(u8);
1674
1675impl SubSliceIndex {
1676 pub const DEFAULT: SubSliceIndex = SubSliceIndex(0);
1677
1678 pub fn new(index: usize) -> Self {
1679 SubSliceIndex(index as u8)
1680 }
1681
1682 pub fn is_primary(&self) -> bool {
1685 self.0 == 0
1686 }
1687
1688 pub fn as_usize(&self) -> usize {
1690 self.0 as usize
1691 }
1692}
1693
1694pub struct CompositorSurface {
1697 pub descriptor: ExternalSurfaceDescriptor,
1699 prohibited_rect: PictureRect,
1702 pub is_opaque: bool,
1704}
1705
1706pub struct SubSlice {
1711 pub tiles: FastHashMap<TileOffset, Box<Tile>>,
1713 pub native_surface: Option<NativeSurface>,
1717 pub compositor_surfaces: Vec<CompositorSurface>,
1720 pub composite_tiles: Vec<CompositeTile>,
1722 pub opaque_tile_descriptors: Vec<CompositeTileDescriptor>,
1724 pub alpha_tile_descriptors: Vec<CompositeTileDescriptor>,
1726}
1727
1728impl SubSlice {
1729 fn new() -> Self {
1731 SubSlice {
1732 tiles: FastHashMap::default(),
1733 native_surface: None,
1734 compositor_surfaces: Vec::new(),
1735 composite_tiles: Vec::new(),
1736 opaque_tile_descriptors: Vec::new(),
1737 alpha_tile_descriptors: Vec::new(),
1738 }
1739 }
1740
1741 fn reset(&mut self) {
1744 self.compositor_surfaces.clear();
1745 self.composite_tiles.clear();
1746 self.opaque_tile_descriptors.clear();
1747 self.alpha_tile_descriptors.clear();
1748 }
1749
1750 fn resize(&mut self, new_tile_rect: TileRect) -> FastHashMap<TileOffset, Box<Tile>> {
1752 let mut old_tiles = mem::replace(&mut self.tiles, FastHashMap::default());
1753 self.tiles.reserve(new_tile_rect.area() as usize);
1754
1755 for y in new_tile_rect.min.y .. new_tile_rect.max.y {
1756 for x in new_tile_rect.min.x .. new_tile_rect.max.x {
1757 let key = TileOffset::new(x, y);
1758 let tile = old_tiles
1759 .remove(&key)
1760 .unwrap_or_else(|| {
1761 Box::new(Tile::new(key))
1762 });
1763 self.tiles.insert(key, tile);
1764 }
1765 }
1766
1767 old_tiles
1768 }
1769}
1770
1771pub struct BackdropSurface {
1772 pub id: NativeSurfaceId,
1773 color: ColorF,
1774 pub device_rect: DeviceRect,
1775}
1776
1777pub struct TileCacheInstance {
1779 pub debug_flags: DebugFlags,
1781 pub slice: usize,
1788 pub slice_flags: SliceFlags,
1790 pub current_tile_size: DeviceIntSize,
1792 pub sub_slices: Vec<SubSlice>,
1794 pub spatial_node_index: SpatialNodeIndex,
1796 pub visibility_node_index: SpatialNodeIndex,
1798 opacity_bindings: FastHashMap<PropertyBindingId, OpacityBindingInfo>,
1801 old_opacity_bindings: FastHashMap<PropertyBindingId, OpacityBindingInfo>,
1803 spatial_node_comparer: SpatialNodeComparer,
1805 color_bindings: FastHashMap<PropertyBindingId, ColorBindingInfo>,
1808 old_color_bindings: FastHashMap<PropertyBindingId, ColorBindingInfo>,
1810 pub dirty_region: DirtyRegion,
1812 tile_size: PictureSize,
1814 tile_rect: TileRect,
1816 tile_bounds_p0: TileOffset,
1819 tile_bounds_p1: TileOffset,
1820 pub local_rect: PictureRect,
1822 pub local_clip_rect: PictureRect,
1824 pub compositor_clip: Option<CompositorClipIndex>,
1826 pub screen_rect_in_pic_space: PictureRect,
1828 surface_index: SurfaceIndex,
1830 pub background_color: Option<ColorF>,
1833 pub backdrop: BackdropInfo,
1835 pub subpixel_mode: SubpixelMode,
1838 pub shared_clip_node_id: ClipNodeId,
1840 pub shared_clip_leaf_id: Option<ClipLeafId>,
1842 frames_until_size_eval: usize,
1847 virtual_offset: DeviceIntPoint,
1854 compare_cache: FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
1857 tile_size_override: Option<DeviceIntSize>,
1860 pub external_native_surface_cache: FastHashMap<ExternalNativeSurfaceKey, ExternalNativeSurface>,
1862 frame_id: FrameId,
1864 pub transform_index: CompositorTransformIndex,
1866 local_to_raster: ScaleOffset,
1868 raster_to_device: ScaleOffset,
1870 invalidate_all_tiles: bool,
1872 current_raster_scale: f32,
1874 current_surface_traversal_depth: usize,
1876 deferred_dirty_tests: Vec<DeferredDirtyTest>,
1879 found_prims_after_backdrop: bool,
1881 pub backdrop_surface: Option<BackdropSurface>,
1882 pub underlays: Vec<ExternalSurfaceDescriptor>,
1884 pub overlay_region: PictureRect,
1886 pub yuv_images_count: usize,
1888 pub yuv_images_remaining: usize,
1891}
1892
1893#[derive(Clone, Copy)]
1894enum SurfacePromotionFailure {
1895 ImageWaitingOnYuvImage,
1896 NotPremultipliedAlpha,
1897 OverlaySurfaceLimit,
1898 OverlayNeedsMask,
1899 UnderlayAlphaBackdrop,
1900 UnderlaySurfaceLimit,
1901 UnderlayIntersectsOverlay,
1902 UnderlayLowQualityZoom,
1903 NotRootTileCache,
1904 ComplexTransform,
1905 SliceAtomic,
1906 SizeTooLarge,
1907}
1908
1909impl Display for SurfacePromotionFailure {
1910 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
1911 write!(
1912 f,
1913 "{}",
1914 match *self {
1915 SurfacePromotionFailure::ImageWaitingOnYuvImage => "Image prim waiting for all YuvImage prims to be considered for promotion",
1916 SurfacePromotionFailure::NotPremultipliedAlpha => "does not use premultiplied alpha",
1917 SurfacePromotionFailure::OverlaySurfaceLimit => "hit the overlay surface limit",
1918 SurfacePromotionFailure::OverlayNeedsMask => "overlay not allowed for prim with mask",
1919 SurfacePromotionFailure::UnderlayAlphaBackdrop => "underlay requires an opaque backdrop",
1920 SurfacePromotionFailure::UnderlaySurfaceLimit => "hit the underlay surface limit",
1921 SurfacePromotionFailure::UnderlayIntersectsOverlay => "underlay intersects already-promoted overlay",
1922 SurfacePromotionFailure::UnderlayLowQualityZoom => "underlay not allowed during low-quality pinch zoom",
1923 SurfacePromotionFailure::NotRootTileCache => "is not on a root tile cache",
1924 SurfacePromotionFailure::ComplexTransform => "has a complex transform",
1925 SurfacePromotionFailure::SliceAtomic => "slice is atomic",
1926 SurfacePromotionFailure::SizeTooLarge => "surface is too large for compositor",
1927 }.to_owned()
1928 )
1929 }
1930}
1931
1932impl TileCacheInstance {
1933 pub fn new(params: TileCacheParams) -> Self {
1934 let sub_slice_count = (params.image_surface_count + params.yuv_image_surface_count).min(MAX_COMPOSITOR_SURFACES) + 1;
1937
1938 let mut sub_slices = Vec::with_capacity(sub_slice_count);
1939 for _ in 0 .. sub_slice_count {
1940 sub_slices.push(SubSlice::new());
1941 }
1942
1943 TileCacheInstance {
1944 debug_flags: params.debug_flags,
1945 slice: params.slice,
1946 slice_flags: params.slice_flags,
1947 spatial_node_index: params.spatial_node_index,
1948 visibility_node_index: params.visibility_node_index,
1949 sub_slices,
1950 opacity_bindings: FastHashMap::default(),
1951 old_opacity_bindings: FastHashMap::default(),
1952 spatial_node_comparer: SpatialNodeComparer::new(),
1953 color_bindings: FastHashMap::default(),
1954 old_color_bindings: FastHashMap::default(),
1955 dirty_region: DirtyRegion::new(params.visibility_node_index, params.spatial_node_index),
1956 tile_size: PictureSize::zero(),
1957 tile_rect: TileRect::zero(),
1958 tile_bounds_p0: TileOffset::zero(),
1959 tile_bounds_p1: TileOffset::zero(),
1960 local_rect: PictureRect::zero(),
1961 local_clip_rect: PictureRect::zero(),
1962 compositor_clip: None,
1963 screen_rect_in_pic_space: PictureRect::zero(),
1964 surface_index: SurfaceIndex(0),
1965 background_color: params.background_color,
1966 backdrop: BackdropInfo::empty(),
1967 subpixel_mode: SubpixelMode::Allow,
1968 shared_clip_node_id: params.shared_clip_node_id,
1969 shared_clip_leaf_id: params.shared_clip_leaf_id,
1970 current_tile_size: DeviceIntSize::zero(),
1971 frames_until_size_eval: 0,
1972 virtual_offset: DeviceIntPoint::new(
1974 params.virtual_surface_size / 2,
1975 params.virtual_surface_size / 2,
1976 ),
1977 compare_cache: FastHashMap::default(),
1978 tile_size_override: None,
1979 external_native_surface_cache: FastHashMap::default(),
1980 frame_id: FrameId::INVALID,
1981 transform_index: CompositorTransformIndex::INVALID,
1982 raster_to_device: ScaleOffset::identity(),
1983 local_to_raster: ScaleOffset::identity(),
1984 invalidate_all_tiles: true,
1985 current_raster_scale: 1.0,
1986 current_surface_traversal_depth: 0,
1987 deferred_dirty_tests: Vec::new(),
1988 found_prims_after_backdrop: false,
1989 backdrop_surface: None,
1990 underlays: Vec::new(),
1991 overlay_region: PictureRect::zero(),
1992 yuv_images_count: params.yuv_image_surface_count,
1993 yuv_images_remaining: 0,
1994 }
1995 }
1996
1997 pub fn tile_count(&self) -> usize {
1999 self.tile_rect.area() as usize * self.sub_slices.len()
2000 }
2001
2002 pub fn memory_pressure(&mut self, resource_cache: &mut ResourceCache) {
2004 for sub_slice in &mut self.sub_slices {
2005 for tile in sub_slice.tiles.values_mut() {
2006 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2007 if let Some(id) = id.take() {
2010 resource_cache.destroy_compositor_tile(id);
2011 }
2012 }
2013 }
2014 if let Some(native_surface) = sub_slice.native_surface.take() {
2015 resource_cache.destroy_compositor_surface(native_surface.opaque);
2016 resource_cache.destroy_compositor_surface(native_surface.alpha);
2017 }
2018 }
2019 }
2020
2021 pub fn prepare_for_new_scene(
2025 &mut self,
2026 params: TileCacheParams,
2027 resource_cache: &mut ResourceCache,
2028 ) {
2029 assert_eq!(self.slice, params.slice);
2031
2032 let required_sub_slice_count = (params.image_surface_count + params.yuv_image_surface_count).min(MAX_COMPOSITOR_SURFACES) + 1;
2035
2036 if self.sub_slices.len() != required_sub_slice_count {
2037 self.tile_rect = TileRect::zero();
2038
2039 if self.sub_slices.len() > required_sub_slice_count {
2040 let old_sub_slices = self.sub_slices.split_off(required_sub_slice_count);
2041
2042 for mut sub_slice in old_sub_slices {
2043 for tile in sub_slice.tiles.values_mut() {
2044 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2045 if let Some(id) = id.take() {
2046 resource_cache.destroy_compositor_tile(id);
2047 }
2048 }
2049 }
2050
2051 if let Some(native_surface) = sub_slice.native_surface {
2052 resource_cache.destroy_compositor_surface(native_surface.opaque);
2053 resource_cache.destroy_compositor_surface(native_surface.alpha);
2054 }
2055 }
2056 } else {
2057 while self.sub_slices.len() < required_sub_slice_count {
2058 self.sub_slices.push(SubSlice::new());
2059 }
2060 }
2061 }
2062
2063 self.slice_flags = params.slice_flags;
2067 self.spatial_node_index = params.spatial_node_index;
2068 self.background_color = params.background_color;
2069 self.shared_clip_leaf_id = params.shared_clip_leaf_id;
2070 self.shared_clip_node_id = params.shared_clip_node_id;
2071
2072 self.frames_until_size_eval = 0;
2075
2076 self.yuv_images_count = params.yuv_image_surface_count;
2078 }
2079
2080 pub fn destroy(
2083 self,
2084 resource_cache: &mut ResourceCache,
2085 ) {
2086 for sub_slice in self.sub_slices {
2087 if let Some(native_surface) = sub_slice.native_surface {
2088 resource_cache.destroy_compositor_surface(native_surface.opaque);
2089 resource_cache.destroy_compositor_surface(native_surface.alpha);
2090 }
2091 }
2092
2093 for (_, external_surface) in self.external_native_surface_cache {
2094 resource_cache.destroy_compositor_surface(external_surface.native_surface_id)
2095 }
2096
2097 if let Some(backdrop_surface) = &self.backdrop_surface {
2098 resource_cache.destroy_compositor_surface(backdrop_surface.id);
2099 }
2100 }
2101
2102 fn get_tile_coords_for_rect(
2104 &self,
2105 rect: &PictureRect,
2106 ) -> (TileOffset, TileOffset) {
2107 let mut p0 = TileOffset::new(
2109 (rect.min.x / self.tile_size.width).floor() as i32,
2110 (rect.min.y / self.tile_size.height).floor() as i32,
2111 );
2112
2113 let mut p1 = TileOffset::new(
2114 (rect.max.x / self.tile_size.width).ceil() as i32,
2115 (rect.max.y / self.tile_size.height).ceil() as i32,
2116 );
2117
2118 p0.x = clamp(p0.x, self.tile_bounds_p0.x, self.tile_bounds_p1.x);
2120 p0.y = clamp(p0.y, self.tile_bounds_p0.y, self.tile_bounds_p1.y);
2121 p1.x = clamp(p1.x, self.tile_bounds_p0.x, self.tile_bounds_p1.x);
2122 p1.y = clamp(p1.y, self.tile_bounds_p0.y, self.tile_bounds_p1.y);
2123
2124 (p0, p1)
2125 }
2126
2127 pub fn pre_update(
2129 &mut self,
2130 surface_index: SurfaceIndex,
2131 frame_context: &FrameVisibilityContext,
2132 frame_state: &mut FrameVisibilityState,
2133 ) -> WorldRect {
2134 let surface = &frame_state.surfaces[surface_index.0];
2135 let pic_rect = surface.unclipped_local_rect;
2136
2137 self.surface_index = surface_index;
2138 self.local_rect = pic_rect;
2139 self.local_clip_rect = PictureRect::max_rect();
2140 self.deferred_dirty_tests.clear();
2141 self.underlays.clear();
2142 self.overlay_region = PictureRect::zero();
2143 self.yuv_images_remaining = self.yuv_images_count;
2144
2145 for sub_slice in &mut self.sub_slices {
2146 sub_slice.reset();
2147 }
2148
2149 self.backdrop = BackdropInfo::empty();
2152
2153 let pic_to_world_mapper = SpaceMapper::new_with_target(
2156 frame_context.root_spatial_node_index,
2157 self.spatial_node_index,
2158 frame_context.global_screen_world_rect,
2159 frame_context.spatial_tree,
2160 );
2161 self.screen_rect_in_pic_space = pic_to_world_mapper
2162 .unmap(&frame_context.global_screen_world_rect)
2163 .expect("unable to unmap screen rect");
2164
2165 let pic_to_vis_mapper = SpaceMapper::new_with_target(
2166 frame_context.root_spatial_node_index,
2168 self.spatial_node_index,
2169 surface.culling_rect,
2170 frame_context.spatial_tree,
2171 );
2172
2173 if let Some(shared_clip_leaf_id) = self.shared_clip_leaf_id {
2177 let map_local_to_picture = SpaceMapper::new(
2178 self.spatial_node_index,
2179 pic_rect,
2180 );
2181
2182 frame_state.clip_store.set_active_clips(
2183 self.spatial_node_index,
2184 map_local_to_picture.ref_spatial_node_index,
2185 surface.visibility_spatial_node_index,
2186 shared_clip_leaf_id,
2187 frame_context.spatial_tree,
2188 &mut frame_state.data_stores.clip,
2189 &frame_state.clip_tree,
2190 );
2191
2192 let clip_chain_instance = frame_state.clip_store.build_clip_chain_instance(
2193 pic_rect.cast_unit(),
2194 &map_local_to_picture,
2195 &pic_to_vis_mapper,
2196 frame_context.spatial_tree,
2197 frame_state.gpu_cache,
2198 frame_state.resource_cache,
2199 frame_context.global_device_pixel_scale,
2200 &surface.culling_rect,
2201 &mut frame_state.data_stores.clip,
2202 frame_state.rg_builder,
2203 true,
2204 );
2205
2206 self.local_clip_rect = PictureRect::zero();
2210 self.compositor_clip = None;
2211
2212 if let Some(clip_chain) = clip_chain_instance {
2213 self.local_clip_rect = clip_chain.pic_coverage_rect;
2214 self.compositor_clip = None;
2215
2216 if clip_chain.needs_mask {
2217 for i in 0 .. clip_chain.clips_range.count {
2218 let clip_instance = frame_state
2219 .clip_store
2220 .get_instance_from_range(&clip_chain.clips_range, i);
2221 let clip_node = &frame_state.data_stores.clip[clip_instance.handle];
2222
2223 match clip_node.item.kind {
2224 ClipItemKind::RoundedRectangle { rect, radius, mode } => {
2225 assert_eq!(mode, ClipMode::Clip);
2226
2227 let map = ClipSpaceConversion::new(
2232 frame_context.root_spatial_node_index,
2233 clip_node.item.spatial_node_index,
2234 frame_context.root_spatial_node_index,
2235 frame_context.spatial_tree,
2236 );
2237
2238 let (rect, radius) = match map {
2239 ClipSpaceConversion::Local => {
2240 (rect.cast_unit(), radius)
2241 }
2242 ClipSpaceConversion::ScaleOffset(scale_offset) => {
2243 (
2244 scale_offset.map_rect(&rect),
2245 BorderRadius {
2246 top_left: scale_offset.map_size(&radius.top_left),
2247 top_right: scale_offset.map_size(&radius.top_right),
2248 bottom_left: scale_offset.map_size(&radius.bottom_left),
2249 bottom_right: scale_offset.map_size(&radius.bottom_right),
2250 },
2251 )
2252 }
2253 ClipSpaceConversion::Transform(..) => {
2254 unreachable!();
2255 }
2256 };
2257
2258 self.compositor_clip = Some(frame_state.composite_state.register_clip(
2259 rect,
2260 radius,
2261 ));
2262
2263 break;
2264 }
2265 _ => {
2266 }
2271 }
2272 }
2273 }
2274 }
2275 }
2276
2277 self.frame_id.advance();
2280
2281 self.spatial_node_comparer.next_frame(self.spatial_node_index);
2284
2285 for external_native_surface in self.external_native_surface_cache.values_mut() {
2291 external_native_surface.used_this_frame = false;
2292 }
2293
2294 if self.frames_until_size_eval == 0 ||
2298 self.tile_size_override != frame_context.config.tile_size_override {
2299
2300 let desired_tile_size = match frame_context.config.tile_size_override {
2302 Some(tile_size_override) => {
2303 tile_size_override
2304 }
2305 None => {
2306 if self.slice_flags.contains(SliceFlags::IS_SCROLLBAR) {
2307 if pic_rect.width() <= pic_rect.height() {
2308 TILE_SIZE_SCROLLBAR_VERTICAL
2309 } else {
2310 TILE_SIZE_SCROLLBAR_HORIZONTAL
2311 }
2312 } else {
2313 frame_state.resource_cache.picture_textures.default_tile_size()
2314 }
2315 }
2316 };
2317
2318 if desired_tile_size != self.current_tile_size {
2321 for sub_slice in &mut self.sub_slices {
2322 if let Some(native_surface) = sub_slice.native_surface.take() {
2325 frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
2326 frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
2327 }
2328 sub_slice.tiles.clear();
2329 }
2330 self.tile_rect = TileRect::zero();
2331 self.current_tile_size = desired_tile_size;
2332 }
2333
2334 self.frames_until_size_eval = 120;
2337 self.tile_size_override = frame_context.config.tile_size_override;
2338 }
2339
2340 let local_to_device = get_relative_scale_offset(
2342 self.spatial_node_index,
2343 frame_context.root_spatial_node_index,
2344 frame_context.spatial_tree,
2345 );
2346
2347 let mut raster_to_device = local_to_device;
2349
2350 if frame_context.config.low_quality_pinch_zoom {
2351 raster_to_device.scale.x /= self.current_raster_scale;
2352 raster_to_device.scale.y /= self.current_raster_scale;
2353 } else {
2354 raster_to_device.scale.x = 1.0;
2355 raster_to_device.scale.y = 1.0;
2356 }
2357
2358 let local_to_raster = local_to_device.then(&raster_to_device.inverse());
2360
2361 const EPSILON: f32 = 0.001;
2362 let compositor_translation_changed =
2363 !raster_to_device.offset.x.approx_eq_eps(&self.raster_to_device.offset.x, &EPSILON) ||
2364 !raster_to_device.offset.y.approx_eq_eps(&self.raster_to_device.offset.y, &EPSILON);
2365 let compositor_scale_changed =
2366 !raster_to_device.scale.x.approx_eq_eps(&self.raster_to_device.scale.x, &EPSILON) ||
2367 !raster_to_device.scale.y.approx_eq_eps(&self.raster_to_device.scale.y, &EPSILON);
2368 let surface_scale_changed =
2369 !local_to_raster.scale.x.approx_eq_eps(&self.local_to_raster.scale.x, &EPSILON) ||
2370 !local_to_raster.scale.y.approx_eq_eps(&self.local_to_raster.scale.y, &EPSILON);
2371
2372 if compositor_translation_changed ||
2373 compositor_scale_changed ||
2374 surface_scale_changed ||
2375 frame_context.config.force_invalidation {
2376 frame_state.composite_state.dirty_rects_are_valid = false;
2377 }
2378
2379 self.raster_to_device = raster_to_device;
2380 self.local_to_raster = local_to_raster;
2381 self.invalidate_all_tiles = surface_scale_changed || frame_context.config.force_invalidation;
2382
2383 let current_properties = frame_context.scene_properties.float_properties();
2386 mem::swap(&mut self.opacity_bindings, &mut self.old_opacity_bindings);
2387
2388 self.opacity_bindings.clear();
2389 for (id, value) in current_properties {
2390 let changed = match self.old_opacity_bindings.get(id) {
2391 Some(old_property) => !old_property.value.approx_eq(value),
2392 None => true,
2393 };
2394 self.opacity_bindings.insert(*id, OpacityBindingInfo {
2395 value: *value,
2396 changed,
2397 });
2398 }
2399
2400 let current_properties = frame_context.scene_properties.color_properties();
2403 mem::swap(&mut self.color_bindings, &mut self.old_color_bindings);
2404
2405 self.color_bindings.clear();
2406 for (id, value) in current_properties {
2407 let changed = match self.old_color_bindings.get(id) {
2408 Some(old_property) => old_property.value != (*value).into(),
2409 None => true,
2410 };
2411 self.color_bindings.insert(*id, ColorBindingInfo {
2412 value: (*value).into(),
2413 changed,
2414 });
2415 }
2416
2417 let world_tile_size = WorldSize::new(
2418 self.current_tile_size.width as f32 / frame_context.global_device_pixel_scale.0,
2419 self.current_tile_size.height as f32 / frame_context.global_device_pixel_scale.0,
2420 );
2421
2422 self.tile_size = PictureSize::new(
2423 world_tile_size.width / self.local_to_raster.scale.x,
2424 world_tile_size.height / self.local_to_raster.scale.y,
2425 );
2426
2427 let desired_rect_in_pic_space = self.screen_rect_in_pic_space
2432 .inflate(0.0, 1.0 * self.tile_size.height);
2433
2434 let needed_rect_in_pic_space = desired_rect_in_pic_space
2435 .intersection(&pic_rect)
2436 .unwrap_or_else(Box2D::zero);
2437
2438 let p0 = needed_rect_in_pic_space.min;
2439 let p1 = needed_rect_in_pic_space.max;
2440
2441 let x0 = (p0.x / self.tile_size.width).floor() as i32;
2442 let x1 = (p1.x / self.tile_size.width).ceil() as i32;
2443
2444 let y0 = (p0.y / self.tile_size.height).floor() as i32;
2445 let y1 = (p1.y / self.tile_size.height).ceil() as i32;
2446
2447 let new_tile_rect = TileRect {
2448 min: TileOffset::new(x0, y0),
2449 max: TileOffset::new(x1, y1),
2450 };
2451
2452 let virtual_surface_size = frame_context.config.compositor_kind.get_virtual_surface_size();
2458 if virtual_surface_size > 0 {
2461 let tx0 = self.virtual_offset.x + x0 * self.current_tile_size.width;
2463 let ty0 = self.virtual_offset.y + y0 * self.current_tile_size.height;
2464 let tx1 = self.virtual_offset.x + (x1+1) * self.current_tile_size.width;
2465 let ty1 = self.virtual_offset.y + (y1+1) * self.current_tile_size.height;
2466
2467 let need_new_virtual_offset = tx0 < 0 ||
2468 ty0 < 0 ||
2469 tx1 >= virtual_surface_size ||
2470 ty1 >= virtual_surface_size;
2471
2472 if need_new_virtual_offset {
2473 self.virtual_offset = DeviceIntPoint::new(
2477 (virtual_surface_size/2) - ((x0 + x1) / 2) * self.current_tile_size.width,
2478 (virtual_surface_size/2) - ((y0 + y1) / 2) * self.current_tile_size.height,
2479 );
2480
2481 for sub_slice in &mut self.sub_slices {
2484 for tile in sub_slice.tiles.values_mut() {
2485 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2486 if let Some(id) = id.take() {
2487 frame_state.resource_cache.destroy_compositor_tile(id);
2488 tile.surface = None;
2489 tile.invalidate(None, InvalidationReason::CompositorKindChanged);
2492 }
2493 }
2494 }
2495
2496 if let Some(native_surface) = sub_slice.native_surface.take() {
2499 frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
2500 frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
2501 }
2502 }
2503 }
2504 }
2505
2506 if new_tile_rect != self.tile_rect {
2508 for sub_slice in &mut self.sub_slices {
2509 let mut old_tiles = sub_slice.resize(new_tile_rect);
2510
2511 if !old_tiles.is_empty() {
2513 frame_state.composite_state.dirty_rects_are_valid = false;
2514 }
2515
2516 frame_state.composite_state.destroy_native_tiles(
2521 old_tiles.values_mut(),
2522 frame_state.resource_cache,
2523 );
2524 }
2525 }
2526
2527 self.tile_bounds_p0 = TileOffset::new(x0, y0);
2530 self.tile_bounds_p1 = TileOffset::new(x1, y1);
2531 self.tile_rect = new_tile_rect;
2532
2533 let mut world_culling_rect = WorldRect::zero();
2534
2535 let mut ctx = TilePreUpdateContext {
2536 pic_to_world_mapper,
2537 background_color: self.background_color,
2538 global_screen_world_rect: frame_context.global_screen_world_rect,
2539 tile_size: self.tile_size,
2540 frame_id: self.frame_id,
2541 };
2542
2543 for sub_slice in &mut self.sub_slices {
2545 for tile in sub_slice.tiles.values_mut() {
2546 tile.pre_update(&ctx);
2547
2548 if tile.is_visible {
2561 world_culling_rect = world_culling_rect.union(&tile.world_tile_rect);
2562 }
2563 }
2564
2565 ctx.background_color = None;
2567 }
2568
2569 match frame_context.config.compositor_kind {
2571 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
2572 for sub_slice in &mut self.sub_slices {
2573 for tile in sub_slice.tiles.values_mut() {
2574 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
2575 if let Some(id) = id.take() {
2576 frame_state.resource_cache.destroy_compositor_tile(id);
2577 }
2578 tile.surface = None;
2579 tile.invalidate(None, InvalidationReason::CompositorKindChanged);
2581 }
2582 }
2583
2584 if let Some(native_surface) = sub_slice.native_surface.take() {
2585 frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
2586 frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
2587 }
2588 }
2589
2590 for (_, external_surface) in self.external_native_surface_cache.drain() {
2591 frame_state.resource_cache.destroy_compositor_surface(external_surface.native_surface_id)
2592 }
2593 }
2594 CompositorKind::Native { .. } => {
2595 for sub_slice in &mut self.sub_slices {
2598 for tile in sub_slice.tiles.values_mut() {
2599 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::TextureCache { .. }, .. }) = tile.surface {
2600 tile.surface = None;
2601 tile.invalidate(None, InvalidationReason::CompositorKindChanged);
2603 }
2604 }
2605 }
2606 }
2607 }
2608
2609 world_culling_rect
2610 }
2611
2612 fn can_promote_to_surface(
2613 &mut self,
2614 prim_clip_chain: &ClipChainInstance,
2615 prim_spatial_node_index: SpatialNodeIndex,
2616 is_root_tile_cache: bool,
2617 sub_slice_index: usize,
2618 surface_kind: CompositorSurfaceKind,
2619 pic_coverage_rect: PictureRect,
2620 frame_context: &FrameVisibilityContext,
2621 force: bool,
2622 ) -> Result<CompositorSurfaceKind, SurfacePromotionFailure> {
2623 use crate::picture::SurfacePromotionFailure::*;
2624
2625 match surface_kind {
2627 CompositorSurfaceKind::Overlay => {
2628 if sub_slice_index == self.sub_slices.len() - 1 {
2632 return Err(OverlaySurfaceLimit);
2633 }
2634
2635 if prim_clip_chain.needs_mask {
2638 return Err(OverlayNeedsMask);
2639 }
2640 }
2641 CompositorSurfaceKind::Underlay => {
2642 if prim_clip_chain.needs_mask {
2644 if !self.backdrop.opaque_rect.contains_box(&pic_coverage_rect) {
2648 let result = Err(UnderlayAlphaBackdrop);
2649 if !force {
2651 return result;
2652 }
2653
2654 self.report_promotion_failure(result, pic_coverage_rect, true);
2656 }
2657
2658 if !self.underlays.is_empty() {
2660 return Err(UnderlaySurfaceLimit);
2661 }
2662 }
2663
2664 if self.overlay_region.intersects(&pic_coverage_rect) {
2667 let result = Err(UnderlayIntersectsOverlay);
2668 if !force {
2670 return result;
2671 }
2672
2673 self.report_promotion_failure(result, pic_coverage_rect, true);
2675 }
2676
2677 if frame_context.config.low_quality_pinch_zoom &&
2681 frame_context.spatial_tree.get_spatial_node(prim_spatial_node_index).is_ancestor_or_self_zooming
2682 {
2683 return Err(UnderlayLowQualityZoom);
2684 }
2685 }
2686 CompositorSurfaceKind::Blit => unreachable!(),
2687 }
2688
2689 if !is_root_tile_cache {
2692 return Err(NotRootTileCache);
2693 }
2694
2695 let mapper : SpaceMapper<PicturePixel, WorldPixel> = SpaceMapper::new_with_target(
2696 frame_context.root_spatial_node_index,
2697 prim_spatial_node_index,
2698 frame_context.global_screen_world_rect,
2699 &frame_context.spatial_tree);
2700 let transform = mapper.get_transform();
2701 if !transform.is_2d_scale_translation() {
2702 let result = Err(ComplexTransform);
2703 return result;
2707 }
2708
2709 if self.slice_flags.contains(SliceFlags::IS_ATOMIC) {
2710 return Err(SliceAtomic);
2711 }
2712
2713 Ok(surface_kind)
2714 }
2715
2716 fn setup_compositor_surfaces_yuv(
2717 &mut self,
2718 sub_slice_index: usize,
2719 prim_info: &mut PrimitiveDependencyInfo,
2720 flags: PrimitiveFlags,
2721 local_prim_rect: LayoutRect,
2722 prim_spatial_node_index: SpatialNodeIndex,
2723 pic_coverage_rect: PictureRect,
2724 frame_context: &FrameVisibilityContext,
2725 image_dependencies: &[ImageDependency;3],
2726 api_keys: &[ImageKey; 3],
2727 resource_cache: &mut ResourceCache,
2728 composite_state: &mut CompositeState,
2729 gpu_cache: &mut GpuCache,
2730 image_rendering: ImageRendering,
2731 color_depth: ColorDepth,
2732 color_space: YuvRangedColorSpace,
2733 format: YuvFormat,
2734 surface_kind: CompositorSurfaceKind,
2735 ) -> Result<CompositorSurfaceKind, SurfacePromotionFailure> {
2736 for &key in api_keys {
2737 if key != ImageKey::DUMMY {
2738 resource_cache.request_image(ImageRequest {
2740 key,
2741 rendering: image_rendering,
2742 tile: None,
2743 },
2744 gpu_cache,
2745 );
2746 }
2747 }
2748
2749 self.setup_compositor_surfaces_impl(
2750 sub_slice_index,
2751 prim_info,
2752 flags,
2753 local_prim_rect,
2754 prim_spatial_node_index,
2755 pic_coverage_rect,
2756 frame_context,
2757 ExternalSurfaceDependency::Yuv {
2758 image_dependencies: *image_dependencies,
2759 color_space,
2760 format,
2761 channel_bit_depth: color_depth.bit_depth(),
2762 },
2763 api_keys,
2764 resource_cache,
2765 composite_state,
2766 image_rendering,
2767 true,
2768 surface_kind,
2769 )
2770 }
2771
2772 fn setup_compositor_surfaces_rgb(
2773 &mut self,
2774 sub_slice_index: usize,
2775 prim_info: &mut PrimitiveDependencyInfo,
2776 flags: PrimitiveFlags,
2777 local_prim_rect: LayoutRect,
2778 prim_spatial_node_index: SpatialNodeIndex,
2779 pic_coverage_rect: PictureRect,
2780 frame_context: &FrameVisibilityContext,
2781 image_dependency: ImageDependency,
2782 api_key: ImageKey,
2783 resource_cache: &mut ResourceCache,
2784 composite_state: &mut CompositeState,
2785 gpu_cache: &mut GpuCache,
2786 image_rendering: ImageRendering,
2787 is_opaque: bool,
2788 surface_kind: CompositorSurfaceKind,
2789 ) -> Result<CompositorSurfaceKind, SurfacePromotionFailure> {
2790 let mut api_keys = [ImageKey::DUMMY; 3];
2791 api_keys[0] = api_key;
2792
2793 resource_cache.request_image(ImageRequest {
2800 key: api_key,
2801 rendering: image_rendering,
2802 tile: None,
2803 },
2804 gpu_cache,
2805 );
2806
2807 self.setup_compositor_surfaces_impl(
2808 sub_slice_index,
2809 prim_info,
2810 flags,
2811 local_prim_rect,
2812 prim_spatial_node_index,
2813 pic_coverage_rect,
2814 frame_context,
2815 ExternalSurfaceDependency::Rgb {
2816 image_dependency,
2817 },
2818 &api_keys,
2819 resource_cache,
2820 composite_state,
2821 image_rendering,
2822 is_opaque,
2823 surface_kind,
2824 )
2825 }
2826
2827 fn setup_compositor_surfaces_impl(
2830 &mut self,
2831 sub_slice_index: usize,
2832 prim_info: &mut PrimitiveDependencyInfo,
2833 flags: PrimitiveFlags,
2834 local_prim_rect: LayoutRect,
2835 prim_spatial_node_index: SpatialNodeIndex,
2836 pic_coverage_rect: PictureRect,
2837 frame_context: &FrameVisibilityContext,
2838 dependency: ExternalSurfaceDependency,
2839 api_keys: &[ImageKey; 3],
2840 resource_cache: &mut ResourceCache,
2841 composite_state: &mut CompositeState,
2842 image_rendering: ImageRendering,
2843 is_opaque: bool,
2844 surface_kind: CompositorSurfaceKind,
2845 ) -> Result<CompositorSurfaceKind, SurfacePromotionFailure> {
2846 use crate::picture::SurfacePromotionFailure::*;
2847
2848 let map_local_to_picture = SpaceMapper::new_with_target(
2849 self.spatial_node_index,
2850 prim_spatial_node_index,
2851 self.local_rect,
2852 frame_context.spatial_tree,
2853 );
2854
2855 let prim_rect = match map_local_to_picture.map(&local_prim_rect) {
2857 Some(rect) => rect,
2858 None => return Ok(surface_kind),
2859 };
2860
2861 if prim_rect.is_empty() {
2863 return Ok(surface_kind);
2864 }
2865
2866 let pic_to_world_mapper = SpaceMapper::new_with_target(
2867 frame_context.root_spatial_node_index,
2868 self.spatial_node_index,
2869 frame_context.global_screen_world_rect,
2870 frame_context.spatial_tree,
2871 );
2872
2873 let world_clip_rect = pic_to_world_mapper
2874 .map(&prim_info.prim_clip_box)
2875 .expect("bug: unable to map clip to world space");
2876
2877 let is_visible = world_clip_rect.intersects(&frame_context.global_screen_world_rect);
2878 if !is_visible {
2879 return Ok(surface_kind);
2880 }
2881
2882 let prim_offset = ScaleOffset::from_offset(local_prim_rect.min.to_vector().cast_unit());
2883
2884 let local_prim_to_device = get_relative_scale_offset(
2885 prim_spatial_node_index,
2886 frame_context.root_spatial_node_index,
2887 frame_context.spatial_tree,
2888 );
2889
2890 let normalized_prim_to_device = prim_offset.then(&local_prim_to_device);
2891
2892 let local_to_raster = ScaleOffset::identity();
2893 let raster_to_device = normalized_prim_to_device;
2894
2895 let mut external_image_id = if flags.contains(PrimitiveFlags::SUPPORTS_EXTERNAL_COMPOSITOR_SURFACE)
2899 && image_rendering == ImageRendering::Auto {
2900 resource_cache.get_image_properties(api_keys[0])
2901 .and_then(|properties| properties.external_image)
2902 .and_then(|image| Some(image.id))
2903 } else {
2904 None
2905 };
2906
2907
2908 if let CompositorKind::Native { capabilities, .. } = composite_state.compositor_kind {
2909 if external_image_id.is_some() &&
2910 !capabilities.supports_external_compositor_surface_negative_scaling &&
2911 (raster_to_device.scale.x < 0.0 || raster_to_device.scale.y < 0.0) {
2912 external_image_id = None;
2913 }
2914 }
2915
2916 let compositor_transform_index = composite_state.register_transform(
2917 local_to_raster,
2918 raster_to_device,
2919 );
2920
2921 let surface_size = composite_state.get_surface_rect(
2922 &local_prim_rect,
2923 &local_prim_rect,
2924 compositor_transform_index,
2925 ).size();
2926
2927 let clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round();
2928
2929 if surface_size.width >= MAX_COMPOSITOR_SURFACES_SIZE ||
2930 surface_size.height >= MAX_COMPOSITOR_SURFACES_SIZE {
2931 return Err(SizeTooLarge);
2932 }
2933
2934 let (native_surface_id, update_params) = match composite_state.compositor_kind {
2939 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
2940 (None, None)
2941 }
2942 CompositorKind::Native { .. } => {
2943 let native_surface_size = surface_size.to_i32();
2944
2945 let key = ExternalNativeSurfaceKey {
2946 image_keys: *api_keys,
2947 size: if external_image_id.is_some() { None } else { Some(native_surface_size) },
2948 };
2949
2950 let native_surface = self.external_native_surface_cache
2951 .entry(key)
2952 .or_insert_with(|| {
2953 let native_surface_id = match external_image_id {
2955 Some(_external_image) => {
2956 resource_cache.create_compositor_external_surface(is_opaque)
2959 }
2960 None => {
2961 let native_surface_id =
2964 resource_cache.create_compositor_surface(
2965 DeviceIntPoint::zero(),
2966 native_surface_size,
2967 is_opaque,
2968 );
2969
2970 let tile_id = NativeTileId {
2971 surface_id: native_surface_id,
2972 x: 0,
2973 y: 0,
2974 };
2975 resource_cache.create_compositor_tile(tile_id);
2976
2977 native_surface_id
2978 }
2979 };
2980
2981 ExternalNativeSurface {
2982 used_this_frame: true,
2983 native_surface_id,
2984 image_dependencies: [ImageDependency::INVALID; 3],
2985 }
2986 });
2987
2988 native_surface.used_this_frame = true;
2991
2992 let update_params = match external_image_id {
2993 Some(external_image) => {
2994 resource_cache.attach_compositor_external_image(
2998 native_surface.native_surface_id,
2999 external_image,
3000 );
3001 None
3002 }
3003 None => {
3004 match dependency {
3007 ExternalSurfaceDependency::Yuv{ image_dependencies, .. } => {
3008 if image_dependencies == native_surface.image_dependencies {
3009 None
3010 } else {
3011 Some(native_surface_size)
3012 }
3013 },
3014 ExternalSurfaceDependency::Rgb{ image_dependency, .. } => {
3015 if image_dependency == native_surface.image_dependencies[0] {
3016 None
3017 } else {
3018 Some(native_surface_size)
3019 }
3020 },
3021 }
3022 }
3023 };
3024
3025 (Some(native_surface.native_surface_id), update_params)
3026 }
3027 };
3028
3029 let descriptor = ExternalSurfaceDescriptor {
3030 local_surface_size: local_prim_rect.size(),
3031 local_rect: prim_rect,
3032 local_clip_rect: prim_info.prim_clip_box,
3033 dependency,
3034 image_rendering,
3035 clip_rect,
3036 transform_index: compositor_transform_index,
3037 z_id: ZBufferId::invalid(),
3038 native_surface_id,
3039 update_params,
3040 external_image_id,
3041 };
3042
3043 match surface_kind {
3046 CompositorSurfaceKind::Underlay => {
3047 self.underlays.push(descriptor);
3048 }
3049 CompositorSurfaceKind::Overlay => {
3050 assert!(sub_slice_index < self.sub_slices.len() - 1);
3053 let sub_slice = &mut self.sub_slices[sub_slice_index];
3054
3055 sub_slice.compositor_surfaces.push(CompositorSurface {
3057 prohibited_rect: pic_coverage_rect,
3058 is_opaque,
3059 descriptor,
3060 });
3061
3062 self.overlay_region = self.overlay_region.union(&pic_coverage_rect);
3066 }
3067 CompositorSurfaceKind::Blit => unreachable!(),
3068 }
3069
3070 Ok(surface_kind)
3071 }
3072
3073 pub fn push_surface(
3079 &mut self,
3080 estimated_local_rect: LayoutRect,
3081 surface_spatial_node_index: SpatialNodeIndex,
3082 spatial_tree: &SpatialTree,
3083 ) {
3084 if self.current_surface_traversal_depth == 0 && self.sub_slices.len() > 1 {
3086 let map_local_to_picture = SpaceMapper::new_with_target(
3087 self.spatial_node_index,
3088 surface_spatial_node_index,
3089 self.local_rect,
3090 spatial_tree,
3091 );
3092
3093 if let Some(pic_rect) = map_local_to_picture.map(&estimated_local_rect) {
3094 for sub_slice in &mut self.sub_slices {
3097 let mut intersects_prohibited_region = false;
3098
3099 for surface in &mut sub_slice.compositor_surfaces {
3100 if pic_rect.intersects(&surface.prohibited_rect) {
3101 surface.prohibited_rect = surface.prohibited_rect.union(&pic_rect);
3102
3103 intersects_prohibited_region = true;
3104 }
3105 }
3106
3107 if !intersects_prohibited_region {
3108 break;
3109 }
3110 }
3111 }
3112 }
3113
3114 self.current_surface_traversal_depth += 1;
3115 }
3116
3117 pub fn pop_surface(&mut self) {
3119 self.current_surface_traversal_depth -= 1;
3120 }
3121
3122 fn report_promotion_failure(&self,
3123 result: Result<CompositorSurfaceKind, SurfacePromotionFailure>,
3124 rect: PictureRect,
3125 ignored: bool) {
3126 if !self.debug_flags.contains(DebugFlags::SURFACE_PROMOTION_LOGGING) || result.is_ok() {
3127 return;
3128 }
3129
3130 let outcome = if ignored { "failure ignored" } else { "failed" };
3133 warn!("Surface promotion of prim at {:?} {outcome} with: {}.", rect, result.unwrap_err());
3134 }
3135
3136 pub fn update_prim_dependencies(
3138 &mut self,
3139 prim_instance: &mut PrimitiveInstance,
3140 prim_spatial_node_index: SpatialNodeIndex,
3141 local_prim_rect: LayoutRect,
3142 frame_context: &FrameVisibilityContext,
3143 data_stores: &DataStores,
3144 clip_store: &ClipStore,
3145 pictures: &[PicturePrimitive],
3146 resource_cache: &mut ResourceCache,
3147 color_bindings: &ColorBindingStorage,
3148 surface_stack: &[(PictureIndex, SurfaceIndex)],
3149 composite_state: &mut CompositeState,
3150 gpu_cache: &mut GpuCache,
3151 scratch: &mut PrimitiveScratchBuffer,
3152 is_root_tile_cache: bool,
3153 surfaces: &mut [SurfaceInfo],
3154 profile: &mut TransactionProfile,
3155 ) -> VisibilityState {
3156 use crate::picture::SurfacePromotionFailure::*;
3157
3158 profile_scope!("update_prim_dependencies");
3160 let prim_surface_index = surface_stack.last().unwrap().1;
3161 let prim_clip_chain = &prim_instance.vis.clip_chain;
3162
3163 let on_picture_surface = prim_surface_index == self.surface_index;
3167 let pic_coverage_rect = if on_picture_surface {
3168 prim_clip_chain.pic_coverage_rect
3169 } else {
3170 let mut current_pic_coverage_rect = prim_clip_chain.pic_coverage_rect;
3178 let mut current_spatial_node_index = surfaces[prim_surface_index.0]
3179 .surface_spatial_node_index;
3180
3181 for (pic_index, surface_index) in surface_stack.iter().rev() {
3182 let surface = &surfaces[surface_index.0];
3183 let pic = &pictures[pic_index.0];
3184
3185 let map_local_to_parent = SpaceMapper::new_with_target(
3186 surface.surface_spatial_node_index,
3187 current_spatial_node_index,
3188 surface.unclipped_local_rect,
3189 frame_context.spatial_tree,
3190 );
3191
3192 current_pic_coverage_rect = match map_local_to_parent.map(¤t_pic_coverage_rect) {
3196 Some(rect) => {
3197 pic.composite_mode.as_ref().unwrap().get_coverage(
3203 surface,
3204 Some(rect.cast_unit()),
3205 ).cast_unit()
3206 }
3207 None => {
3208 return VisibilityState::Culled;
3209 }
3210 };
3211
3212 current_spatial_node_index = surface.surface_spatial_node_index;
3213 }
3214
3215 current_pic_coverage_rect
3216 };
3217
3218 let (p0, p1) = self.get_tile_coords_for_rect(&pic_coverage_rect);
3220
3221 if p0.x == p1.x || p0.y == p1.y {
3224 return VisibilityState::Culled;
3225 }
3226
3227 let mut prim_info = PrimitiveDependencyInfo::new(
3229 prim_instance.uid(),
3230 pic_coverage_rect,
3231 );
3232
3233 let mut sub_slice_index = self.sub_slices.len() - 1;
3234
3235 if sub_slice_index > 0 {
3237 for (i, sub_slice) in self.sub_slices.iter_mut().enumerate() {
3240 let mut intersects_prohibited_region = false;
3241
3242 for surface in &mut sub_slice.compositor_surfaces {
3243 if pic_coverage_rect.intersects(&surface.prohibited_rect) {
3244 surface.prohibited_rect = surface.prohibited_rect.union(&pic_coverage_rect);
3245
3246 intersects_prohibited_region = true;
3247 }
3248 }
3249
3250 if !intersects_prohibited_region {
3251 sub_slice_index = i;
3252 break;
3253 }
3254 }
3255 }
3256
3257 if prim_spatial_node_index != self.spatial_node_index {
3259 prim_info.spatial_nodes.push(prim_spatial_node_index);
3260 }
3261
3262 let clip_instances = &clip_store
3264 .clip_node_instances[prim_clip_chain.clips_range.to_range()];
3265 for clip_instance in clip_instances {
3266 let clip = &data_stores.clip[clip_instance.handle];
3267
3268 prim_info.clips.push(clip_instance.handle.uid());
3269
3270 if clip.item.spatial_node_index != self.spatial_node_index
3273 && !prim_info.spatial_nodes.contains(&clip.item.spatial_node_index) {
3274 prim_info.spatial_nodes.push(clip.item.spatial_node_index);
3275 }
3276 }
3277
3278 let mut backdrop_candidate = None;
3281
3282 match prim_instance.kind {
3294 PrimitiveInstanceKind::Picture { pic_index,.. } => {
3295 let pic = &pictures[pic_index.0];
3297 if let Some(PictureCompositeMode::Filter(Filter::Opacity(binding, _))) = pic.composite_mode {
3298 prim_info.opacity_bindings.push(binding.into());
3299 }
3300 }
3301 PrimitiveInstanceKind::Rectangle { data_handle, color_binding_index, .. } => {
3302 let color = match data_stores.prim[data_handle].kind {
3306 PrimitiveTemplateKind::Rectangle { color, .. } => {
3307 frame_context.scene_properties.resolve_color(&color)
3308 }
3309 _ => unreachable!(),
3310 };
3311 if color.a >= 1.0 {
3312 backdrop_candidate = Some(BackdropInfo {
3313 opaque_rect: pic_coverage_rect,
3314 spanning_opaque_color: None,
3315 kind: Some(BackdropKind::Color { color }),
3316 backdrop_rect: pic_coverage_rect,
3317 });
3318 }
3319
3320 if color_binding_index != ColorBindingIndex::INVALID {
3321 prim_info.color_binding = Some(color_bindings[color_binding_index].into());
3322 }
3323 }
3324 PrimitiveInstanceKind::Image { data_handle, ref mut compositor_surface_kind, .. } => {
3325 let image_key = &data_stores.image[data_handle];
3326 let image_data = &image_key.kind;
3327
3328 let mut is_opaque = false;
3333
3334 if let Some(image_properties) = resource_cache.get_image_properties(image_data.key) {
3335 if image_properties.descriptor.is_opaque() &&
3341 image_properties.tiling.is_none() &&
3342 image_data.tile_spacing == LayoutSize::zero() &&
3343 image_data.color.a >= 1.0 {
3344 backdrop_candidate = Some(BackdropInfo {
3345 opaque_rect: pic_coverage_rect,
3346 spanning_opaque_color: None,
3347 kind: None,
3348 backdrop_rect: PictureRect::zero(),
3349 });
3350 }
3351
3352 is_opaque = image_properties.descriptor.is_opaque();
3353 }
3354
3355 let mut promotion_result: Result<CompositorSurfaceKind, SurfacePromotionFailure> = Ok(CompositorSurfaceKind::Blit);
3356 if image_key.common.flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
3357 if self.yuv_images_remaining > 0 {
3360 promotion_result = Err(ImageWaitingOnYuvImage);
3361 } else {
3362 promotion_result = self.can_promote_to_surface(prim_clip_chain,
3363 prim_spatial_node_index,
3364 is_root_tile_cache,
3365 sub_slice_index,
3366 CompositorSurfaceKind::Overlay,
3367 pic_coverage_rect,
3368 frame_context,
3369 false);
3370 }
3371
3372 if image_data.alpha_type == AlphaType::Alpha {
3375 promotion_result = Err(NotPremultipliedAlpha);
3376 }
3377
3378 if let Ok(kind) = promotion_result {
3379 promotion_result = self.setup_compositor_surfaces_rgb(
3380 sub_slice_index,
3381 &mut prim_info,
3382 image_key.common.flags,
3383 local_prim_rect,
3384 prim_spatial_node_index,
3385 pic_coverage_rect,
3386 frame_context,
3387 ImageDependency {
3388 key: image_data.key,
3389 generation: resource_cache.get_image_generation(image_data.key),
3390 },
3391 image_data.key,
3392 resource_cache,
3393 composite_state,
3394 gpu_cache,
3395 image_data.image_rendering,
3396 is_opaque,
3397 kind,
3398 );
3399 }
3400 }
3401
3402 if let Ok(kind) = promotion_result {
3403 *compositor_surface_kind = kind;
3404
3405 if kind == CompositorSurfaceKind::Overlay {
3406 profile.inc(profiler::COMPOSITOR_SURFACE_OVERLAYS);
3407 return VisibilityState::Culled;
3408 }
3409
3410 assert!(kind == CompositorSurfaceKind::Blit, "Image prims should either be overlays or blits.");
3411 } else {
3412 self.report_promotion_failure(promotion_result, pic_coverage_rect, false);
3414 *compositor_surface_kind = CompositorSurfaceKind::Blit;
3415 }
3416
3417 if image_key.common.flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
3418 profile.inc(profiler::COMPOSITOR_SURFACE_BLITS);
3419 }
3420
3421 prim_info.images.push(ImageDependency {
3422 key: image_data.key,
3423 generation: resource_cache.get_image_generation(image_data.key),
3424 });
3425 }
3426 PrimitiveInstanceKind::YuvImage { data_handle, ref mut compositor_surface_kind, .. } => {
3427 let prim_data = &data_stores.yuv_image[data_handle];
3428
3429 let mut promotion_result: Result<CompositorSurfaceKind, SurfacePromotionFailure> = Ok(CompositorSurfaceKind::Blit);
3430 if prim_data.common.flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
3431 if is_root_tile_cache {
3437 self.yuv_images_remaining -= 1;
3438 }
3439
3440 let force = prim_data.kind.color_depth.bit_depth() > 8;
3443
3444 let clip_on_top = prim_clip_chain.needs_mask;
3445 let prefer_underlay = clip_on_top || !cfg!(target_os = "macos");
3446 let promotion_attempts = if prefer_underlay {
3447 [CompositorSurfaceKind::Underlay, CompositorSurfaceKind::Overlay]
3448 } else {
3449 [CompositorSurfaceKind::Overlay, CompositorSurfaceKind::Underlay]
3450 };
3451
3452 for kind in promotion_attempts {
3453 promotion_result = self.can_promote_to_surface(
3456 prim_clip_chain,
3457 prim_spatial_node_index,
3458 is_root_tile_cache,
3459 sub_slice_index,
3460 kind,
3461 pic_coverage_rect,
3462 frame_context,
3463 force);
3464 if promotion_result.is_ok() {
3465 break;
3466 }
3467
3468 if let Err(SliceAtomic) = promotion_result {
3473 if prim_data.kind. color_depth != ColorDepth::Color8 {
3474 promotion_result = Ok(kind);
3476 break;
3477 }
3478 }
3479 }
3480
3481 if let Ok(kind) = promotion_result {
3490 let mut image_dependencies = [ImageDependency::INVALID; 3];
3493 for (key, dep) in prim_data.kind.yuv_key.iter().cloned().zip(image_dependencies.iter_mut()) {
3494 *dep = ImageDependency {
3495 key,
3496 generation: resource_cache.get_image_generation(key),
3497 }
3498 }
3499
3500 promotion_result = self.setup_compositor_surfaces_yuv(
3501 sub_slice_index,
3502 &mut prim_info,
3503 prim_data.common.flags,
3504 local_prim_rect,
3505 prim_spatial_node_index,
3506 pic_coverage_rect,
3507 frame_context,
3508 &image_dependencies,
3509 &prim_data.kind.yuv_key,
3510 resource_cache,
3511 composite_state,
3512 gpu_cache,
3513 prim_data.kind.image_rendering,
3514 prim_data.kind.color_depth,
3515 prim_data.kind.color_space.with_range(prim_data.kind.color_range),
3516 prim_data.kind.format,
3517 kind,
3518 );
3519 }
3520 }
3521
3522 if let Ok(kind) = promotion_result {
3526 *compositor_surface_kind = kind;
3527 if kind == CompositorSurfaceKind::Overlay {
3528 profile.inc(profiler::COMPOSITOR_SURFACE_OVERLAYS);
3529 return VisibilityState::Culled;
3530 }
3531
3532 profile.inc(profiler::COMPOSITOR_SURFACE_UNDERLAYS);
3533 } else {
3534 self.report_promotion_failure(promotion_result, pic_coverage_rect, false);
3536 *compositor_surface_kind = CompositorSurfaceKind::Blit;
3537 if prim_data.common.flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
3538 profile.inc(profiler::COMPOSITOR_SURFACE_BLITS);
3539 }
3540 }
3541
3542 if *compositor_surface_kind == CompositorSurfaceKind::Blit {
3543 prim_info.images.extend(
3544 prim_data.kind.yuv_key.iter().map(|key| {
3545 ImageDependency {
3546 key: *key,
3547 generation: resource_cache.get_image_generation(*key),
3548 }
3549 })
3550 );
3551 }
3552 }
3553 PrimitiveInstanceKind::ImageBorder { data_handle, .. } => {
3554 let border_data = &data_stores.image_border[data_handle].kind;
3555 prim_info.images.push(ImageDependency {
3556 key: border_data.request.key,
3557 generation: resource_cache.get_image_generation(border_data.request.key),
3558 });
3559 }
3560 PrimitiveInstanceKind::Clear { .. } => {
3561 backdrop_candidate = Some(BackdropInfo {
3562 opaque_rect: pic_coverage_rect,
3563 spanning_opaque_color: None,
3564 kind: Some(BackdropKind::Clear),
3565 backdrop_rect: pic_coverage_rect,
3566 });
3567 }
3568 PrimitiveInstanceKind::LinearGradient { data_handle, .. }
3569 | PrimitiveInstanceKind::CachedLinearGradient { data_handle, .. } => {
3570 let gradient_data = &data_stores.linear_grad[data_handle];
3571 if gradient_data.stops_opacity.is_opaque
3572 && gradient_data.tile_spacing == LayoutSize::zero()
3573 {
3574 backdrop_candidate = Some(BackdropInfo {
3575 opaque_rect: pic_coverage_rect,
3576 spanning_opaque_color: None,
3577 kind: None,
3578 backdrop_rect: PictureRect::zero(),
3579 });
3580 }
3581 }
3582 PrimitiveInstanceKind::ConicGradient { data_handle, .. } => {
3583 let gradient_data = &data_stores.conic_grad[data_handle];
3584 if gradient_data.stops_opacity.is_opaque
3585 && gradient_data.tile_spacing == LayoutSize::zero()
3586 {
3587 backdrop_candidate = Some(BackdropInfo {
3588 opaque_rect: pic_coverage_rect,
3589 spanning_opaque_color: None,
3590 kind: None,
3591 backdrop_rect: PictureRect::zero(),
3592 });
3593 }
3594 }
3595 PrimitiveInstanceKind::RadialGradient { data_handle, .. } => {
3596 let gradient_data = &data_stores.radial_grad[data_handle];
3597 if gradient_data.stops_opacity.is_opaque
3598 && gradient_data.tile_spacing == LayoutSize::zero()
3599 {
3600 backdrop_candidate = Some(BackdropInfo {
3601 opaque_rect: pic_coverage_rect,
3602 spanning_opaque_color: None,
3603 kind: None,
3604 backdrop_rect: PictureRect::zero(),
3605 });
3606 }
3607 }
3608 PrimitiveInstanceKind::BackdropCapture { .. } => {}
3609 PrimitiveInstanceKind::BackdropRender { pic_index, .. } => {
3610 if !pic_coverage_rect.is_empty() {
3616 scratch.required_sub_graphs.insert(pic_index);
3619
3620 let sub_slice = &mut self.sub_slices[sub_slice_index];
3623
3624 let mut surface_info = Vec::new();
3625 for (pic_index, surface_index) in surface_stack.iter().rev() {
3626 let pic = &pictures[pic_index.0];
3627 surface_info.push((pic.composite_mode.as_ref().unwrap().clone(), *surface_index));
3628 }
3629
3630 for y in p0.y .. p1.y {
3631 for x in p0.x .. p1.x {
3632 let key = TileOffset::new(x, y);
3633 let tile = sub_slice.tiles.get_mut(&key).expect("bug: no tile");
3634 tile.sub_graphs.push((pic_coverage_rect, surface_info.clone()));
3635 }
3636 }
3637
3638 self.deferred_dirty_tests.push(DeferredDirtyTest {
3641 tile_rect: TileRect::new(p0, p1),
3642 prim_rect: pic_coverage_rect,
3643 });
3644 }
3645 }
3646 PrimitiveInstanceKind::LineDecoration { .. } |
3647 PrimitiveInstanceKind::NormalBorder { .. } |
3648 PrimitiveInstanceKind::BoxShadow { .. } |
3649 PrimitiveInstanceKind::TextRun { .. } => {
3650 }
3652 };
3653
3654 let visible_local_clip_rect = self.local_clip_rect.intersection(&self.screen_rect_in_pic_space).unwrap_or_default();
3658 if pic_coverage_rect.intersects(&visible_local_clip_rect) {
3659 self.found_prims_after_backdrop = true;
3660 }
3661
3662 let mut vis_flags = PrimitiveVisibilityFlags::empty();
3665 let sub_slice = &mut self.sub_slices[sub_slice_index];
3666 if let Some(mut backdrop_candidate) = backdrop_candidate {
3667 match backdrop_candidate.kind {
3672 Some(BackdropKind::Color { .. }) | None => {
3673 let surface = &mut surfaces[prim_surface_index.0];
3674
3675 let is_same_coord_system = frame_context.spatial_tree.is_matching_coord_system(
3676 prim_spatial_node_index,
3677 surface.surface_spatial_node_index,
3678 );
3679
3680 if is_same_coord_system &&
3685 !prim_clip_chain.needs_mask &&
3686 prim_clip_chain.pic_coverage_rect.contains_box(&surface.unclipped_local_rect)
3687 {
3688 surface.is_opaque = true;
3693 }
3694 }
3695 Some(BackdropKind::Clear) => {}
3696 }
3697
3698 let is_suitable_backdrop = match backdrop_candidate.kind {
3699 Some(BackdropKind::Clear) => {
3700 true
3705 }
3706 Some(BackdropKind::Color { .. }) | None => {
3707 let same_coord_system = frame_context.spatial_tree.is_matching_coord_system(
3716 prim_spatial_node_index,
3717 self.spatial_node_index,
3718 );
3719
3720 same_coord_system && on_picture_surface
3721 }
3722 };
3723
3724 if sub_slice_index == 0 &&
3725 is_suitable_backdrop &&
3726 sub_slice.compositor_surfaces.is_empty() {
3727
3728 if prim_clip_chain.needs_mask {
3731 backdrop_candidate.opaque_rect = clip_store
3732 .get_inner_rect_for_clip_chain(
3733 prim_clip_chain,
3734 &data_stores.clip,
3735 frame_context.spatial_tree,
3736 )
3737 .unwrap_or(PictureRect::zero());
3738 }
3739
3740 if backdrop_candidate.opaque_rect.contains_box(&self.backdrop.opaque_rect) {
3744 self.backdrop.opaque_rect = backdrop_candidate.opaque_rect;
3745 }
3746
3747 if let Some(kind) = backdrop_candidate.kind {
3748 if backdrop_candidate.opaque_rect.contains_box(&visible_local_clip_rect) {
3749 self.found_prims_after_backdrop = false;
3750 self.backdrop.kind = Some(kind);
3751 self.backdrop.backdrop_rect = backdrop_candidate.opaque_rect;
3752
3753 if let BackdropKind::Color { color } = kind {
3759 if backdrop_candidate.opaque_rect.contains_box(&self.local_rect) {
3760 vis_flags |= PrimitiveVisibilityFlags::IS_BACKDROP;
3761 self.backdrop.spanning_opaque_color = Some(color);
3762 }
3763 }
3764 }
3765 }
3766 }
3767 }
3768
3769 for spatial_node_index in &prim_info.spatial_nodes {
3771 self.spatial_node_comparer.register_used_transform(
3772 *spatial_node_index,
3773 self.frame_id,
3774 frame_context.spatial_tree,
3775 );
3776 }
3777
3778 for y in p0.y .. p1.y {
3781 for x in p0.x .. p1.x {
3782 let key = TileOffset::new(x, y);
3784 let tile = sub_slice.tiles.get_mut(&key).expect("bug: no tile");
3785
3786 tile.add_prim_dependency(&prim_info);
3787 }
3788 }
3789
3790 VisibilityState::Visible {
3791 vis_flags,
3792 sub_slice_index: SubSliceIndex::new(sub_slice_index),
3793 }
3794 }
3795
3796 fn print(&self) {
3798 let mut pt = PrintTree::new("Picture Cache");
3804
3805 pt.new_level(format!("Slice {:?}", self.slice));
3806
3807 pt.add_item(format!("background_color: {:?}", self.background_color));
3808
3809 for (sub_slice_index, sub_slice) in self.sub_slices.iter().enumerate() {
3810 pt.new_level(format!("SubSlice {:?}", sub_slice_index));
3811
3812 for y in self.tile_bounds_p0.y .. self.tile_bounds_p1.y {
3813 for x in self.tile_bounds_p0.x .. self.tile_bounds_p1.x {
3814 let key = TileOffset::new(x, y);
3815 let tile = &sub_slice.tiles[&key];
3816 tile.print(&mut pt);
3817 }
3818 }
3819
3820 pt.end_level();
3821 }
3822
3823 pt.end_level();
3824 }
3825
3826 fn calculate_subpixel_mode(&self) -> SubpixelMode {
3827 if self.underlays.is_empty() {
3829 let has_opaque_bg_color = self.background_color.map_or(false, |c| c.a >= 1.0);
3830
3831 if has_opaque_bg_color {
3833 return SubpixelMode::Allow;
3834 }
3835
3836 if self.backdrop.opaque_rect.contains_box(&self.local_rect) {
3840 return SubpixelMode::Allow;
3841 }
3842 }
3843
3844 if self.backdrop.opaque_rect.is_empty() {
3846 return SubpixelMode::Deny;
3847 }
3848
3849 let prohibited_rect = self
3855 .underlays
3856 .iter()
3857 .fold(
3858 PictureRect::zero(),
3859 |acc, underlay| {
3860 acc.union(&underlay.local_rect)
3861 }
3862 );
3863
3864 SubpixelMode::Conditional {
3872 allowed_rect: self.backdrop.opaque_rect,
3873 prohibited_rect,
3874 }
3875 }
3876
3877 pub fn post_update(
3881 &mut self,
3882 frame_context: &FrameVisibilityContext,
3883 composite_state: &mut CompositeState,
3884 resource_cache: &mut ResourceCache,
3885 ) {
3886 assert!(self.current_surface_traversal_depth == 0);
3887
3888 let visibility_node = frame_context.spatial_tree.root_reference_frame_index();
3890
3891 self.dirty_region.reset(visibility_node, self.spatial_node_index);
3892 self.subpixel_mode = self.calculate_subpixel_mode();
3893
3894 self.transform_index = composite_state.register_transform(
3895 self.local_to_raster,
3896 self.raster_to_device,
3899 );
3900
3901 let map_pic_to_world = SpaceMapper::new_with_target(
3902 frame_context.root_spatial_node_index,
3903 self.spatial_node_index,
3904 frame_context.global_screen_world_rect,
3905 frame_context.spatial_tree,
3906 );
3907
3908 self.external_native_surface_cache.retain(|_, surface| {
3911 if !surface.used_this_frame {
3912 composite_state.dirty_rects_are_valid = false;
3915
3916 resource_cache.destroy_compositor_surface(surface.native_surface_id);
3917 }
3918
3919 surface.used_this_frame
3920 });
3921
3922 let pic_to_world_mapper = SpaceMapper::new_with_target(
3923 frame_context.root_spatial_node_index,
3924 self.spatial_node_index,
3925 frame_context.global_screen_world_rect,
3926 frame_context.spatial_tree,
3927 );
3928
3929 let ctx = TileUpdateDirtyContext {
3930 pic_to_world_mapper,
3931 global_device_pixel_scale: frame_context.global_device_pixel_scale,
3932 opacity_bindings: &self.opacity_bindings,
3933 color_bindings: &self.color_bindings,
3934 local_rect: self.local_rect,
3935 invalidate_all: self.invalidate_all_tiles,
3936 };
3937
3938 let mut state = TileUpdateDirtyState {
3939 resource_cache,
3940 composite_state,
3941 compare_cache: &mut self.compare_cache,
3942 spatial_node_comparer: &mut self.spatial_node_comparer,
3943 };
3944
3945 for sub_slice in &mut self.sub_slices {
3948 for tile in sub_slice.tiles.values_mut() {
3949 tile.update_dirty_and_valid_rects(&ctx, &mut state, frame_context);
3950 }
3951 }
3952
3953 for sub_slice in &mut self.sub_slices {
3955 for dirty_test in self.deferred_dirty_tests.drain(..) {
3956 let mut total_dirty_rect = PictureRect::zero();
3958
3959 for y in dirty_test.tile_rect.min.y .. dirty_test.tile_rect.max.y {
3960 for x in dirty_test.tile_rect.min.x .. dirty_test.tile_rect.max.x {
3961 let key = TileOffset::new(x, y);
3962 let tile = sub_slice.tiles.get_mut(&key).expect("bug: no tile");
3963 total_dirty_rect = total_dirty_rect.union(&tile.local_dirty_rect);
3964 }
3965 }
3966
3967 if total_dirty_rect.intersects(&dirty_test.prim_rect) {
3975 for y in dirty_test.tile_rect.min.y .. dirty_test.tile_rect.max.y {
3976 for x in dirty_test.tile_rect.min.x .. dirty_test.tile_rect.max.x {
3977 let key = TileOffset::new(x, y);
3978 let tile = sub_slice.tiles.get_mut(&key).expect("bug: no tile");
3979 tile.invalidate(
3980 Some(dirty_test.prim_rect),
3981 InvalidationReason::SurfaceContentChanged,
3982 );
3983 }
3984 }
3985 }
3986 }
3987 }
3988
3989 let mut ctx = TilePostUpdateContext {
3990 local_clip_rect: self.local_clip_rect,
3991 backdrop: None,
3992 current_tile_size: self.current_tile_size,
3993 z_id: ZBufferId::invalid(),
3994 underlays: &self.underlays,
3995 };
3996
3997 let mut state = TilePostUpdateState {
3998 resource_cache,
3999 composite_state,
4000 };
4001
4002 for (i, sub_slice) in self.sub_slices.iter_mut().enumerate().rev() {
4003 if i == 0 {
4005 ctx.backdrop = Some(self.backdrop);
4006 }
4007
4008 for compositor_surface in sub_slice.compositor_surfaces.iter_mut().rev() {
4009 compositor_surface.descriptor.z_id = state.composite_state.z_generator.next();
4010 }
4011
4012 ctx.z_id = state.composite_state.z_generator.next();
4013
4014 for tile in sub_slice.tiles.values_mut() {
4015 tile.post_update(&ctx, &mut state, frame_context);
4016 }
4017 }
4018
4019 for underlay in self.underlays.iter_mut().rev() {
4021 underlay.z_id = state.composite_state.z_generator.next();
4022 }
4023
4024 for underlay in &self.underlays {
4031 if let Some(world_surface_rect) = underlay.get_occluder_rect(
4032 &self.local_clip_rect,
4033 &map_pic_to_world,
4034 ) {
4035 composite_state.register_occluder(
4036 underlay.z_id,
4037 world_surface_rect,
4038 self.compositor_clip,
4039 );
4040 }
4041 }
4042
4043 for sub_slice in &self.sub_slices {
4044 for compositor_surface in &sub_slice.compositor_surfaces {
4045 if compositor_surface.is_opaque {
4046 if let Some(world_surface_rect) = compositor_surface.descriptor.get_occluder_rect(
4047 &self.local_clip_rect,
4048 &map_pic_to_world,
4049 ) {
4050 composite_state.register_occluder(
4051 compositor_surface.descriptor.z_id,
4052 world_surface_rect,
4053 self.compositor_clip,
4054 );
4055 }
4056 }
4057 }
4058 }
4059
4060 if !self.backdrop.opaque_rect.is_empty() {
4063 let z_id_backdrop = composite_state.z_generator.next();
4064
4065 let backdrop_rect = self.backdrop.opaque_rect
4066 .intersection(&self.local_rect)
4067 .and_then(|r| {
4068 r.intersection(&self.local_clip_rect)
4069 });
4070
4071 if let Some(backdrop_rect) = backdrop_rect {
4072 let world_backdrop_rect = map_pic_to_world
4073 .map(&backdrop_rect)
4074 .expect("bug: unable to map backdrop to world space");
4075
4076 composite_state.register_occluder(
4079 z_id_backdrop,
4080 world_backdrop_rect,
4081 self.compositor_clip,
4082 );
4083 }
4084 }
4085 }
4086}
4087
4088pub struct PictureScratchBuffer {
4089 surface_stack: Vec<SurfaceIndex>,
4090}
4091
4092impl Default for PictureScratchBuffer {
4093 fn default() -> Self {
4094 PictureScratchBuffer {
4095 surface_stack: Vec::new(),
4096 }
4097 }
4098}
4099
4100impl PictureScratchBuffer {
4101 pub fn begin_frame(&mut self) {
4102 self.surface_stack.clear();
4103 }
4104
4105 pub fn recycle(&mut self, recycler: &mut Recycler) {
4106 recycler.recycle_vec(&mut self.surface_stack);
4107 }
4108}
4109
4110#[derive(Debug, Copy, Clone, PartialEq)]
4111#[cfg_attr(feature = "capture", derive(Serialize))]
4112#[cfg_attr(feature = "replay", derive(Deserialize))]
4113pub struct SurfaceIndex(pub usize);
4114
4115pub struct SurfaceInfo {
4122 pub unclipped_local_rect: PictureRect,
4126 pub clipped_local_rect: PictureRect,
4129 pub clipping_rect: PictureRect,
4132 pub culling_rect: VisRect,
4134 pub map_local_to_picture: SpaceMapper<LayoutPixel, PicturePixel>,
4137 pub surface_spatial_node_index: SpatialNodeIndex,
4139 pub raster_spatial_node_index: SpatialNodeIndex,
4141 pub visibility_spatial_node_index: SpatialNodeIndex,
4144 pub device_pixel_scale: DevicePixelScale,
4146 pub world_scale_factors: (f32, f32),
4148 pub local_scale: (f32, f32),
4150 pub is_opaque: bool,
4152 pub allow_snapping: bool,
4154 pub force_scissor_rect: bool,
4156}
4157
4158impl SurfaceInfo {
4159 pub fn new(
4160 surface_spatial_node_index: SpatialNodeIndex,
4161 raster_spatial_node_index: SpatialNodeIndex,
4162 world_rect: WorldRect,
4163 spatial_tree: &SpatialTree,
4164 device_pixel_scale: DevicePixelScale,
4165 world_scale_factors: (f32, f32),
4166 local_scale: (f32, f32),
4167 allow_snapping: bool,
4168 force_scissor_rect: bool,
4169 ) -> Self {
4170 let map_surface_to_world = SpaceMapper::new_with_target(
4171 spatial_tree.root_reference_frame_index(),
4172 surface_spatial_node_index,
4173 world_rect,
4174 spatial_tree,
4175 );
4176
4177 let pic_bounds = map_surface_to_world
4178 .unmap(&map_surface_to_world.bounds)
4179 .unwrap_or_else(PictureRect::max_rect);
4180
4181 let map_local_to_picture = SpaceMapper::new(
4182 surface_spatial_node_index,
4183 pic_bounds,
4184 );
4185
4186 let visibility_spatial_node_index = spatial_tree.root_reference_frame_index();
4188
4189 SurfaceInfo {
4190 unclipped_local_rect: PictureRect::zero(),
4191 clipped_local_rect: PictureRect::zero(),
4192 is_opaque: false,
4193 clipping_rect: PictureRect::zero(),
4194 map_local_to_picture,
4195 raster_spatial_node_index,
4196 surface_spatial_node_index,
4197 visibility_spatial_node_index,
4198 device_pixel_scale,
4199 world_scale_factors,
4200 local_scale,
4201 allow_snapping,
4202 force_scissor_rect,
4203 culling_rect: world_rect.cast_unit(),
4206 }
4207 }
4208
4209 pub fn clamp_blur_radius(
4211 &self,
4212 x_blur_radius: f32,
4213 y_blur_radius: f32,
4214 ) -> (f32, f32) {
4215 let sx_blur_radius = x_blur_radius * self.local_scale.0;
4220 let sy_blur_radius = y_blur_radius * self.local_scale.1;
4221
4222 let largest_scaled_blur_radius = f32::max(
4223 sx_blur_radius * self.world_scale_factors.0,
4224 sy_blur_radius * self.world_scale_factors.1,
4225 );
4226
4227 if largest_scaled_blur_radius > MAX_BLUR_RADIUS {
4228 let sf = MAX_BLUR_RADIUS / largest_scaled_blur_radius;
4229 (x_blur_radius * sf, y_blur_radius * sf)
4230 } else {
4231 (x_blur_radius, y_blur_radius)
4233 }
4234 }
4235
4236 pub fn update_culling_rect(
4237 &mut self,
4238 parent_culling_rect: VisRect,
4239 composite_mode: &PictureCompositeMode,
4240 frame_context: &FrameVisibilityContext,
4241 ) {
4242 self.culling_rect = parent_culling_rect;
4245
4246 if let PictureCompositeMode::Filter(Filter::Blur { width, height, should_inflate, .. }) = composite_mode {
4247 if *should_inflate {
4248 let map_surface_to_vis = SpaceMapper::new_with_target(
4250 frame_context.root_spatial_node_index,
4252 self.surface_spatial_node_index,
4253 parent_culling_rect,
4254 frame_context.spatial_tree,
4255 );
4256
4257 if let Some(local_parent_culling_rect) = map_surface_to_vis.unmap(&parent_culling_rect) {
4260 let (width_factor, height_factor) = self.clamp_blur_radius(*width, *height);
4261
4262 let expanded_rect: PictureBox2D = local_parent_culling_rect.inflate(
4264 width_factor.ceil() * BLUR_SAMPLE_SCALE,
4265 height_factor.ceil() * BLUR_SAMPLE_SCALE,
4266 );
4267
4268 if let Some(rect) = map_surface_to_vis.map(&expanded_rect) {
4270 self.culling_rect = rect;
4271 }
4272 }
4273 }
4274 }
4275 }
4276
4277 pub fn map_to_device_rect(
4278 &self,
4279 picture_rect: &PictureRect,
4280 spatial_tree: &SpatialTree,
4281 ) -> DeviceRect {
4282 let raster_rect = if self.raster_spatial_node_index != self.surface_spatial_node_index {
4283 assert_eq!(self.device_pixel_scale.0, 1.0);
4287 assert_eq!(self.raster_spatial_node_index, spatial_tree.root_reference_frame_index());
4288
4289 let pic_to_raster = SpaceMapper::new_with_target(
4290 self.raster_spatial_node_index,
4291 self.surface_spatial_node_index,
4292 WorldRect::max_rect(),
4293 spatial_tree,
4294 );
4295
4296 pic_to_raster.map(&picture_rect).unwrap()
4297 } else {
4298 picture_rect.cast_unit()
4299 };
4300
4301 raster_rect * self.device_pixel_scale
4302 }
4303
4304 pub fn get_surface_rect(
4307 &self,
4308 local_rect: &PictureRect,
4309 spatial_tree: &SpatialTree,
4310 ) -> Option<DeviceIntRect> {
4311 let local_rect = match local_rect.intersection(&self.clipping_rect) {
4312 Some(rect) => rect,
4313 None => return None,
4314 };
4315
4316 let raster_rect = if self.raster_spatial_node_index != self.surface_spatial_node_index {
4317 assert_eq!(self.device_pixel_scale.0, 1.0);
4318
4319 let local_to_world = SpaceMapper::new_with_target(
4320 spatial_tree.root_reference_frame_index(),
4321 self.surface_spatial_node_index,
4322 WorldRect::max_rect(),
4323 spatial_tree,
4324 );
4325
4326 local_to_world.map(&local_rect).unwrap()
4327 } else {
4328 assert!(self.device_pixel_scale.0 > 0.0);
4330
4331 local_rect.cast_unit()
4332 };
4333
4334 let surface_rect = (raster_rect * self.device_pixel_scale).round_out().to_i32();
4335 if surface_rect.is_empty() {
4336 return None;
4340 }
4341
4342 Some(surface_rect)
4343 }
4344}
4345
4346#[derive(Debug)]
4349struct SurfaceAllocInfo {
4350 task_size: DeviceIntSize,
4351 needs_scissor_rect: bool,
4352 clipped: DeviceRect,
4353 unclipped: DeviceRect,
4354 source: DeviceRect,
4357 clipped_notsnapped: DeviceRect,
4359 clipped_local: PictureRect,
4360 uv_rect_kind: UvRectKind,
4361}
4362
4363#[derive(Debug)]
4364#[cfg_attr(feature = "capture", derive(Serialize))]
4365pub struct RasterConfig {
4366 pub composite_mode: PictureCompositeMode,
4370 pub surface_index: SurfaceIndex,
4373}
4374
4375bitflags! {
4376 #[cfg_attr(feature = "capture", derive(Serialize))]
4378 #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
4379 pub struct BlitReason: u32 {
4380 const BLEND_MODE = 1 << 0;
4382 const CLIP = 1 << 1;
4384 const PRESERVE3D = 1 << 2;
4386 const FORCED_ISOLATION = 1 << 3;
4388 const SNAPSHOT = 1 << 4;
4390 }
4391}
4392
4393#[allow(dead_code)]
4396#[derive(Debug, Clone)]
4397#[cfg_attr(feature = "capture", derive(Serialize))]
4398pub enum PictureCompositeMode {
4399 MixBlend(MixBlendMode),
4401 Filter(Filter),
4403 ComponentTransferFilter(FilterDataHandle),
4405 Blit(BlitReason),
4408 TileCache {
4410 slice_id: SliceId,
4411 },
4412 SvgFilter(Vec<FilterPrimitive>, Vec<SFilterData>),
4414 SVGFEGraph(Vec<(FilterGraphNode, FilterGraphOp)>),
4416 IntermediateSurface,
4418}
4419
4420impl PictureCompositeMode {
4421 pub fn get_rect(
4422 &self,
4423 surface: &SurfaceInfo,
4424 sub_rect: Option<LayoutRect>,
4425 ) -> LayoutRect {
4426 let surface_rect = match sub_rect {
4427 Some(sub_rect) => sub_rect,
4428 None => surface.clipped_local_rect.cast_unit(),
4429 };
4430
4431 match self {
4432 PictureCompositeMode::Filter(Filter::Blur { width, height, should_inflate, .. }) => {
4433 if *should_inflate {
4434 let (width_factor, height_factor) = surface.clamp_blur_radius(*width, *height);
4435
4436 surface_rect.inflate(
4437 width_factor.ceil() * BLUR_SAMPLE_SCALE,
4438 height_factor.ceil() * BLUR_SAMPLE_SCALE,
4439 )
4440 } else {
4441 surface_rect
4442 }
4443 }
4444 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
4445 let mut max_blur_radius = 0.0;
4446 for shadow in shadows {
4447 max_blur_radius = f32::max(max_blur_radius, shadow.blur_radius);
4448 }
4449
4450 let (max_blur_radius_x, max_blur_radius_y) = surface.clamp_blur_radius(
4451 max_blur_radius,
4452 max_blur_radius,
4453 );
4454 let blur_inflation_x = max_blur_radius_x * BLUR_SAMPLE_SCALE;
4455 let blur_inflation_y = max_blur_radius_y * BLUR_SAMPLE_SCALE;
4456
4457 surface_rect.inflate(blur_inflation_x, blur_inflation_y)
4458 }
4459 PictureCompositeMode::SvgFilter(primitives, _) => {
4460 let mut result_rect = surface_rect;
4461 let mut output_rects = Vec::with_capacity(primitives.len());
4462
4463 for (cur_index, primitive) in primitives.iter().enumerate() {
4464 let output_rect = match primitive.kind {
4465 FilterPrimitiveKind::Blur(ref primitive) => {
4466 let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4467 let width_factor = primitive.width.round() * BLUR_SAMPLE_SCALE;
4468 let height_factor = primitive.height.round() * BLUR_SAMPLE_SCALE;
4469 input.inflate(width_factor, height_factor)
4470 }
4471 FilterPrimitiveKind::DropShadow(ref primitive) => {
4472 let inflation_factor = primitive.shadow.blur_radius.ceil() * BLUR_SAMPLE_SCALE;
4473 let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4474 let shadow_rect = input.inflate(inflation_factor, inflation_factor);
4475 input.union(&shadow_rect.translate(primitive.shadow.offset * Scale::new(1.0)))
4476 }
4477 FilterPrimitiveKind::Blend(ref primitive) => {
4478 primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect)
4479 .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect))
4480 }
4481 FilterPrimitiveKind::Composite(ref primitive) => {
4482 primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect)
4483 .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect))
4484 }
4485 FilterPrimitiveKind::Identity(ref primitive) =>
4486 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4487 FilterPrimitiveKind::Opacity(ref primitive) =>
4488 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4489 FilterPrimitiveKind::ColorMatrix(ref primitive) =>
4490 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4491 FilterPrimitiveKind::ComponentTransfer(ref primitive) =>
4492 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4493 FilterPrimitiveKind::Offset(ref primitive) => {
4494 let input_rect = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4495 input_rect.translate(primitive.offset * Scale::new(1.0))
4496 },
4497
4498 FilterPrimitiveKind::Flood(..) => surface_rect,
4499 };
4500 output_rects.push(output_rect);
4501 result_rect = result_rect.union(&output_rect);
4502 }
4503 result_rect
4504 }
4505 PictureCompositeMode::SVGFEGraph(ref filters) => {
4506 self.get_coverage_target_svgfe(filters, surface_rect.cast_unit())
4510 }
4511 _ => {
4512 surface_rect
4513 }
4514 }
4515 }
4516
4517 pub fn get_coverage(
4518 &self,
4519 surface: &SurfaceInfo,
4520 sub_rect: Option<LayoutRect>,
4521 ) -> LayoutRect {
4522 let surface_rect = match sub_rect {
4523 Some(sub_rect) => sub_rect,
4524 None => surface.clipped_local_rect.cast_unit(),
4525 };
4526
4527 match self {
4528 PictureCompositeMode::Filter(Filter::Blur { width, height, should_inflate, .. }) => {
4529 if *should_inflate {
4530 let (width_factor, height_factor) = surface.clamp_blur_radius(*width, *height);
4531
4532 surface_rect.inflate(
4533 width_factor.ceil() * BLUR_SAMPLE_SCALE,
4534 height_factor.ceil() * BLUR_SAMPLE_SCALE,
4535 )
4536 } else {
4537 surface_rect
4538 }
4539 }
4540 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
4541 let mut rect = surface_rect;
4542
4543 for shadow in shadows {
4544 let (blur_radius_x, blur_radius_y) = surface.clamp_blur_radius(
4545 shadow.blur_radius,
4546 shadow.blur_radius,
4547 );
4548 let blur_inflation_x = blur_radius_x * BLUR_SAMPLE_SCALE;
4549 let blur_inflation_y = blur_radius_y * BLUR_SAMPLE_SCALE;
4550
4551 let shadow_rect = surface_rect
4552 .translate(shadow.offset)
4553 .inflate(blur_inflation_x, blur_inflation_y);
4554 rect = rect.union(&shadow_rect);
4555 }
4556
4557 rect
4558 }
4559 PictureCompositeMode::SvgFilter(primitives, _) => {
4560 let mut result_rect = surface_rect;
4561 let mut output_rects = Vec::with_capacity(primitives.len());
4562
4563 for (cur_index, primitive) in primitives.iter().enumerate() {
4564 let output_rect = match primitive.kind {
4565 FilterPrimitiveKind::Blur(ref primitive) => {
4566 let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4567 let width_factor = primitive.width.round() * BLUR_SAMPLE_SCALE;
4568 let height_factor = primitive.height.round() * BLUR_SAMPLE_SCALE;
4569
4570 input.inflate(width_factor, height_factor)
4571 }
4572 FilterPrimitiveKind::DropShadow(ref primitive) => {
4573 let inflation_factor = primitive.shadow.blur_radius.ceil() * BLUR_SAMPLE_SCALE;
4574 let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4575 let shadow_rect = input.inflate(inflation_factor, inflation_factor);
4576 input.union(&shadow_rect.translate(primitive.shadow.offset * Scale::new(1.0)))
4577 }
4578 FilterPrimitiveKind::Blend(ref primitive) => {
4579 primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect)
4580 .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect))
4581 }
4582 FilterPrimitiveKind::Composite(ref primitive) => {
4583 primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect)
4584 .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect))
4585 }
4586 FilterPrimitiveKind::Identity(ref primitive) =>
4587 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4588 FilterPrimitiveKind::Opacity(ref primitive) =>
4589 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4590 FilterPrimitiveKind::ColorMatrix(ref primitive) =>
4591 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4592 FilterPrimitiveKind::ComponentTransfer(ref primitive) =>
4593 primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect),
4594 FilterPrimitiveKind::Offset(ref primitive) => {
4595 let input_rect = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(surface_rect);
4596 input_rect.translate(primitive.offset * Scale::new(1.0))
4597 },
4598
4599 FilterPrimitiveKind::Flood(..) => surface_rect,
4600 };
4601 output_rects.push(output_rect);
4602 result_rect = result_rect.union(&output_rect);
4603 }
4604 result_rect
4605 }
4606 PictureCompositeMode::SVGFEGraph(ref filters) => {
4607 let target_subregion = self.get_coverage_source_svgfe(filters, surface_rect.cast());
4610 let source_subregion = self.get_coverage_target_svgfe(filters, surface_rect.cast());
4611 target_subregion.union(&source_subregion)
4612 }
4613 _ => {
4614 surface_rect
4615 }
4616 }
4617 }
4618
4619 pub fn kind(&self) -> &'static str {
4622 match *self {
4623 PictureCompositeMode::Blit(..) => "Blit",
4624 PictureCompositeMode::ComponentTransferFilter(..) => "ComponentTransferFilter",
4625 PictureCompositeMode::IntermediateSurface => "IntermediateSurface",
4626 PictureCompositeMode::MixBlend(..) => "MixBlend",
4627 PictureCompositeMode::SVGFEGraph(..) => "SVGFEGraph",
4628 PictureCompositeMode::SvgFilter(..) => "SvgFilter",
4629 PictureCompositeMode::TileCache{..} => "TileCache",
4630 PictureCompositeMode::Filter(Filter::Blur{..}) => "Filter::Blur",
4631 PictureCompositeMode::Filter(Filter::Brightness(..)) => "Filter::Brightness",
4632 PictureCompositeMode::Filter(Filter::ColorMatrix(..)) => "Filter::ColorMatrix",
4633 PictureCompositeMode::Filter(Filter::ComponentTransfer) => "Filter::ComponentTransfer",
4634 PictureCompositeMode::Filter(Filter::Contrast(..)) => "Filter::Contrast",
4635 PictureCompositeMode::Filter(Filter::DropShadows(..)) => "Filter::DropShadows",
4636 PictureCompositeMode::Filter(Filter::Flood(..)) => "Filter::Flood",
4637 PictureCompositeMode::Filter(Filter::Grayscale(..)) => "Filter::Grayscale",
4638 PictureCompositeMode::Filter(Filter::HueRotate(..)) => "Filter::HueRotate",
4639 PictureCompositeMode::Filter(Filter::Identity) => "Filter::Identity",
4640 PictureCompositeMode::Filter(Filter::Invert(..)) => "Filter::Invert",
4641 PictureCompositeMode::Filter(Filter::LinearToSrgb) => "Filter::LinearToSrgb",
4642 PictureCompositeMode::Filter(Filter::Opacity(..)) => "Filter::Opacity",
4643 PictureCompositeMode::Filter(Filter::Saturate(..)) => "Filter::Saturate",
4644 PictureCompositeMode::Filter(Filter::Sepia(..)) => "Filter::Sepia",
4645 PictureCompositeMode::Filter(Filter::SrgbToLinear) => "Filter::SrgbToLinear",
4646 PictureCompositeMode::Filter(Filter::SVGGraphNode(..)) => "Filter::SVGGraphNode",
4647 }
4648 }
4649
4650 pub fn get_coverage_target_svgfe(
4663 &self,
4664 filters: &[(FilterGraphNode, FilterGraphOp)],
4665 surface_rect: LayoutRect,
4666 ) -> LayoutRect {
4667
4668 const BUFFER_LIMIT: usize = SVGFE_GRAPH_MAX;
4671
4672 let mut subregion_by_buffer_id: [LayoutRect; BUFFER_LIMIT] = [LayoutRect::zero(); BUFFER_LIMIT];
4675 for (id, (node, op)) in filters.iter().enumerate() {
4676 let full_subregion = node.subregion;
4677 let mut used_subregion = LayoutRect::zero();
4678 for input in &node.inputs {
4679 match input.buffer_id {
4680 FilterOpGraphPictureBufferId::BufferId(id) => {
4681 assert!((id as usize) < BUFFER_LIMIT, "BUFFER_LIMIT must be the same in frame building and scene building");
4682 let input_subregion = subregion_by_buffer_id[id as usize];
4684 let input_subregion =
4688 LayoutRect::new(
4689 LayoutPoint::new(
4690 input_subregion.min.x + input.target_padding.min.x,
4691 input_subregion.min.y + input.target_padding.min.y,
4692 ),
4693 LayoutPoint::new(
4694 input_subregion.max.x + input.target_padding.max.x,
4695 input_subregion.max.y + input.target_padding.max.y,
4696 ),
4697 );
4698 used_subregion = used_subregion
4699 .union(&input_subregion);
4700 }
4701 FilterOpGraphPictureBufferId::None => {
4702 panic!("Unsupported BufferId type");
4703 }
4704 }
4705 }
4706 used_subregion = used_subregion
4708 .intersection(&full_subregion)
4709 .unwrap_or(LayoutRect::zero());
4710 match op {
4711 FilterGraphOp::SVGFEBlendColor => {}
4712 FilterGraphOp::SVGFEBlendColorBurn => {}
4713 FilterGraphOp::SVGFEBlendColorDodge => {}
4714 FilterGraphOp::SVGFEBlendDarken => {}
4715 FilterGraphOp::SVGFEBlendDifference => {}
4716 FilterGraphOp::SVGFEBlendExclusion => {}
4717 FilterGraphOp::SVGFEBlendHardLight => {}
4718 FilterGraphOp::SVGFEBlendHue => {}
4719 FilterGraphOp::SVGFEBlendLighten => {}
4720 FilterGraphOp::SVGFEBlendLuminosity => {}
4721 FilterGraphOp::SVGFEBlendMultiply => {}
4722 FilterGraphOp::SVGFEBlendNormal => {}
4723 FilterGraphOp::SVGFEBlendOverlay => {}
4724 FilterGraphOp::SVGFEBlendSaturation => {}
4725 FilterGraphOp::SVGFEBlendScreen => {}
4726 FilterGraphOp::SVGFEBlendSoftLight => {}
4727 FilterGraphOp::SVGFEColorMatrix { values } => {
4728 if values[19] > 0.0 {
4729 used_subregion = full_subregion;
4732 add_text_marker(
4733 "SVGFEColorMatrix",
4734 "SVGFEColorMatrix with non-zero alpha offset, using full subregion",
4735 Duration::from_millis(1));
4736 }
4737 }
4738 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
4739 FilterGraphOp::SVGFEComponentTransferInterned{handle: _, creates_pixels} => {
4740 if *creates_pixels {
4744 used_subregion = full_subregion;
4745 add_text_marker(
4746 "SVGFEComponentTransfer",
4747 "SVGFEComponentTransfer with non-zero minimum alpha, using full subregion",
4748 Duration::from_millis(1));
4749 }
4750 }
4751 FilterGraphOp::SVGFECompositeArithmetic { k1, k2, k3, k4 } => {
4752 if *k1 <= 0.0 &&
4764 *k2 <= 0.0 &&
4765 *k3 <= 0.0 {
4766 used_subregion = LayoutRect::zero();
4767 }
4768 if *k4 > 0.0 {
4771 used_subregion = full_subregion;
4772 add_text_marker(
4773 "SVGFECompositeArithmetic",
4774 "SVGFECompositeArithmetic with non-zero offset, using full subregion",
4775 Duration::from_millis(1));
4776 }
4777 }
4778 FilterGraphOp::SVGFECompositeATop => {}
4779 FilterGraphOp::SVGFECompositeIn => {}
4780 FilterGraphOp::SVGFECompositeLighter => {}
4781 FilterGraphOp::SVGFECompositeOut => {}
4782 FilterGraphOp::SVGFECompositeOver => {}
4783 FilterGraphOp::SVGFECompositeXOR => {}
4784 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{..} => {}
4785 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{..} => {}
4786 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{..} => {}
4787 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {}
4788 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {}
4789 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {}
4790 FilterGraphOp::SVGFEDisplacementMap{..} => {}
4791 FilterGraphOp::SVGFEDropShadow{..} => {}
4792 FilterGraphOp::SVGFEFlood { color } => {
4793 if color.a > 0.0 {
4796 used_subregion = full_subregion;
4797 }
4798 }
4799 FilterGraphOp::SVGFEGaussianBlur{..} => {}
4800 FilterGraphOp::SVGFEIdentity => {}
4801 FilterGraphOp::SVGFEImage { sampling_filter: _sampling_filter, matrix: _matrix } => {
4802 used_subregion = full_subregion;
4804 }
4805 FilterGraphOp::SVGFEMorphologyDilate{..} => {}
4806 FilterGraphOp::SVGFEMorphologyErode{..} => {}
4807 FilterGraphOp::SVGFEOpacity { valuebinding: _valuebinding, value } => {
4808 if *value <= 0.0 {
4810 used_subregion = LayoutRect::zero();
4811 }
4812 }
4813 FilterGraphOp::SVGFESourceAlpha |
4814 FilterGraphOp::SVGFESourceGraphic => {
4815 used_subregion = surface_rect;
4816 }
4817 FilterGraphOp::SVGFESpecularLightingDistant{..} => {}
4818 FilterGraphOp::SVGFESpecularLightingPoint{..} => {}
4819 FilterGraphOp::SVGFESpecularLightingSpot{..} => {}
4820 FilterGraphOp::SVGFETile => {
4821 used_subregion = full_subregion;
4824 }
4825 FilterGraphOp::SVGFEToAlpha => {}
4826 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} |
4827 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} |
4828 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} |
4829 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {
4830 used_subregion = full_subregion;
4833 }
4834 }
4835 assert!((id as usize) < BUFFER_LIMIT, "BUFFER_LIMIT must be the same in frame building and scene building");
4838 subregion_by_buffer_id[id] = used_subregion;
4839 }
4840 subregion_by_buffer_id[filters.len() - 1]
4841 }
4842
4843 pub fn get_coverage_source_svgfe(
4856 &self,
4857 filters: &[(FilterGraphNode, FilterGraphOp)],
4858 surface_rect: LayoutRect,
4859 ) -> LayoutRect {
4860
4861 const BUFFER_LIMIT: usize = SVGFE_GRAPH_MAX;
4864
4865 let mut source_subregion = LayoutRect::zero();
4872 let mut subregion_by_buffer_id: [LayoutRect; BUFFER_LIMIT] =
4873 [LayoutRect::zero(); BUFFER_LIMIT];
4874 let final_buffer_id = filters.len() - 1;
4875 assert!(final_buffer_id < BUFFER_LIMIT, "BUFFER_LIMIT must be the same in frame building and scene building");
4876 subregion_by_buffer_id[final_buffer_id] = surface_rect;
4877 for (node_buffer_id, (node, op)) in filters.iter().enumerate().rev() {
4878 assert!(node_buffer_id < BUFFER_LIMIT, "BUFFER_LIMIT must be the same in frame building and scene building");
4882 let full_subregion = node.subregion;
4883 let mut used_subregion =
4884 subregion_by_buffer_id[node_buffer_id];
4885 used_subregion = used_subregion
4888 .intersection(&full_subregion)
4889 .unwrap_or(LayoutRect::zero());
4890 if !used_subregion.is_empty() {
4891 for input in &node.inputs {
4892 let input_subregion = LayoutRect::new(
4893 LayoutPoint::new(
4894 used_subregion.min.x + input.source_padding.min.x,
4895 used_subregion.min.y + input.source_padding.min.y,
4896 ),
4897 LayoutPoint::new(
4898 used_subregion.max.x + input.source_padding.max.x,
4899 used_subregion.max.y + input.source_padding.max.y,
4900 ),
4901 );
4902 match input.buffer_id {
4903 FilterOpGraphPictureBufferId::BufferId(id) => {
4904 subregion_by_buffer_id[id as usize] =
4908 subregion_by_buffer_id[id as usize]
4909 .union(&input_subregion);
4910 }
4911 FilterOpGraphPictureBufferId::None => {}
4912 }
4913 }
4914 }
4915 match op {
4919 FilterGraphOp::SVGFESourceAlpha |
4920 FilterGraphOp::SVGFESourceGraphic => {
4921 source_subregion = source_subregion.union(&used_subregion);
4922 }
4923 _ => {}
4924 }
4925 }
4926
4927 source_subregion
4930 }
4931}
4932
4933#[derive(Clone, Debug)]
4935#[cfg_attr(feature = "capture", derive(Serialize))]
4936pub enum Picture3DContext<C> {
4937 Out,
4939 In {
4941 root_data: Option<Vec<C>>,
4943 ancestor_index: SpatialNodeIndex,
4949 plane_splitter_index: PlaneSplitterIndex,
4951 },
4952}
4953
4954#[derive(Clone, Debug)]
4957#[cfg_attr(feature = "capture", derive(Serialize))]
4958pub struct OrderedPictureChild {
4959 pub anchor: PlaneSplitAnchor,
4960 pub gpu_address: GpuCacheAddress,
4961}
4962
4963bitflags! {
4964 #[cfg_attr(feature = "capture", derive(Serialize))]
4966 #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
4967 pub struct ClusterFlags: u32 {
4968 const IS_BACKFACE_VISIBLE = 1;
4970 const IS_VISIBLE = 2;
4974 }
4975}
4976
4977#[cfg_attr(feature = "capture", derive(Serialize))]
4980pub struct PrimitiveCluster {
4981 pub spatial_node_index: SpatialNodeIndex,
4983 bounding_rect: LayoutRect,
4988 pub opaque_rect: LayoutRect,
4992 pub prim_range: Range<usize>,
4994 pub flags: ClusterFlags,
4996}
4997
4998impl PrimitiveCluster {
4999 fn new(
5001 spatial_node_index: SpatialNodeIndex,
5002 flags: ClusterFlags,
5003 first_instance_index: usize,
5004 ) -> Self {
5005 PrimitiveCluster {
5006 bounding_rect: LayoutRect::zero(),
5007 opaque_rect: LayoutRect::zero(),
5008 spatial_node_index,
5009 flags,
5010 prim_range: first_instance_index..first_instance_index
5011 }
5012 }
5013
5014 pub fn is_compatible(
5016 &self,
5017 spatial_node_index: SpatialNodeIndex,
5018 flags: ClusterFlags,
5019 instance_index: usize,
5020 ) -> bool {
5021 self.flags == flags &&
5022 self.spatial_node_index == spatial_node_index &&
5023 instance_index == self.prim_range.end
5024 }
5025
5026 pub fn prim_range(&self) -> Range<usize> {
5027 self.prim_range.clone()
5028 }
5029
5030 fn add_instance(
5032 &mut self,
5033 culling_rect: &LayoutRect,
5034 instance_index: usize,
5035 ) {
5036 debug_assert_eq!(instance_index, self.prim_range.end);
5037 self.bounding_rect = self.bounding_rect.union(culling_rect);
5038 self.prim_range.end += 1;
5039 }
5040}
5041
5042#[cfg_attr(feature = "capture", derive(Serialize))]
5047pub struct PrimitiveList {
5048 pub clusters: Vec<PrimitiveCluster>,
5050 pub child_pictures: Vec<PictureIndex>,
5051 pub image_surface_count: usize,
5054 pub yuv_image_surface_count: usize,
5057 pub needs_scissor_rect: bool,
5058}
5059
5060impl PrimitiveList {
5061 pub fn empty() -> Self {
5066 PrimitiveList {
5067 clusters: Vec::new(),
5068 child_pictures: Vec::new(),
5069 image_surface_count: 0,
5070 yuv_image_surface_count: 0,
5071 needs_scissor_rect: false,
5072 }
5073 }
5074
5075 pub fn merge(&mut self, other: PrimitiveList) {
5076 self.clusters.extend(other.clusters);
5077 self.child_pictures.extend(other.child_pictures);
5078 self.image_surface_count += other.image_surface_count;
5079 self.yuv_image_surface_count += other.yuv_image_surface_count;
5080 self.needs_scissor_rect |= other.needs_scissor_rect;
5081 }
5082
5083 pub fn add_prim(
5085 &mut self,
5086 prim_instance: PrimitiveInstance,
5087 prim_rect: LayoutRect,
5088 spatial_node_index: SpatialNodeIndex,
5089 prim_flags: PrimitiveFlags,
5090 prim_instances: &mut Vec<PrimitiveInstance>,
5091 clip_tree_builder: &ClipTreeBuilder,
5092 ) {
5093 let mut flags = ClusterFlags::empty();
5094
5095 match prim_instance.kind {
5098 PrimitiveInstanceKind::Picture { pic_index, .. } => {
5099 self.child_pictures.push(pic_index);
5100 }
5101 PrimitiveInstanceKind::TextRun { .. } => {
5102 self.needs_scissor_rect = true;
5103 }
5104 PrimitiveInstanceKind::YuvImage { .. } => {
5105 if prim_flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
5112 self.yuv_image_surface_count += 1;
5113 }
5114 }
5115 PrimitiveInstanceKind::Image { .. } => {
5116 if prim_flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
5122 self.image_surface_count += 1;
5123 }
5124 }
5125 _ => {}
5126 }
5127
5128 if prim_flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE) {
5129 flags.insert(ClusterFlags::IS_BACKFACE_VISIBLE);
5130 }
5131
5132 let clip_leaf = clip_tree_builder.get_leaf(prim_instance.clip_leaf_id);
5133 let culling_rect = clip_leaf.local_clip_rect
5134 .intersection(&prim_rect)
5135 .unwrap_or_else(LayoutRect::zero);
5136
5137 let instance_index = prim_instances.len();
5138 prim_instances.push(prim_instance);
5139
5140 if let Some(cluster) = self.clusters.last_mut() {
5141 if cluster.is_compatible(spatial_node_index, flags, instance_index) {
5142 cluster.add_instance(&culling_rect, instance_index);
5143 return;
5144 }
5145 }
5146
5147 let clusters_len = self.clusters.len();
5149 if clusters_len == self.clusters.capacity() {
5150 let next_alloc = match clusters_len {
5151 1 ..= 15 => 16 - clusters_len,
5152 16 ..= 127 => 128 - clusters_len,
5153 _ => clusters_len * 2,
5154 };
5155
5156 self.clusters.reserve(next_alloc);
5157 }
5158
5159 let mut cluster = PrimitiveCluster::new(
5160 spatial_node_index,
5161 flags,
5162 instance_index,
5163 );
5164
5165 cluster.add_instance(&culling_rect, instance_index);
5166 self.clusters.push(cluster);
5167 }
5168
5169 pub fn is_empty(&self) -> bool {
5171 self.clusters.is_empty()
5172 }
5173}
5174
5175bitflags! {
5176 #[cfg_attr(feature = "capture", derive(Serialize))]
5177 #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
5179 pub struct PictureFlags : u8 {
5180 const IS_RESOLVE_TARGET = 1 << 0;
5183 const IS_SUB_GRAPH = 1 << 1;
5186 const DISABLE_SNAPPING = 1 << 2;
5188 }
5189}
5190
5191#[cfg_attr(feature = "capture", derive(Serialize))]
5192pub struct PicturePrimitive {
5193 pub prim_list: PrimitiveList,
5195
5196 pub is_backface_visible: bool,
5199
5200 pub primary_render_task_id: Option<RenderTaskId>,
5202 pub secondary_render_task_id: Option<RenderTaskId>,
5211 pub composite_mode: Option<PictureCompositeMode>,
5214
5215 pub raster_config: Option<RasterConfig>,
5216 pub context_3d: Picture3DContext<OrderedPictureChild>,
5217
5218 pub extra_gpu_data_handles: SmallVec<[GpuCacheHandle; 1]>,
5222
5223 pub spatial_node_index: SpatialNodeIndex,
5226
5227 pub prev_local_rect: LayoutRect,
5231
5232 pub segments_are_valid: bool,
5237
5238 pub is_opaque: bool,
5240
5241 pub raster_space: RasterSpace,
5243
5244 pub flags: PictureFlags,
5246
5247 pub clip_root: Option<ClipNodeId>,
5251
5252 pub snapshot: Option<SnapshotInfo>,
5255}
5256
5257impl PicturePrimitive {
5258 pub fn print<T: PrintTreePrinter>(
5259 &self,
5260 pictures: &[Self],
5261 self_index: PictureIndex,
5262 pt: &mut T,
5263 ) {
5264 pt.new_level(format!("{:?}", self_index));
5265 pt.add_item(format!("cluster_count: {:?}", self.prim_list.clusters.len()));
5266 pt.add_item(format!("spatial_node_index: {:?}", self.spatial_node_index));
5267 pt.add_item(format!("raster_config: {:?}", self.raster_config));
5268 pt.add_item(format!("composite_mode: {:?}", self.composite_mode));
5269 pt.add_item(format!("flags: {:?}", self.flags));
5270
5271 for child_pic_index in &self.prim_list.child_pictures {
5272 pictures[child_pic_index.0].print(pictures, *child_pic_index, pt);
5273 }
5274
5275 pt.end_level();
5276 }
5277
5278 fn resolve_scene_properties(&mut self, properties: &SceneProperties) {
5279 match self.composite_mode {
5280 Some(PictureCompositeMode::Filter(ref mut filter)) => {
5281 match *filter {
5282 Filter::Opacity(ref binding, ref mut value) => {
5283 *value = properties.resolve_float(binding);
5284 }
5285 _ => {}
5286 }
5287 }
5288 _ => {}
5289 }
5290 }
5291
5292 pub fn is_visible(
5293 &self,
5294 spatial_tree: &SpatialTree,
5295 ) -> bool {
5296 if let Some(PictureCompositeMode::Filter(ref filter)) = self.composite_mode {
5297 if !filter.is_visible() {
5298 return false;
5299 }
5300 }
5301
5302 if !self.is_backface_visible {
5307 if let Picture3DContext::Out = self.context_3d {
5308 match spatial_tree.get_local_visible_face(self.spatial_node_index) {
5309 VisibleFace::Front => {}
5310 VisibleFace::Back => return false,
5311 }
5312 }
5313 }
5314
5315 true
5316 }
5317
5318 pub fn new_image(
5319 composite_mode: Option<PictureCompositeMode>,
5320 context_3d: Picture3DContext<OrderedPictureChild>,
5321 prim_flags: PrimitiveFlags,
5322 prim_list: PrimitiveList,
5323 spatial_node_index: SpatialNodeIndex,
5324 raster_space: RasterSpace,
5325 flags: PictureFlags,
5326 snapshot: Option<SnapshotInfo>,
5327 ) -> Self {
5328 PicturePrimitive {
5329 prim_list,
5330 primary_render_task_id: None,
5331 secondary_render_task_id: None,
5332 composite_mode,
5333 raster_config: None,
5334 context_3d,
5335 extra_gpu_data_handles: SmallVec::new(),
5336 is_backface_visible: prim_flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE),
5337 spatial_node_index,
5338 prev_local_rect: LayoutRect::zero(),
5339 segments_are_valid: false,
5340 is_opaque: false,
5341 raster_space,
5342 flags,
5343 clip_root: None,
5344 snapshot,
5345 }
5346 }
5347
5348 pub fn take_context(
5349 &mut self,
5350 pic_index: PictureIndex,
5351 parent_surface_index: Option<SurfaceIndex>,
5352 parent_subpixel_mode: SubpixelMode,
5353 frame_state: &mut FrameBuildingState,
5354 frame_context: &FrameBuildingContext,
5355 data_stores: &mut DataStores,
5356 scratch: &mut PrimitiveScratchBuffer,
5357 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
5358 ) -> Option<(PictureContext, PictureState, PrimitiveList)> {
5359 frame_state.visited_pictures[pic_index.0] = true;
5360 self.primary_render_task_id = None;
5361 self.secondary_render_task_id = None;
5362
5363 let dbg_flags = DebugFlags::PICTURE_CACHING_DBG | DebugFlags::PICTURE_BORDERS;
5364 if frame_context.debug_flags.intersects(dbg_flags) {
5365 self.draw_debug_overlay(
5366 parent_surface_index,
5367 frame_state,
5368 frame_context,
5369 tile_caches,
5370 scratch,
5371 );
5372 }
5373
5374 if !self.is_visible(frame_context.spatial_tree) {
5375 return None;
5376 }
5377
5378 profile_scope!("take_context");
5379
5380 let surface_index = match self.raster_config {
5381 Some(ref raster_config) => raster_config.surface_index,
5382 None => parent_surface_index.expect("bug: no parent"),
5383 };
5384 let surface = &frame_state.surfaces[surface_index.0];
5385 let surface_spatial_node_index = surface.surface_spatial_node_index;
5386
5387 let map_pic_to_world = SpaceMapper::new_with_target(
5388 frame_context.root_spatial_node_index,
5389 surface_spatial_node_index,
5390 frame_context.global_screen_world_rect,
5391 frame_context.spatial_tree,
5392 );
5393
5394 let map_pic_to_vis = SpaceMapper::new_with_target(
5395 frame_context.root_spatial_node_index,
5397 surface_spatial_node_index,
5398 surface.culling_rect,
5399 frame_context.spatial_tree,
5400 );
5401
5402 let pic_bounds = map_pic_to_world
5406 .unmap(&map_pic_to_world.bounds)
5407 .unwrap_or_else(PictureRect::max_rect);
5408
5409 let map_local_to_pic = SpaceMapper::new(
5410 surface_spatial_node_index,
5411 pic_bounds,
5412 );
5413
5414 match self.raster_config {
5415 Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) => {
5416 let tile_cache = tile_caches.get_mut(&slice_id).unwrap();
5417 let mut debug_info = SliceDebugInfo::new();
5418 let mut surface_render_tasks = FastHashMap::default();
5419 let mut surface_local_dirty_rect = PictureRect::zero();
5420 let device_pixel_scale = frame_state
5421 .surfaces[surface_index.0]
5422 .device_pixel_scale;
5423 let mut at_least_one_tile_visible = false;
5424
5425 let world_clip_rect = map_pic_to_world
5428 .map(&tile_cache.local_clip_rect)
5429 .expect("bug: unable to map clip rect")
5430 .round();
5431 let device_clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round();
5432
5433 for (sub_slice_index, sub_slice) in tile_cache.sub_slices.iter_mut().enumerate() {
5434 for tile in sub_slice.tiles.values_mut() {
5435 tile.local_dirty_rect = tile.local_dirty_rect
5437 .intersection(&tile.current_descriptor.local_valid_rect)
5438 .unwrap_or_else(|| { tile.is_valid = true; PictureRect::zero() });
5439
5440 let valid_rect = frame_state.composite_state.get_surface_rect(
5441 &tile.current_descriptor.local_valid_rect,
5442 &tile.local_tile_rect,
5443 tile_cache.transform_index,
5444 ).to_i32();
5445
5446 let scissor_rect = frame_state.composite_state.get_surface_rect(
5447 &tile.local_dirty_rect,
5448 &tile.local_tile_rect,
5449 tile_cache.transform_index,
5450 ).to_i32().intersection(&valid_rect).unwrap_or_else(|| { Box2D::zero() });
5451
5452 if tile.is_visible {
5453 let world_draw_rect = world_clip_rect.intersection(&tile.world_valid_rect);
5455
5456 match world_draw_rect {
5461 Some(world_draw_rect) => {
5462 if tile_cache.spatial_node_index == frame_context.root_spatial_node_index &&
5464 frame_state.composite_state.occluders.is_tile_occluded(tile.z_id, world_draw_rect) {
5465 let surface = tile.surface.as_mut().expect("no tile surface set!");
5470
5471 if let TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { id, .. }, .. } = surface {
5472 if let Some(id) = id.take() {
5473 frame_state.resource_cache.destroy_compositor_tile(id);
5474 }
5475 }
5476
5477 tile.is_visible = false;
5478
5479 if frame_context.fb_config.testing {
5480 debug_info.tiles.insert(
5481 tile.tile_offset,
5482 TileDebugInfo::Occluded,
5483 );
5484 }
5485
5486 continue;
5487 }
5488 }
5489 None => {
5490 tile.is_visible = false;
5491 }
5492 }
5493
5494 if !tile.is_valid && (scissor_rect.is_empty() || valid_rect.is_empty()) {
5502 tile.is_visible = false;
5503 }
5504 }
5505
5506 if let Some(TileSurface::Texture { descriptor, .. }) = tile.surface.as_ref() {
5511 if let SurfaceTextureDescriptor::TextureCache { handle: Some(handle), .. } = descriptor {
5512 frame_state.resource_cache
5513 .picture_textures.request(handle, frame_state.gpu_cache);
5514 }
5515 }
5516
5517 if !tile.is_visible {
5519 if frame_context.fb_config.testing {
5520 debug_info.tiles.insert(
5521 tile.tile_offset,
5522 TileDebugInfo::Culled,
5523 );
5524 }
5525
5526 continue;
5527 }
5528
5529 at_least_one_tile_visible = true;
5530
5531 if let TileSurface::Texture { descriptor, .. } = tile.surface.as_mut().unwrap() {
5532 match descriptor {
5533 SurfaceTextureDescriptor::TextureCache { ref handle, .. } => {
5534 let exists = handle.as_ref().map_or(false,
5535 |handle| frame_state.resource_cache.picture_textures.entry_exists(handle)
5536 );
5537 if exists {
5539 frame_state.resource_cache
5548 .picture_textures
5549 .request(handle.as_ref().unwrap(), frame_state.gpu_cache);
5550 } else {
5551 tile.invalidate(None, InvalidationReason::NoTexture);
5554 }
5555 }
5556 SurfaceTextureDescriptor::Native { id, .. } => {
5557 if id.is_none() {
5558 tile.invalidate(None, InvalidationReason::NoSurface);
5560 }
5561 }
5562 }
5563 }
5564
5565 tile.local_dirty_rect = tile.local_dirty_rect
5568 .intersection(&tile.current_descriptor.local_valid_rect)
5569 .unwrap_or_else(|| { tile.is_valid = true; PictureRect::zero() });
5570
5571 surface_local_dirty_rect = surface_local_dirty_rect.union(&tile.local_dirty_rect);
5572
5573 let world_dirty_rect = map_pic_to_world.map(&tile.local_dirty_rect).expect("bug");
5575
5576 let device_rect = (tile.world_tile_rect * frame_context.global_device_pixel_scale).round();
5577 tile.device_dirty_rect = (world_dirty_rect * frame_context.global_device_pixel_scale)
5578 .round_out()
5579 .intersection(&device_rect)
5580 .unwrap_or_else(DeviceRect::zero);
5581
5582 if tile.is_valid {
5583 if frame_context.fb_config.testing {
5584 debug_info.tiles.insert(
5585 tile.tile_offset,
5586 TileDebugInfo::Valid,
5587 );
5588 }
5589 } else {
5590 tile_cache.dirty_region.add_dirty_region(
5594 tile.local_dirty_rect,
5595 frame_context.spatial_tree,
5596 );
5597
5598 if let TileSurface::Texture { ref mut descriptor } = tile.surface.as_mut().unwrap() {
5600 match descriptor {
5601 SurfaceTextureDescriptor::TextureCache { ref mut handle } => {
5602
5603 frame_state.resource_cache.picture_textures.update(
5604 tile_cache.current_tile_size,
5605 handle,
5606 frame_state.gpu_cache,
5607 &mut frame_state.resource_cache.texture_cache.next_id,
5608 &mut frame_state.resource_cache.texture_cache.pending_updates,
5609 );
5610 }
5611 SurfaceTextureDescriptor::Native { id } => {
5612 if id.is_none() {
5613 if sub_slice.native_surface.is_none() {
5617 let opaque = frame_state
5618 .resource_cache
5619 .create_compositor_surface(
5620 tile_cache.virtual_offset,
5621 tile_cache.current_tile_size,
5622 true,
5623 );
5624
5625 let alpha = frame_state
5626 .resource_cache
5627 .create_compositor_surface(
5628 tile_cache.virtual_offset,
5629 tile_cache.current_tile_size,
5630 false,
5631 );
5632
5633 sub_slice.native_surface = Some(NativeSurface {
5634 opaque,
5635 alpha,
5636 });
5637 }
5638
5639 let surface_id = if tile.is_opaque {
5641 sub_slice.native_surface.as_ref().unwrap().opaque
5642 } else {
5643 sub_slice.native_surface.as_ref().unwrap().alpha
5644 };
5645
5646 let tile_id = NativeTileId {
5647 surface_id,
5648 x: tile.tile_offset.x,
5649 y: tile.tile_offset.y,
5650 };
5651
5652 frame_state.resource_cache.create_compositor_tile(tile_id);
5653
5654 *id = Some(tile_id);
5655 }
5656 }
5657 }
5658
5659 let content_origin_f = tile.local_tile_rect.min.cast_unit() * device_pixel_scale;
5666 let content_origin = content_origin_f.round();
5667 debug_assert!((content_origin_f.x - content_origin.x).abs() < 0.15);
5672 debug_assert!((content_origin_f.y - content_origin.y).abs() < 0.15);
5673
5674 let surface = descriptor.resolve(
5675 frame_state.resource_cache,
5676 tile_cache.current_tile_size,
5677 );
5678
5679 let scissor_rect = frame_state.composite_state.get_surface_rect(
5681 &tile.local_dirty_rect,
5682 &tile.local_tile_rect,
5683 tile_cache.transform_index,
5684 ).to_i32();
5685
5686 let composite_task_size = tile_cache.current_tile_size;
5687
5688 let tile_key = TileKey {
5689 sub_slice_index: SubSliceIndex::new(sub_slice_index),
5690 tile_offset: tile.tile_offset,
5691 };
5692
5693 let mut clear_color = ColorF::TRANSPARENT;
5694
5695 if SubSliceIndex::new(sub_slice_index).is_primary() {
5696 if let Some(background_color) = tile_cache.background_color {
5697 clear_color = background_color;
5698 }
5699
5700 if let Some(color) = tile_cache.backdrop.spanning_opaque_color {
5706 clear_color = color;
5707 }
5708 }
5709
5710 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
5711
5712 let use_tile_composite = !tile.sub_graphs.is_empty();
5716
5717 if use_tile_composite {
5718 let mut local_content_rect = tile.local_dirty_rect;
5719
5720 for (sub_graph_rect, surface_stack) in &tile.sub_graphs {
5721 if let Some(dirty_sub_graph_rect) = sub_graph_rect.intersection(&tile.local_dirty_rect) {
5722 for (composite_mode, surface_index) in surface_stack {
5723 let surface = &frame_state.surfaces[surface_index.0];
5724
5725 let rect = composite_mode.get_coverage(
5726 surface,
5727 Some(dirty_sub_graph_rect.cast_unit()),
5728 ).cast_unit();
5729
5730 local_content_rect = local_content_rect.union(&rect);
5731 }
5732 }
5733 }
5734
5735 let max_content_rect = (tile.local_dirty_rect.cast_unit() * device_pixel_scale)
5739 .inflate(
5740 MAX_BLUR_RADIUS * BLUR_SAMPLE_SCALE,
5741 MAX_BLUR_RADIUS * BLUR_SAMPLE_SCALE,
5742 )
5743 .round_out()
5744 .to_i32();
5745
5746 let content_device_rect = (local_content_rect.cast_unit() * device_pixel_scale)
5747 .round_out()
5748 .to_i32();
5749
5750 let content_device_rect = content_device_rect
5751 .intersection(&max_content_rect)
5752 .expect("bug: no intersection with tile dirty rect: {content_device_rect:?} / {max_content_rect:?}");
5753
5754 let content_task_size = content_device_rect.size();
5755 let normalized_content_rect = content_task_size.into();
5756
5757 let inner_offset = content_origin + scissor_rect.min.to_vector().to_f32();
5758 let outer_offset = content_device_rect.min.to_f32();
5759 let sub_rect_offset = (inner_offset - outer_offset).round().to_i32();
5760
5761 let render_task_id = frame_state.rg_builder.add().init(
5762 RenderTask::new_dynamic(
5763 content_task_size,
5764 RenderTaskKind::new_picture(
5765 content_task_size,
5766 true,
5767 content_device_rect.min.to_f32(),
5768 surface_spatial_node_index,
5769 surface_spatial_node_index,
5771 device_pixel_scale,
5772 Some(normalized_content_rect),
5773 None,
5774 Some(clear_color),
5775 cmd_buffer_index,
5776 false,
5777 None,
5778 )
5779 ),
5780 );
5781
5782 let composite_task_id = frame_state.rg_builder.add().init(
5783 RenderTask::new(
5784 RenderTaskLocation::Static {
5785 surface: StaticRenderTaskSurface::PictureCache {
5786 surface,
5787 },
5788 rect: composite_task_size.into(),
5789 },
5790 RenderTaskKind::new_tile_composite(
5791 sub_rect_offset,
5792 scissor_rect,
5793 valid_rect,
5794 clear_color,
5795 ),
5796 ),
5797 );
5798
5799 surface_render_tasks.insert(
5800 tile_key,
5801 SurfaceTileDescriptor {
5802 current_task_id: render_task_id,
5803 composite_task_id: Some(composite_task_id),
5804 dirty_rect: tile.local_dirty_rect,
5805 },
5806 );
5807 } else {
5808 let render_task_id = frame_state.rg_builder.add().init(
5809 RenderTask::new(
5810 RenderTaskLocation::Static {
5811 surface: StaticRenderTaskSurface::PictureCache {
5812 surface,
5813 },
5814 rect: composite_task_size.into(),
5815 },
5816 RenderTaskKind::new_picture(
5817 composite_task_size,
5818 true,
5819 content_origin,
5820 surface_spatial_node_index,
5821 surface_spatial_node_index,
5823 device_pixel_scale,
5824 Some(scissor_rect),
5825 Some(valid_rect),
5826 Some(clear_color),
5827 cmd_buffer_index,
5828 false,
5829 None,
5830 )
5831 ),
5832 );
5833
5834 surface_render_tasks.insert(
5835 tile_key,
5836 SurfaceTileDescriptor {
5837 current_task_id: render_task_id,
5838 composite_task_id: None,
5839 dirty_rect: tile.local_dirty_rect,
5840 },
5841 );
5842 }
5843 }
5844
5845 if frame_context.fb_config.testing {
5846 debug_info.tiles.insert(
5847 tile.tile_offset,
5848 TileDebugInfo::Dirty(DirtyTileDebugInfo {
5849 local_valid_rect: tile.current_descriptor.local_valid_rect,
5850 local_dirty_rect: tile.local_dirty_rect,
5851 }),
5852 );
5853 }
5854 }
5855
5856 let surface = tile.surface.as_ref().expect("no tile surface set!");
5857
5858 let descriptor = CompositeTileDescriptor {
5859 surface_kind: surface.into(),
5860 tile_id: tile.id,
5861 };
5862
5863 let (surface, is_opaque) = match surface {
5864 TileSurface::Color { color } => {
5865 (CompositeTileSurface::Color { color: *color }, true)
5866 }
5867 TileSurface::Clear => {
5868 (CompositeTileSurface::Clear, false)
5870 }
5871 TileSurface::Texture { descriptor, .. } => {
5872 let surface = descriptor.resolve(frame_state.resource_cache, tile_cache.current_tile_size);
5873 (
5874 CompositeTileSurface::Texture { surface },
5875 tile.is_opaque
5876 )
5877 }
5878 };
5879
5880 if is_opaque {
5881 sub_slice.opaque_tile_descriptors.push(descriptor);
5882 } else {
5883 sub_slice.alpha_tile_descriptors.push(descriptor);
5884 }
5885
5886 let composite_tile = CompositeTile {
5887 kind: tile_kind(&surface, is_opaque),
5888 surface,
5889 local_rect: tile.local_tile_rect,
5890 local_valid_rect: tile.current_descriptor.local_valid_rect,
5891 local_dirty_rect: tile.local_dirty_rect,
5892 device_clip_rect,
5893 z_id: tile.z_id,
5894 transform_index: tile_cache.transform_index,
5895 clip_index: tile_cache.compositor_clip,
5896 tile_id: Some(tile.id),
5897 };
5898
5899 sub_slice.composite_tiles.push(composite_tile);
5900
5901 tile.local_dirty_rect = PictureRect::zero();
5903 tile.is_valid = true;
5904 }
5905
5906 sub_slice.opaque_tile_descriptors.sort_by_key(|desc| desc.tile_id);
5911 sub_slice.alpha_tile_descriptors.sort_by_key(|desc| desc.tile_id);
5912 }
5913
5914 let backdrop_rect = tile_cache.backdrop.backdrop_rect
5916 .intersection(&tile_cache.local_rect)
5917 .and_then(|r| {
5918 r.intersection(&tile_cache.local_clip_rect)
5919 });
5920
5921 let mut backdrop_in_use_and_visible = false;
5922 if let Some(backdrop_rect) = backdrop_rect {
5923 let supports_surface_for_backdrop = match frame_state.composite_state.compositor_kind {
5924 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
5925 false
5926 }
5927 CompositorKind::Native { capabilities, .. } => {
5928 capabilities.supports_surface_for_backdrop
5929 }
5930 };
5931 if supports_surface_for_backdrop && !tile_cache.found_prims_after_backdrop && at_least_one_tile_visible {
5932 if let Some(BackdropKind::Color { color }) = tile_cache.backdrop.kind {
5933 backdrop_in_use_and_visible = true;
5934
5935 for sub_slice in &mut tile_cache.sub_slices {
5938 for tile in sub_slice.tiles.values_mut() {
5939 tile.is_visible = false;
5940 }
5941 }
5942
5943 if let Some(backdrop_surface) = &tile_cache.backdrop_surface {
5946 if backdrop_surface.color != color {
5947 frame_state.resource_cache.destroy_compositor_surface(backdrop_surface.id);
5948 tile_cache.backdrop_surface = None;
5949 }
5950 }
5951
5952 let world_backdrop_rect = map_pic_to_world.map(&backdrop_rect).expect("bug: unable to map backdrop rect");
5955 let device_rect = (world_backdrop_rect * frame_context.global_device_pixel_scale).round();
5956
5957 if let Some(backdrop_surface) = &mut tile_cache.backdrop_surface {
5960 backdrop_surface.device_rect = device_rect;
5961 } else {
5962 tile_cache.backdrop_surface = Some(BackdropSurface {
5964 id: frame_state.resource_cache.create_compositor_backdrop_surface(color),
5965 color,
5966 device_rect,
5967 });
5968 }
5969 }
5970 }
5971 }
5972
5973 if !backdrop_in_use_and_visible {
5974 if let Some(backdrop_surface) = &tile_cache.backdrop_surface {
5975 frame_state.resource_cache.destroy_compositor_surface(backdrop_surface.id);
5978 tile_cache.backdrop_surface = None;
5979 }
5980 }
5981
5982 if frame_context.debug_flags.contains(DebugFlags::INVALIDATION_DBG) {
5984 tile_cache.print();
5985 }
5986
5987 if frame_context.fb_config.testing {
5990 frame_state.composite_state
5991 .picture_cache_debug
5992 .slices
5993 .insert(
5994 tile_cache.slice,
5995 debug_info,
5996 );
5997 }
5998
5999 let descriptor = SurfaceDescriptor::new_tiled(surface_render_tasks);
6000
6001 frame_state.surface_builder.push_surface(
6002 surface_index,
6003 false,
6004 surface_local_dirty_rect,
6005 Some(descriptor),
6006 frame_state.surfaces,
6007 frame_state.rg_builder,
6008 );
6009 }
6010 Some(ref mut raster_config) => {
6011 let (pic_rect, force_scissor_rect) = {
6012 let surface = &frame_state.surfaces[raster_config.surface_index.0];
6013 (surface.clipped_local_rect, surface.force_scissor_rect)
6014 };
6015
6016 let parent_surface_index = parent_surface_index.expect("bug: no parent for child surface");
6017
6018 let local_rect = pic_rect * Scale::new(1.0);
6021
6022 if local_rect != self.prev_local_rect {
6031 match raster_config.composite_mode {
6032 PictureCompositeMode::Filter(Filter::DropShadows(..)) => {
6033 for handle in &self.extra_gpu_data_handles {
6034 frame_state.gpu_cache.invalidate(handle);
6035 }
6036 }
6037 _ => {}
6038 }
6039 self.segments_are_valid = false;
6042 self.prev_local_rect = local_rect;
6043 }
6044
6045 let max_surface_size = frame_context
6046 .fb_config
6047 .max_surface_override
6048 .unwrap_or(MAX_SURFACE_SIZE) as f32;
6049
6050 let surface_rects = match get_surface_rects(
6051 raster_config.surface_index,
6052 &raster_config.composite_mode,
6053 parent_surface_index,
6054 &mut frame_state.surfaces,
6055 frame_context.spatial_tree,
6056 max_surface_size,
6057 force_scissor_rect,
6058 ) {
6059 Some(rects) => rects,
6060 None => return None,
6061 };
6062
6063 let (raster_spatial_node_index, device_pixel_scale) = {
6064 let surface = &frame_state.surfaces[surface_index.0];
6065 (surface.raster_spatial_node_index, surface.device_pixel_scale)
6066 };
6067 let can_use_shared_surface = !self.flags.contains(PictureFlags::IS_RESOLVE_TARGET);
6068
6069 let primary_render_task_id;
6070 let surface_descriptor;
6071 match raster_config.composite_mode {
6072 PictureCompositeMode::TileCache { .. } => {
6073 unreachable!("handled above");
6074 }
6075 PictureCompositeMode::Filter(Filter::Blur { width, height, edge_mode, .. }) => {
6076 let surface = &frame_state.surfaces[raster_config.surface_index.0];
6077 let (width, height) = surface.clamp_blur_radius(width, height);
6078
6079 let width_std_deviation = width * surface.local_scale.0 * device_pixel_scale.0;
6080 let height_std_deviation = height * surface.local_scale.1 * device_pixel_scale.0;
6081 let blur_std_deviation = DeviceSize::new(
6082 width_std_deviation,
6083 height_std_deviation,
6084 );
6085
6086 let original_size = surface_rects.clipped.size();
6087
6088 let adjusted_size = BlurTask::adjusted_blur_source_size(
6092 original_size,
6093 blur_std_deviation,
6094 );
6095
6096 let clear_color = if adjusted_size == original_size {
6101 None
6102 } else {
6103 Some(ColorF::TRANSPARENT)
6104 };
6105
6106 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6107 let adjusted_size = adjusted_size.to_i32();
6108
6109 let uv_rect_kind = calculate_uv_rect_kind(
6112 DeviceRect::from_origin_and_size(surface_rects.clipped.min, adjusted_size.to_f32()),
6113 surface_rects.unclipped,
6114 );
6115
6116 let picture_task_id = frame_state.rg_builder.add().init(
6117 RenderTask::new_dynamic(
6118 adjusted_size,
6119 RenderTaskKind::new_picture(
6120 adjusted_size,
6121 surface_rects.needs_scissor_rect,
6122 surface_rects.clipped.min,
6123 surface_spatial_node_index,
6124 raster_spatial_node_index,
6125 device_pixel_scale,
6126 None,
6127 None,
6128 clear_color,
6129 cmd_buffer_index,
6130 can_use_shared_surface,
6131 Some(original_size.round().to_i32()),
6132 )
6133 ).with_uv_rect_kind(uv_rect_kind)
6134 );
6135
6136
6137 let blur_render_task_id = request_render_task(
6138 frame_state,
6139 &self.snapshot,
6140 &surface_rects,
6141 false,
6142 &mut|rg_builder, _, _| {
6143 RenderTask::new_blur(
6144 blur_std_deviation,
6145 picture_task_id,
6146 rg_builder,
6147 RenderTargetKind::Color,
6148 None,
6149 original_size.to_i32(),
6150 edge_mode,
6151 )
6152 }
6153 );
6154 primary_render_task_id = blur_render_task_id;
6155
6156 surface_descriptor = SurfaceDescriptor::new_chained(
6157 picture_task_id,
6158 blur_render_task_id,
6159 surface_rects.clipped_local,
6160 );
6161 }
6162 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
6163 let surface = &frame_state.surfaces[raster_config.surface_index.0];
6164
6165 let device_rect = surface_rects.clipped;
6166
6167 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6168
6169 let picture_task_id = frame_state.rg_builder.add().init(
6170 RenderTask::new_dynamic(
6171 surface_rects.task_size,
6172 RenderTaskKind::new_picture(
6173 surface_rects.task_size,
6174 surface_rects.needs_scissor_rect,
6175 device_rect.min,
6176 surface_spatial_node_index,
6177 raster_spatial_node_index,
6178 device_pixel_scale,
6179 None,
6180 None,
6181 None,
6182 cmd_buffer_index,
6183 can_use_shared_surface,
6184 None,
6185 ),
6186 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6187 );
6188
6189 let mut blur_tasks = BlurTaskCache::default();
6190
6191 self.extra_gpu_data_handles.resize(shadows.len(), GpuCacheHandle::new());
6192
6193 let mut blur_render_task_id = picture_task_id;
6194 for shadow in shadows {
6195 let (blur_radius_x, blur_radius_y) = surface.clamp_blur_radius(
6196 shadow.blur_radius,
6197 shadow.blur_radius,
6198 );
6199
6200 blur_render_task_id = RenderTask::new_blur(
6201 DeviceSize::new(
6202 blur_radius_x * surface.local_scale.0 * device_pixel_scale.0,
6203 blur_radius_y * surface.local_scale.1 * device_pixel_scale.0,
6204 ),
6205 picture_task_id,
6206 frame_state.rg_builder,
6207 RenderTargetKind::Color,
6208 Some(&mut blur_tasks),
6209 device_rect.size().to_i32(),
6210 BlurEdgeMode::Duplicate,
6211 );
6212 }
6213
6214 frame_state.surface_builder.add_picture_render_task(picture_task_id);
6219
6220 primary_render_task_id = blur_render_task_id;
6221 self.secondary_render_task_id = Some(picture_task_id);
6222
6223 surface_descriptor = SurfaceDescriptor::new_chained(
6224 picture_task_id,
6225 blur_render_task_id,
6226 surface_rects.clipped_local,
6227 );
6228 }
6229 PictureCompositeMode::MixBlend(mode) if BlendMode::from_mix_blend_mode(
6230 mode,
6231 frame_context.fb_config.gpu_supports_advanced_blend,
6232 frame_context.fb_config.advanced_blend_is_coherent,
6233 frame_context.fb_config.dual_source_blending_is_supported,
6234 ).is_none() => {
6235 let parent_surface = &frame_state.surfaces[parent_surface_index.0];
6236
6237 let map_pic_to_parent = SpaceMapper::new_with_target(
6243 parent_surface.surface_spatial_node_index,
6244 surface_spatial_node_index,
6245 parent_surface.clipping_rect,
6246 frame_context.spatial_tree,
6247 );
6248 let pic_in_raster_space = map_pic_to_parent
6249 .map(&pic_rect)
6250 .expect("bug: unable to map mix-blend content into parent");
6251
6252 let backdrop_rect = pic_in_raster_space;
6255 let parent_surface_rect = parent_surface.clipping_rect;
6256
6257 let readback_task_id = match backdrop_rect.intersection(&parent_surface_rect) {
6264 Some(available_rect) => {
6265 let backdrop_rect = parent_surface.map_to_device_rect(
6271 &backdrop_rect,
6272 frame_context.spatial_tree,
6273 );
6274
6275 let available_rect = parent_surface.map_to_device_rect(
6276 &available_rect,
6277 frame_context.spatial_tree,
6278 ).round_out();
6279
6280 let backdrop_uv = calculate_uv_rect_kind(
6281 available_rect,
6282 backdrop_rect,
6283 );
6284
6285 frame_state.rg_builder.add().init(
6286 RenderTask::new_dynamic(
6287 available_rect.size().to_i32(),
6288 RenderTaskKind::new_readback(Some(available_rect.min)),
6289 ).with_uv_rect_kind(backdrop_uv)
6290 )
6291 }
6292 None => {
6293 frame_state.rg_builder.add().init(
6294 RenderTask::new_dynamic(
6295 DeviceIntSize::new(16, 16),
6296 RenderTaskKind::new_readback(None),
6297 )
6298 )
6299 }
6300 };
6301
6302 frame_state.surface_builder.add_child_render_task(
6303 readback_task_id,
6304 frame_state.rg_builder,
6305 );
6306
6307 self.secondary_render_task_id = Some(readback_task_id);
6308
6309 let task_size = surface_rects.clipped.size().to_i32();
6310
6311 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6312
6313 let is_opaque = false; let render_task_id = request_render_task(
6315 frame_state,
6316 &self.snapshot,
6317 &surface_rects,
6318 is_opaque,
6319 &mut|rg_builder, _, _| {
6320 rg_builder.add().init(
6321 RenderTask::new_dynamic(
6322 task_size,
6323 RenderTaskKind::new_picture(
6324 task_size,
6325 surface_rects.needs_scissor_rect,
6326 surface_rects.clipped.min,
6327 surface_spatial_node_index,
6328 raster_spatial_node_index,
6329 device_pixel_scale,
6330 None,
6331 None,
6332 None,
6333 cmd_buffer_index,
6334 can_use_shared_surface,
6335 None,
6336 )
6337 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6338 )
6339 }
6340 );
6341
6342 primary_render_task_id = render_task_id;
6343
6344 surface_descriptor = SurfaceDescriptor::new_simple(
6345 render_task_id,
6346 surface_rects.clipped_local,
6347 );
6348 }
6349 PictureCompositeMode::Filter(..) => {
6350 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6351
6352 let is_opaque = false; let render_task_id = request_render_task(
6354 frame_state,
6355 &self.snapshot,
6356 &surface_rects,
6357 is_opaque,
6358 &mut|rg_builder, _, _| {
6359 rg_builder.add().init(
6360 RenderTask::new_dynamic(
6361 surface_rects.task_size,
6362 RenderTaskKind::new_picture(
6363 surface_rects.task_size,
6364 surface_rects.needs_scissor_rect,
6365 surface_rects.clipped.min,
6366 surface_spatial_node_index,
6367 raster_spatial_node_index,
6368 device_pixel_scale,
6369 None,
6370 None,
6371 None,
6372 cmd_buffer_index,
6373 can_use_shared_surface,
6374 None,
6375 )
6376 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6377 )
6378 },
6379 );
6380
6381 primary_render_task_id = render_task_id;
6382
6383 surface_descriptor = SurfaceDescriptor::new_simple(
6384 render_task_id,
6385 surface_rects.clipped_local,
6386 );
6387 }
6388 PictureCompositeMode::ComponentTransferFilter(..) => {
6389 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6390
6391 let is_opaque = false; let render_task_id = request_render_task(
6393 frame_state,
6394 &self.snapshot,
6395 &surface_rects,
6396 is_opaque,
6397 &mut|rg_builder, _, _| {
6398 rg_builder.add().init(
6399 RenderTask::new_dynamic(
6400 surface_rects.task_size,
6401 RenderTaskKind::new_picture(
6402 surface_rects.task_size,
6403 surface_rects.needs_scissor_rect,
6404 surface_rects.clipped.min,
6405 surface_spatial_node_index,
6406 raster_spatial_node_index,
6407 device_pixel_scale,
6408 None,
6409 None,
6410 None,
6411 cmd_buffer_index,
6412 can_use_shared_surface,
6413 None,
6414 )
6415 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6416 )
6417 }
6418 );
6419
6420 primary_render_task_id = render_task_id;
6421
6422 surface_descriptor = SurfaceDescriptor::new_simple(
6423 render_task_id,
6424 surface_rects.clipped_local,
6425 );
6426 }
6427 PictureCompositeMode::MixBlend(..) |
6428 PictureCompositeMode::Blit(_) => {
6429 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6430
6431 let is_opaque = false; let render_task_id = request_render_task(
6433 frame_state,
6434 &self.snapshot,
6435 &surface_rects,
6436 is_opaque,
6437 &mut|rg_builder, _, _| {
6438 rg_builder.add().init(
6439 RenderTask::new_dynamic(
6440 surface_rects.task_size,
6441 RenderTaskKind::new_picture(
6442 surface_rects.task_size,
6443 surface_rects.needs_scissor_rect,
6444 surface_rects.clipped.min,
6445 surface_spatial_node_index,
6446 raster_spatial_node_index,
6447 device_pixel_scale,
6448 None,
6449 None,
6450 None,
6451 cmd_buffer_index,
6452 can_use_shared_surface,
6453 None,
6454 )
6455 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6456 )
6457 }
6458 );
6459
6460 primary_render_task_id = render_task_id;
6461
6462 surface_descriptor = SurfaceDescriptor::new_simple(
6463 render_task_id,
6464 surface_rects.clipped_local,
6465 );
6466 }
6467 PictureCompositeMode::IntermediateSurface => {
6468 if !scratch.required_sub_graphs.contains(&pic_index) {
6469 return None;
6470 }
6471
6472 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6475
6476 let is_opaque = false; let render_task_id = request_render_task(
6478 frame_state,
6479 &self.snapshot,
6480 &surface_rects,
6481 is_opaque,
6482 &mut|rg_builder, _, _| {
6483 rg_builder.add().init(
6484 RenderTask::new_dynamic(
6485 surface_rects.task_size,
6486 RenderTaskKind::new_picture(
6487 surface_rects.task_size,
6488 surface_rects.needs_scissor_rect,
6489 surface_rects.clipped.min,
6490 surface_spatial_node_index,
6491 raster_spatial_node_index,
6492 device_pixel_scale,
6493 None,
6494 None,
6495 None,
6496 cmd_buffer_index,
6497 can_use_shared_surface,
6498 None,
6499 )
6500 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6501 )
6502 }
6503 );
6504
6505 primary_render_task_id = render_task_id;
6506
6507 surface_descriptor = SurfaceDescriptor::new_simple(
6508 render_task_id,
6509 surface_rects.clipped_local,
6510 );
6511 }
6512 PictureCompositeMode::SvgFilter(ref primitives, ref filter_datas) => {
6513 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6514
6515 let picture_task_id = frame_state.rg_builder.add().init(
6516 RenderTask::new_dynamic(
6517 surface_rects.task_size,
6518 RenderTaskKind::new_picture(
6519 surface_rects.task_size,
6520 surface_rects.needs_scissor_rect,
6521 surface_rects.clipped.min,
6522 surface_spatial_node_index,
6523 raster_spatial_node_index,
6524 device_pixel_scale,
6525 None,
6526 None,
6527 None,
6528 cmd_buffer_index,
6529 can_use_shared_surface,
6530 None,
6531 )
6532 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
6533 );
6534
6535 let is_opaque = false; let filter_task_id = request_render_task(
6537 frame_state,
6538 &self.snapshot,
6539 &surface_rects,
6540 is_opaque,
6541 &mut|rg_builder, _, _| {
6542 RenderTask::new_svg_filter(
6543 primitives,
6544 filter_datas,
6545 rg_builder,
6546 surface_rects.clipped.size().to_i32(),
6547 surface_rects.uv_rect_kind,
6548 picture_task_id,
6549 device_pixel_scale,
6550 )
6551 }
6552 );
6553
6554 primary_render_task_id = filter_task_id;
6555
6556 surface_descriptor = SurfaceDescriptor::new_chained(
6557 picture_task_id,
6558 filter_task_id,
6559 surface_rects.clipped_local,
6560 );
6561 }
6562 PictureCompositeMode::SVGFEGraph(ref filters) => {
6563 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
6564
6565 let prim_subregion = surface_rects.unclipped;
6567 let target_subregion = surface_rects.clipped;
6569 let source_subregion = surface_rects.source;
6572
6573 let source_task_size = source_subregion.round_out().size().to_i32();
6576 let source_task_size = if source_task_size.width > 0 && source_task_size.height > 0 {
6577 source_task_size
6578 } else {
6579 DeviceIntSize::new(1,1)
6580 };
6581 let picture_task_id = frame_state.rg_builder.add().init(
6582 RenderTask::new_dynamic(
6583 source_task_size,
6584 RenderTaskKind::new_picture(
6585 source_task_size,
6586 surface_rects.needs_scissor_rect,
6587 source_subregion.min,
6588 surface_spatial_node_index,
6589 raster_spatial_node_index,
6590 device_pixel_scale,
6591 None,
6592 None,
6593 None,
6594 cmd_buffer_index,
6595 can_use_shared_surface,
6596 None,
6597 )
6598 )
6599 );
6600
6601 let subregion_to_device_scale_x = surface_rects.clipped_notsnapped.width() / surface_rects.clipped_local.width();
6605 let subregion_to_device_scale_y = surface_rects.clipped_notsnapped.height() / surface_rects.clipped_local.height();
6606 let subregion_to_device_offset_x = surface_rects.clipped_notsnapped.min.x - (surface_rects.clipped_local.min.x * subregion_to_device_scale_x).floor();
6607 let subregion_to_device_offset_y = surface_rects.clipped_notsnapped.min.y - (surface_rects.clipped_local.min.y * subregion_to_device_scale_y).floor();
6608
6609 let filter_task_id = request_render_task(
6612 frame_state,
6613 &self.snapshot,
6614 &surface_rects,
6615 false,
6616 &mut|rg_builder, _, gpu_cache| {
6617 RenderTask::new_svg_filter_graph(
6618 filters,
6619 rg_builder,
6620 gpu_cache,
6621 data_stores,
6622 surface_rects.uv_rect_kind,
6623 picture_task_id,
6624 source_subregion.cast_unit(),
6625 target_subregion.cast_unit(),
6626 prim_subregion.cast_unit(),
6627 subregion_to_device_scale_x,
6628 subregion_to_device_scale_y,
6629 subregion_to_device_offset_x,
6630 subregion_to_device_offset_y,
6631 )
6632 }
6633 );
6634
6635 primary_render_task_id = filter_task_id;
6636
6637 surface_descriptor = SurfaceDescriptor::new_chained(
6638 picture_task_id,
6639 filter_task_id,
6640 surface_rects.clipped_local,
6641 );
6642 }
6643 }
6644
6645 let is_sub_graph = self.flags.contains(PictureFlags::IS_SUB_GRAPH);
6646
6647 frame_state.surface_builder.push_surface(
6648 raster_config.surface_index,
6649 is_sub_graph,
6650 surface_rects.clipped_local,
6651 Some(surface_descriptor),
6652 frame_state.surfaces,
6653 frame_state.rg_builder,
6654 );
6655
6656 self.primary_render_task_id = Some(primary_render_task_id);
6657 }
6658 None => {}
6659 };
6660
6661 let state = PictureState {
6662 map_local_to_pic,
6663 map_pic_to_vis,
6664 };
6665
6666 let mut dirty_region_count = 0;
6667
6668 if let Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) = self.raster_config {
6671 let dirty_region = tile_caches[&slice_id].dirty_region.clone();
6672 frame_state.push_dirty_region(dirty_region);
6673
6674 dirty_region_count += 1;
6675 }
6676
6677 let subpixel_mode = match self.raster_config {
6680 Some(RasterConfig { ref composite_mode, .. }) => {
6681 let subpixel_mode = match composite_mode {
6682 PictureCompositeMode::TileCache { slice_id } => {
6683 tile_caches[&slice_id].subpixel_mode
6684 }
6685 PictureCompositeMode::Blit(..) |
6686 PictureCompositeMode::ComponentTransferFilter(..) |
6687 PictureCompositeMode::Filter(..) |
6688 PictureCompositeMode::MixBlend(..) |
6689 PictureCompositeMode::IntermediateSurface |
6690 PictureCompositeMode::SvgFilter(..) |
6691 PictureCompositeMode::SVGFEGraph(..) => {
6692 SubpixelMode::Deny
6697 }
6698 };
6699
6700 subpixel_mode
6701 }
6702 None => {
6703 SubpixelMode::Allow
6704 }
6705 };
6706
6707 let subpixel_mode = match (parent_subpixel_mode, subpixel_mode) {
6709 (SubpixelMode::Allow, SubpixelMode::Allow) => {
6710 SubpixelMode::Allow
6712 }
6713 (SubpixelMode::Allow, SubpixelMode::Conditional { allowed_rect, prohibited_rect }) => {
6714 SubpixelMode::Conditional {
6716 allowed_rect,
6717 prohibited_rect,
6718 }
6719 }
6720 (SubpixelMode::Conditional { allowed_rect, prohibited_rect }, SubpixelMode::Allow) => {
6721 SubpixelMode::Conditional {
6723 allowed_rect,
6724 prohibited_rect,
6725 }
6726 }
6727 (SubpixelMode::Conditional { .. }, SubpixelMode::Conditional { ..}) => {
6728 unreachable!("bug: only top level picture caches have conditional subpixel");
6729 }
6730 (SubpixelMode::Deny, _) | (_, SubpixelMode::Deny) => {
6731 SubpixelMode::Deny
6733 }
6734 };
6735
6736 let context = PictureContext {
6737 pic_index,
6738 raster_spatial_node_index: frame_state.surfaces[surface_index.0].raster_spatial_node_index,
6739 visibility_spatial_node_index: frame_context.root_spatial_node_index,
6741 surface_spatial_node_index,
6742 surface_index,
6743 dirty_region_count,
6744 subpixel_mode,
6745 };
6746
6747 let prim_list = mem::replace(&mut self.prim_list, PrimitiveList::empty());
6748
6749 Some((context, state, prim_list))
6750 }
6751
6752 pub fn restore_context(
6753 &mut self,
6754 pic_index: PictureIndex,
6755 prim_list: PrimitiveList,
6756 context: PictureContext,
6757 prim_instances: &[PrimitiveInstance],
6758 frame_context: &FrameBuildingContext,
6759 frame_state: &mut FrameBuildingState,
6760 ) {
6761 for _ in 0 .. context.dirty_region_count {
6763 frame_state.pop_dirty_region();
6764 }
6765
6766 if self.raster_config.is_some() {
6767 frame_state.surface_builder.pop_surface(
6768 pic_index,
6769 frame_state.rg_builder,
6770 frame_state.cmd_buffers,
6771 );
6772 }
6773
6774 if let Picture3DContext::In { root_data: Some(ref mut list), plane_splitter_index, .. } = self.context_3d {
6775 let splitter = &mut frame_state.plane_splitters[plane_splitter_index.0];
6776
6777 PicturePrimitive::resolve_split_planes(
6779 splitter,
6780 list,
6781 &mut frame_state.gpu_cache,
6782 &frame_context.spatial_tree,
6783 );
6784
6785 let mut cmd_buffer_targets = Vec::new();
6787 for child in list {
6788 let child_prim_instance = &prim_instances[child.anchor.instance_index.0 as usize];
6789
6790 if frame_state.surface_builder.get_cmd_buffer_targets_for_prim(
6791 &child_prim_instance.vis,
6792 &mut cmd_buffer_targets,
6793 ) {
6794 let prim_cmd = PrimitiveCommand::complex(
6795 child.anchor.instance_index,
6796 child.gpu_address
6797 );
6798
6799 frame_state.push_prim(
6800 &prim_cmd,
6801 child.anchor.spatial_node_index,
6802 &cmd_buffer_targets,
6803 );
6804 }
6805 }
6806 }
6807
6808 self.prim_list = prim_list;
6809 }
6810
6811 pub fn add_split_plane(
6815 splitter: &mut PlaneSplitter,
6816 spatial_tree: &SpatialTree,
6817 prim_spatial_node_index: SpatialNodeIndex,
6818 visibility_spatial_node_index: SpatialNodeIndex,
6821 original_local_rect: LayoutRect,
6822 combined_local_clip_rect: &LayoutRect,
6823 dirty_rect: VisRect,
6824 plane_split_anchor: PlaneSplitAnchor,
6825 ) -> bool {
6826 let transform = spatial_tree.get_relative_transform(
6827 prim_spatial_node_index,
6828 visibility_spatial_node_index
6829 );
6830
6831 let matrix = transform.clone().into_transform().cast().to_untyped();
6832
6833 let local_rect = match original_local_rect
6840 .intersection(combined_local_clip_rect)
6841 {
6842 Some(rect) => rect.cast(),
6843 None => return false,
6844 };
6845 let dirty_rect = dirty_rect.cast();
6846
6847 match transform {
6848 CoordinateSpaceMapping::Local => {
6849 let polygon = Polygon::from_rect(
6850 local_rect.to_rect() * Scale::new(1.0),
6851 plane_split_anchor,
6852 );
6853 splitter.add(polygon);
6854 }
6855 CoordinateSpaceMapping::ScaleOffset(scale_offset) if scale_offset.scale == Vector2D::new(1.0, 1.0) => {
6856 let inv_matrix = scale_offset.inverse().to_transform().cast();
6857 let polygon = Polygon::from_transformed_rect_with_inverse(
6858 local_rect.to_rect().to_untyped(),
6859 &matrix,
6860 &inv_matrix,
6861 plane_split_anchor,
6862 ).unwrap();
6863 splitter.add(polygon);
6864 }
6865 CoordinateSpaceMapping::ScaleOffset(_) |
6866 CoordinateSpaceMapping::Transform(_) => {
6867 let mut clipper = Clipper::new();
6868 let results = clipper.clip_transformed(
6869 Polygon::from_rect(
6870 local_rect.to_rect().to_untyped(),
6871 plane_split_anchor,
6872 ),
6873 &matrix,
6874 Some(dirty_rect.to_rect().to_untyped()),
6875 );
6876 if let Ok(results) = results {
6877 for poly in results {
6878 splitter.add(poly);
6879 }
6880 }
6881 }
6882 }
6883
6884 true
6885 }
6886
6887 fn resolve_split_planes(
6888 splitter: &mut PlaneSplitter,
6889 ordered: &mut Vec<OrderedPictureChild>,
6890 gpu_cache: &mut GpuCache,
6891 spatial_tree: &SpatialTree,
6892 ) {
6893 ordered.clear();
6894
6895 let sorted = splitter.sort(vec3(0.0, 0.0, 1.0));
6898 ordered.reserve(sorted.len());
6899 for poly in sorted {
6900 let transform = match spatial_tree
6901 .get_world_transform(poly.anchor.spatial_node_index)
6902 .inverse()
6903 {
6904 Some(transform) => transform.into_transform(),
6905 None => continue,
6907 };
6908
6909 let local_points = [
6910 transform.transform_point3d(poly.points[0].cast_unit().to_f32()),
6911 transform.transform_point3d(poly.points[1].cast_unit().to_f32()),
6912 transform.transform_point3d(poly.points[2].cast_unit().to_f32()),
6913 transform.transform_point3d(poly.points[3].cast_unit().to_f32()),
6914 ];
6915
6916 if local_points.iter().any(|p| p.is_none()) {
6919 continue;
6920 }
6921
6922 let p0 = local_points[0].unwrap();
6923 let p1 = local_points[1].unwrap();
6924 let p2 = local_points[2].unwrap();
6925 let p3 = local_points[3].unwrap();
6926 let gpu_blocks = [
6927 [p0.x, p0.y, p1.x, p1.y].into(),
6928 [p2.x, p2.y, p3.x, p3.y].into(),
6929 ];
6930 let gpu_handle = gpu_cache.push_per_frame_blocks(&gpu_blocks);
6931 let gpu_address = gpu_cache.get_address(&gpu_handle);
6932
6933 ordered.push(OrderedPictureChild {
6934 anchor: poly.anchor,
6935 gpu_address,
6936 });
6937 }
6938 }
6939
6940 pub fn pre_update(
6943 &mut self,
6944 frame_context: &FrameBuildingContext,
6945 ) {
6946 self.resolve_scene_properties(frame_context.scene_properties);
6948 }
6949
6950 pub fn assign_surface(
6954 &mut self,
6955 frame_context: &FrameBuildingContext,
6956 parent_surface_index: Option<SurfaceIndex>,
6957 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
6958 surfaces: &mut Vec<SurfaceInfo>,
6959 ) -> Option<SurfaceIndex> {
6960 self.raster_config = None;
6962
6963 match self.composite_mode {
6964 Some(ref composite_mode) => {
6965 let surface_spatial_node_index = self.spatial_node_index;
6966
6967 let mut min_scale;
6969 let mut max_scale = 1.0e32;
6970
6971 let world_scale_factors = match parent_surface_index {
6975 Some(parent_surface_index) => {
6976 let parent_surface = &surfaces[parent_surface_index.0];
6977
6978 let local_to_surface = frame_context
6979 .spatial_tree
6980 .get_relative_transform(
6981 surface_spatial_node_index,
6982 parent_surface.surface_spatial_node_index,
6983 );
6984
6985 let scale_factors = if local_to_surface.is_perspective() {
6992 (1.0, 1.0)
6993 } else {
6994 local_to_surface.scale_factors()
6995 };
6996
6997 let scale_factors = (
6998 scale_factors.0 * parent_surface.world_scale_factors.0,
6999 scale_factors.1 * parent_surface.world_scale_factors.1,
7000 );
7001
7002 scale_factors
7003 }
7004 None => {
7005 let local_to_surface_scale_factors = frame_context
7006 .spatial_tree
7007 .get_relative_transform(
7008 surface_spatial_node_index,
7009 frame_context.spatial_tree.root_reference_frame_index(),
7010 )
7011 .scale_factors();
7012
7013 let scale_factors = (
7014 local_to_surface_scale_factors.0,
7015 local_to_surface_scale_factors.1,
7016 );
7017
7018 scale_factors
7019 }
7020 };
7021
7022 let allow_snapping = !self.flags.contains(PictureFlags::DISABLE_SNAPPING);
7029
7030 let force_scissor_rect = self.prim_list.needs_scissor_rect;
7039
7040 let (device_pixel_scale, raster_spatial_node_index, local_scale, world_scale_factors) = match composite_mode {
7043 PictureCompositeMode::TileCache { slice_id } => {
7044 let tile_cache = tile_caches.get_mut(&slice_id).unwrap();
7045
7046 let local_to_device = get_relative_scale_offset(
7048 tile_cache.spatial_node_index,
7049 frame_context.root_spatial_node_index,
7050 frame_context.spatial_tree,
7051 );
7052 let local_to_cur_raster_scale = local_to_device.scale.x / tile_cache.current_raster_scale;
7053
7054 if !frame_context.fb_config.low_quality_pinch_zoom
7062 || !frame_context
7063 .spatial_tree.get_spatial_node(tile_cache.spatial_node_index)
7064 .is_ancestor_or_self_zooming
7065 || local_to_cur_raster_scale <= 0.5
7066 || local_to_cur_raster_scale >= 2.0
7067 {
7068 tile_cache.current_raster_scale = local_to_device.scale.x;
7069 }
7070
7071 min_scale = 0.0;
7073
7074 if frame_context.fb_config.low_quality_pinch_zoom {
7075 min_scale = tile_cache.current_raster_scale;
7079 max_scale = tile_cache.current_raster_scale;
7080 }
7081
7082 let scaling_factor = world_scale_factors.0.max(world_scale_factors.1).max(min_scale).min(max_scale);
7084
7085 let device_pixel_scale = Scale::new(scaling_factor);
7086
7087 (device_pixel_scale, surface_spatial_node_index, (1.0, 1.0), world_scale_factors)
7088 }
7089 _ => {
7090 let surface_spatial_node = frame_context.spatial_tree.get_spatial_node(surface_spatial_node_index);
7091
7092 let enable_snapping =
7093 allow_snapping &&
7094 surface_spatial_node.coordinate_system_id == CoordinateSystemId::root() &&
7095 surface_spatial_node.snapping_transform.is_some();
7096
7097 if enable_snapping {
7098 let raster_spatial_node_index = frame_context.spatial_tree.root_reference_frame_index();
7099
7100 let local_to_raster_transform = frame_context
7101 .spatial_tree
7102 .get_relative_transform(
7103 self.spatial_node_index,
7104 raster_spatial_node_index,
7105 );
7106
7107 let local_scale = local_to_raster_transform.scale_factors();
7108
7109 (Scale::new(1.0), raster_spatial_node_index, local_scale, (1.0, 1.0))
7110 } else {
7111 let world_scale_factors = match self.raster_space {
7114 RasterSpace::Screen => world_scale_factors,
7115 RasterSpace::Local(scale) => (scale, scale),
7116 };
7117
7118 let device_pixel_scale = Scale::new(
7119 world_scale_factors.0.max(world_scale_factors.1).min(max_scale)
7120 );
7121
7122 (device_pixel_scale, surface_spatial_node_index, (1.0, 1.0), world_scale_factors)
7123 }
7124 }
7125 };
7126
7127 let surface = SurfaceInfo::new(
7128 surface_spatial_node_index,
7129 raster_spatial_node_index,
7130 frame_context.global_screen_world_rect,
7131 &frame_context.spatial_tree,
7132 device_pixel_scale,
7133 world_scale_factors,
7134 local_scale,
7135 allow_snapping,
7136 force_scissor_rect,
7137 );
7138
7139 let surface_index = SurfaceIndex(surfaces.len());
7140
7141 surfaces.push(surface);
7142
7143 self.raster_config = Some(RasterConfig {
7144 composite_mode: composite_mode.clone(),
7145 surface_index,
7146 });
7147
7148 Some(surface_index)
7149 }
7150 None => {
7151 None
7152 }
7153 }
7154 }
7155
7156 pub fn propagate_bounding_rect(
7161 &mut self,
7162 surface_index: SurfaceIndex,
7163 parent_surface_index: Option<SurfaceIndex>,
7164 surfaces: &mut [SurfaceInfo],
7165 frame_context: &FrameBuildingContext,
7166 ) {
7167 let surface = &mut surfaces[surface_index.0];
7168
7169 for cluster in &mut self.prim_list.clusters {
7170 cluster.flags.remove(ClusterFlags::IS_VISIBLE);
7171
7172 if !cluster.flags.contains(ClusterFlags::IS_BACKFACE_VISIBLE) {
7174 if let Picture3DContext::In { ancestor_index, .. } = self.context_3d {
7177 let mut face = VisibleFace::Front;
7178 frame_context.spatial_tree.get_relative_transform_with_face(
7179 cluster.spatial_node_index,
7180 ancestor_index,
7181 Some(&mut face),
7182 );
7183 if face == VisibleFace::Back {
7184 continue
7185 }
7186 }
7187 }
7188
7189 let spatial_node = &frame_context
7191 .spatial_tree
7192 .get_spatial_node(cluster.spatial_node_index);
7193 if !spatial_node.invertible {
7194 continue;
7195 }
7196
7197 surface.map_local_to_picture.set_target_spatial_node(
7200 cluster.spatial_node_index,
7201 frame_context.spatial_tree,
7202 );
7203
7204 cluster.flags.insert(ClusterFlags::IS_VISIBLE);
7207 if let Some(cluster_rect) = surface.map_local_to_picture.map(&cluster.bounding_rect) {
7208 surface.unclipped_local_rect = surface.unclipped_local_rect.union(&cluster_rect);
7209 }
7210 }
7211
7212 if let Some(ref mut raster_config) = self.raster_config {
7216 if let Some(parent_surface_index) = parent_surface_index {
7218 let surface_rect = raster_config.composite_mode.get_coverage(
7219 surface,
7220 Some(surface.unclipped_local_rect.cast_unit()),
7221 );
7222
7223 let parent_surface = &mut surfaces[parent_surface_index.0];
7224 parent_surface.map_local_to_picture.set_target_spatial_node(
7225 self.spatial_node_index,
7226 frame_context.spatial_tree,
7227 );
7228
7229 if let Some(parent_surface_rect) = parent_surface
7233 .map_local_to_picture
7234 .map(&surface_rect)
7235 {
7236 parent_surface.unclipped_local_rect =
7237 parent_surface.unclipped_local_rect.union(&parent_surface_rect);
7238 }
7239 }
7240 }
7241 }
7242
7243 pub fn prepare_for_render(
7244 &mut self,
7245 frame_state: &mut FrameBuildingState,
7246 data_stores: &mut DataStores,
7247 ) -> bool {
7248 let raster_config = match self.raster_config {
7249 Some(ref mut raster_config) => raster_config,
7250 None => {
7251 return true
7252 }
7253 };
7254
7255 match raster_config.composite_mode {
7263 PictureCompositeMode::TileCache { .. } => {}
7264 PictureCompositeMode::Filter(Filter::Blur { .. }) => {}
7265 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
7266 self.extra_gpu_data_handles.resize(shadows.len(), GpuCacheHandle::new());
7267 for (shadow, extra_handle) in shadows.iter().zip(self.extra_gpu_data_handles.iter_mut()) {
7268 if let Some(mut request) = frame_state.gpu_cache.request(extra_handle) {
7269 let surface = &frame_state.surfaces[raster_config.surface_index.0];
7270 let prim_rect = surface.clipped_local_rect.cast_unit();
7271
7272 let (blur_inflation_x, blur_inflation_y) = surface.clamp_blur_radius(
7276 shadow.blur_radius,
7277 shadow.blur_radius,
7278 );
7279
7280 let shadow_rect = prim_rect.inflate(
7281 blur_inflation_x * BLUR_SAMPLE_SCALE,
7282 blur_inflation_y * BLUR_SAMPLE_SCALE,
7283 ).translate(shadow.offset);
7284
7285 request.push(shadow.color.premultiplied());
7287 request.push(PremultipliedColorF::WHITE);
7288 request.push([
7289 shadow_rect.width(),
7290 shadow_rect.height(),
7291 0.0,
7292 0.0,
7293 ]);
7294
7295 request.push(shadow_rect);
7297 request.push([0.0, 0.0, 0.0, 0.0]);
7298 }
7299 }
7300 }
7301 PictureCompositeMode::Filter(ref filter) => {
7302 match *filter {
7303 Filter::ColorMatrix(ref m) => {
7304 if self.extra_gpu_data_handles.is_empty() {
7305 self.extra_gpu_data_handles.push(GpuCacheHandle::new());
7306 }
7307 if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handles[0]) {
7308 for i in 0..5 {
7309 request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
7310 }
7311 }
7312 }
7313 Filter::Flood(ref color) => {
7314 if self.extra_gpu_data_handles.is_empty() {
7315 self.extra_gpu_data_handles.push(GpuCacheHandle::new());
7316 }
7317 if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handles[0]) {
7318 request.push(color.to_array());
7319 }
7320 }
7321 _ => {}
7322 }
7323 }
7324 PictureCompositeMode::ComponentTransferFilter(handle) => {
7325 let filter_data = &mut data_stores.filter_data[handle];
7326 filter_data.update(&mut frame_state.gpu_cache);
7327 }
7328 PictureCompositeMode::MixBlend(..) |
7329 PictureCompositeMode::Blit(_) |
7330 PictureCompositeMode::IntermediateSurface |
7331 PictureCompositeMode::SvgFilter(..) => {}
7332 PictureCompositeMode::SVGFEGraph(ref filters) => {
7333 for (_node, op) in filters {
7335 match op {
7336 FilterGraphOp::SVGFEComponentTransferInterned { handle, creates_pixels: _ } => {
7337 let filter_data = &mut data_stores.filter_data[*handle];
7338 filter_data.update(&mut frame_state.gpu_cache);
7339 }
7340 _ => {}
7341 }
7342 }
7343 }
7344 }
7345
7346 true
7347 }
7348
7349 #[cold]
7350 fn draw_debug_overlay(
7351 &self,
7352 parent_surface_index: Option<SurfaceIndex>,
7353 frame_state: &FrameBuildingState,
7354 frame_context: &FrameBuildingContext,
7355 tile_caches: &FastHashMap<SliceId, Box<TileCacheInstance>>,
7356 scratch: &mut PrimitiveScratchBuffer,
7357 ) {
7358 fn draw_debug_border(
7359 local_rect: &PictureRect,
7360 thickness: i32,
7361 pic_to_world_mapper: &SpaceMapper<PicturePixel, WorldPixel>,
7362 global_device_pixel_scale: DevicePixelScale,
7363 color: ColorF,
7364 scratch: &mut PrimitiveScratchBuffer,
7365 ) {
7366 if let Some(world_rect) = pic_to_world_mapper.map(&local_rect) {
7367 let device_rect = world_rect * global_device_pixel_scale;
7368 scratch.push_debug_rect(
7369 device_rect,
7370 thickness,
7371 color,
7372 ColorF::TRANSPARENT,
7373 );
7374 }
7375 }
7376
7377 let flags = frame_context.debug_flags;
7378 let draw_borders = flags.contains(DebugFlags::PICTURE_BORDERS);
7379 let draw_tile_dbg = flags.contains(DebugFlags::PICTURE_CACHING_DBG);
7380
7381 let surface_index = match &self.raster_config {
7382 Some(raster_config) => raster_config.surface_index,
7383 None => parent_surface_index.expect("bug: no parent"),
7384 };
7385 let surface_spatial_node_index = frame_state
7386 .surfaces[surface_index.0]
7387 .surface_spatial_node_index;
7388
7389 let map_pic_to_world = SpaceMapper::new_with_target(
7390 frame_context.root_spatial_node_index,
7391 surface_spatial_node_index,
7392 frame_context.global_screen_world_rect,
7393 frame_context.spatial_tree,
7394 );
7395
7396 let Some(raster_config) = &self.raster_config else {
7397 return;
7398 };
7399
7400 if draw_borders {
7401 let layer_color;
7402 if let PictureCompositeMode::TileCache { slice_id } = &raster_config.composite_mode {
7403 layer_color = ColorF::new(0.0, 1.0, 0.0, 0.8);
7405
7406 let Some(tile_cache) = tile_caches.get(&slice_id) else {
7407 return;
7408 };
7409
7410 for (_, sub_slice) in tile_cache.sub_slices.iter().enumerate() {
7412 for tile in sub_slice.tiles.values() {
7413 if !tile.is_visible {
7414 continue;
7415 }
7416 let rect = tile.local_tile_rect.intersection(&tile_cache.local_rect);
7417 if let Some(rect) = rect {
7418 draw_debug_border(
7419 &rect,
7420 1,
7421 &map_pic_to_world,
7422 frame_context.global_device_pixel_scale,
7423 ColorF::new(0.0, 1.0, 0.0, 0.2),
7424 scratch,
7425 );
7426 }
7427 }
7428 }
7429 } else {
7430 layer_color = ColorF::new(1.0, 0.0, 0.0, 0.5);
7432 }
7433
7434 let pic_rect = frame_state
7436 .surfaces[raster_config.surface_index.0]
7437 .unclipped_local_rect;
7438
7439 draw_debug_border(
7440 &pic_rect,
7441 3,
7442 &map_pic_to_world,
7443 frame_context.global_device_pixel_scale,
7444 layer_color,
7445 scratch,
7446 );
7447 }
7448
7449 if draw_tile_dbg && self.is_visible(frame_context.spatial_tree) {
7450 if let PictureCompositeMode::TileCache { slice_id } = &raster_config.composite_mode {
7451 let Some(tile_cache) = tile_caches.get(&slice_id) else {
7452 return;
7453 };
7454 for (sub_slice_index, sub_slice) in tile_cache.sub_slices.iter().enumerate() {
7455 for tile in sub_slice.tiles.values() {
7456 if !tile.is_visible {
7457 continue;
7458 }
7459 tile.root.draw_debug_rects(
7460 &map_pic_to_world,
7461 tile.is_opaque,
7462 tile.current_descriptor.local_valid_rect,
7463 scratch,
7464 frame_context.global_device_pixel_scale,
7465 );
7466
7467 let label_offset = DeviceVector2D::new(
7468 20.0 + sub_slice_index as f32 * 20.0,
7469 30.0 + sub_slice_index as f32 * 20.0,
7470 );
7471 let tile_device_rect = tile.world_tile_rect
7472 * frame_context.global_device_pixel_scale;
7473
7474 if tile_device_rect.height() >= label_offset.y {
7475 let surface = tile.surface.as_ref().expect("no tile surface set!");
7476
7477 scratch.push_debug_string(
7478 tile_device_rect.min + label_offset,
7479 debug_colors::RED,
7480 format!("{:?}: s={} is_opaque={} surface={} sub={}",
7481 tile.id,
7482 tile_cache.slice,
7483 tile.is_opaque,
7484 surface.kind(),
7485 sub_slice_index,
7486 ),
7487 );
7488 }
7489 }
7490 }
7491 }
7492 }
7493 }
7494}
7495
7496fn get_transform_key(
7497 spatial_node_index: SpatialNodeIndex,
7498 cache_spatial_node_index: SpatialNodeIndex,
7499 spatial_tree: &SpatialTree,
7500) -> TransformKey {
7501 spatial_tree.get_relative_transform(
7502 spatial_node_index,
7503 cache_spatial_node_index,
7504 ).into()
7505}
7506
7507#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
7509struct PrimitiveComparisonKey {
7510 prev_index: PrimitiveDependencyIndex,
7511 curr_index: PrimitiveDependencyIndex,
7512}
7513
7514#[derive(Debug, Copy, Clone, PartialEq, PeekPoke, Default)]
7516#[cfg_attr(feature = "capture", derive(Serialize))]
7517#[cfg_attr(feature = "replay", derive(Deserialize))]
7518pub struct ImageDependency {
7519 pub key: ImageKey,
7520 pub generation: ImageGeneration,
7521}
7522
7523impl ImageDependency {
7524 pub const INVALID: ImageDependency = ImageDependency {
7525 key: ImageKey::DUMMY,
7526 generation: ImageGeneration::INVALID,
7527 };
7528}
7529
7530#[derive(Debug)]
7533struct DeferredDirtyTest {
7534 tile_rect: TileRect,
7536 prim_rect: PictureRect,
7538}
7539
7540struct PrimitiveComparer<'a> {
7542 prev_data: &'a [u8],
7543 curr_data: &'a [u8],
7544 prev_frame_id: FrameId,
7545 curr_frame_id: FrameId,
7546 resource_cache: &'a ResourceCache,
7547 spatial_node_comparer: &'a mut SpatialNodeComparer,
7548 opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
7549 color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
7550}
7551
7552impl<'a> PrimitiveComparer<'a> {
7553 fn new(
7554 prev: &'a TileDescriptor,
7555 curr: &'a TileDescriptor,
7556 resource_cache: &'a ResourceCache,
7557 spatial_node_comparer: &'a mut SpatialNodeComparer,
7558 opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>,
7559 color_bindings: &'a FastHashMap<PropertyBindingId, ColorBindingInfo>,
7560 ) -> Self {
7561 PrimitiveComparer {
7562 prev_data: &prev.dep_data,
7563 curr_data: &curr.dep_data,
7564 prev_frame_id: prev.last_updated_frame_id,
7565 curr_frame_id: curr.last_updated_frame_id,
7566 resource_cache,
7567 spatial_node_comparer,
7568 opacity_bindings,
7569 color_bindings,
7570 }
7571 }
7572
7573 fn compare_prim(
7575 &mut self,
7576 prev_desc: &PrimitiveDescriptor,
7577 curr_desc: &PrimitiveDescriptor,
7578 ) -> PrimitiveCompareResult {
7579 let resource_cache = self.resource_cache;
7580 let spatial_node_comparer = &mut self.spatial_node_comparer;
7581 let opacity_bindings = self.opacity_bindings;
7582 let color_bindings = self.color_bindings;
7583
7584 if prev_desc != curr_desc {
7586 return PrimitiveCompareResult::Descriptor;
7587 }
7588
7589 let mut prev_dep_data = &self.prev_data[prev_desc.dep_offset as usize ..];
7590 let mut curr_dep_data = &self.curr_data[curr_desc.dep_offset as usize ..];
7591
7592 let mut prev_dep = PrimitiveDependency::SpatialNode { index: SpatialNodeIndex::INVALID };
7593 let mut curr_dep = PrimitiveDependency::SpatialNode { index: SpatialNodeIndex::INVALID };
7594
7595 debug_assert_eq!(prev_desc.dep_count, curr_desc.dep_count);
7596
7597 for _ in 0 .. prev_desc.dep_count {
7598 prev_dep_data = peek_from_slice(prev_dep_data, &mut prev_dep);
7599 curr_dep_data = peek_from_slice(curr_dep_data, &mut curr_dep);
7600
7601 match (&prev_dep, &curr_dep) {
7602 (PrimitiveDependency::Clip { clip: prev }, PrimitiveDependency::Clip { clip: curr }) => {
7603 if prev != curr {
7604 return PrimitiveCompareResult::Clip;
7605 }
7606 }
7607 (PrimitiveDependency::SpatialNode { index: prev }, PrimitiveDependency::SpatialNode { index: curr }) => {
7608 let prev_key = SpatialNodeKey {
7609 spatial_node_index: *prev,
7610 frame_id: self.prev_frame_id,
7611 };
7612 let curr_key = SpatialNodeKey {
7613 spatial_node_index: *curr,
7614 frame_id: self.curr_frame_id,
7615 };
7616 if !spatial_node_comparer.are_transforms_equivalent(&prev_key, &curr_key) {
7617 return PrimitiveCompareResult::Transform;
7618 }
7619 }
7620 (PrimitiveDependency::OpacityBinding { binding: prev }, PrimitiveDependency::OpacityBinding { binding: curr }) => {
7621 if prev != curr {
7622 return PrimitiveCompareResult::OpacityBinding;
7623 }
7624
7625 if let OpacityBinding::Binding(id) = curr {
7626 if opacity_bindings
7627 .get(id)
7628 .map_or(true, |info| info.changed) {
7629 return PrimitiveCompareResult::OpacityBinding;
7630 }
7631 }
7632 }
7633 (PrimitiveDependency::ColorBinding { binding: prev }, PrimitiveDependency::ColorBinding { binding: curr }) => {
7634 if prev != curr {
7635 return PrimitiveCompareResult::ColorBinding;
7636 }
7637
7638 if let ColorBinding::Binding(id) = curr {
7639 if color_bindings
7640 .get(id)
7641 .map_or(true, |info| info.changed) {
7642 return PrimitiveCompareResult::ColorBinding;
7643 }
7644 }
7645 }
7646 (PrimitiveDependency::Image { image: prev }, PrimitiveDependency::Image { image: curr }) => {
7647 if prev != curr {
7648 return PrimitiveCompareResult::Image;
7649 }
7650
7651 if resource_cache.get_image_generation(curr.key) != curr.generation {
7652 return PrimitiveCompareResult::Image;
7653 }
7654 }
7655 _ => {
7656 return PrimitiveCompareResult::Descriptor;
7658 }
7659 }
7660 }
7661
7662 PrimitiveCompareResult::Equal
7663 }
7664}
7665
7666#[cfg_attr(any(feature="capture",feature="replay"), derive(Clone))]
7668#[cfg_attr(feature = "capture", derive(Serialize))]
7669#[cfg_attr(feature = "replay", derive(Deserialize))]
7670pub enum TileNodeKind {
7671 Leaf {
7672 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
7674 prev_indices: Vec<PrimitiveDependencyIndex>,
7675 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
7677 curr_indices: Vec<PrimitiveDependencyIndex>,
7678 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
7680 dirty_tracker: u64,
7681 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
7683 frames_since_modified: usize,
7684 },
7685 Node {
7686 children: Vec<TileNode>,
7688 },
7689}
7690
7691#[derive(Copy, Clone, PartialEq, Debug)]
7693enum TileModification {
7694 Split,
7695 Merge,
7696}
7697
7698#[cfg_attr(any(feature="capture",feature="replay"), derive(Clone))]
7700#[cfg_attr(feature = "capture", derive(Serialize))]
7701#[cfg_attr(feature = "replay", derive(Deserialize))]
7702pub struct TileNode {
7703 pub kind: TileNodeKind,
7705 pub rect: PictureBox2D,
7707}
7708
7709impl TileNode {
7710 fn new_leaf(curr_indices: Vec<PrimitiveDependencyIndex>) -> Self {
7712 TileNode {
7713 kind: TileNodeKind::Leaf {
7714 prev_indices: Vec::new(),
7715 curr_indices,
7716 dirty_tracker: 0,
7717 frames_since_modified: 0,
7718 },
7719 rect: PictureBox2D::zero(),
7720 }
7721 }
7722
7723 fn draw_debug_rects(
7725 &self,
7726 pic_to_world_mapper: &SpaceMapper<PicturePixel, WorldPixel>,
7727 is_opaque: bool,
7728 local_valid_rect: PictureRect,
7729 scratch: &mut PrimitiveScratchBuffer,
7730 global_device_pixel_scale: DevicePixelScale,
7731 ) {
7732 match self.kind {
7733 TileNodeKind::Leaf { dirty_tracker, .. } => {
7734 let color = if (dirty_tracker & 1) != 0 {
7735 debug_colors::RED
7736 } else if is_opaque {
7737 debug_colors::GREEN
7738 } else {
7739 debug_colors::YELLOW
7740 };
7741
7742 if let Some(local_rect) = local_valid_rect.intersection(&self.rect) {
7743 let world_rect = pic_to_world_mapper
7744 .map(&local_rect)
7745 .unwrap();
7746 let device_rect = world_rect * global_device_pixel_scale;
7747
7748 let outer_color = color.scale_alpha(0.3);
7749 let inner_color = outer_color.scale_alpha(0.5);
7750 scratch.push_debug_rect(
7751 device_rect.inflate(-3.0, -3.0),
7752 1,
7753 outer_color,
7754 inner_color
7755 );
7756 }
7757 }
7758 TileNodeKind::Node { ref children, .. } => {
7759 for child in children.iter() {
7760 child.draw_debug_rects(
7761 pic_to_world_mapper,
7762 is_opaque,
7763 local_valid_rect,
7764 scratch,
7765 global_device_pixel_scale,
7766 );
7767 }
7768 }
7769 }
7770 }
7771
7772 fn get_child_rects(
7774 rect: &PictureBox2D,
7775 result: &mut [PictureBox2D; 4],
7776 ) {
7777 let p0 = rect.min;
7778 let p1 = rect.max;
7779 let pc = p0 + rect.size() * 0.5;
7780
7781 *result = [
7782 PictureBox2D::new(
7783 p0,
7784 pc,
7785 ),
7786 PictureBox2D::new(
7787 PicturePoint::new(pc.x, p0.y),
7788 PicturePoint::new(p1.x, pc.y),
7789 ),
7790 PictureBox2D::new(
7791 PicturePoint::new(p0.x, pc.y),
7792 PicturePoint::new(pc.x, p1.y),
7793 ),
7794 PictureBox2D::new(
7795 pc,
7796 p1,
7797 ),
7798 ];
7799 }
7800
7801 fn clear(
7803 &mut self,
7804 rect: PictureBox2D,
7805 ) {
7806 self.rect = rect;
7807
7808 match self.kind {
7809 TileNodeKind::Leaf { ref mut prev_indices, ref mut curr_indices, ref mut dirty_tracker, ref mut frames_since_modified } => {
7810 mem::swap(prev_indices, curr_indices);
7812 curr_indices.clear();
7813 *dirty_tracker = *dirty_tracker << 1;
7815 *frames_since_modified += 1;
7816 }
7817 TileNodeKind::Node { ref mut children, .. } => {
7818 let mut child_rects = [PictureBox2D::zero(); 4];
7819 TileNode::get_child_rects(&rect, &mut child_rects);
7820 assert_eq!(child_rects.len(), children.len());
7821
7822 for (child, rect) in children.iter_mut().zip(child_rects.iter()) {
7823 child.clear(*rect);
7824 }
7825 }
7826 }
7827 }
7828
7829 fn add_prim(
7831 &mut self,
7832 index: PrimitiveDependencyIndex,
7833 prim_rect: &PictureBox2D,
7834 ) {
7835 match self.kind {
7836 TileNodeKind::Leaf { ref mut curr_indices, .. } => {
7837 curr_indices.push(index);
7838 }
7839 TileNodeKind::Node { ref mut children, .. } => {
7840 for child in children.iter_mut() {
7841 if child.rect.intersects(prim_rect) {
7842 child.add_prim(index, prim_rect);
7843 }
7844 }
7845 }
7846 }
7847 }
7848
7849 fn maybe_merge_or_split(
7851 &mut self,
7852 level: i32,
7853 curr_prims: &[PrimitiveDescriptor],
7854 max_split_levels: i32,
7855 ) {
7856 let mut tile_mod = None;
7858
7859 fn get_dirty_frames(
7860 dirty_tracker: u64,
7861 frames_since_modified: usize,
7862 ) -> Option<u32> {
7863 if frames_since_modified > 64 {
7865 Some(dirty_tracker.count_ones())
7867 } else {
7868 None
7869 }
7870 }
7871
7872 match self.kind {
7873 TileNodeKind::Leaf { dirty_tracker, frames_since_modified, .. } => {
7874 if level < max_split_levels {
7876 if let Some(dirty_frames) = get_dirty_frames(dirty_tracker, frames_since_modified) {
7877 if dirty_frames > 32 {
7879 tile_mod = Some(TileModification::Split);
7880 }
7881 }
7882 }
7883 }
7884 TileNodeKind::Node { ref children, .. } => {
7885 let mut static_count = 0;
7892 let mut changing_count = 0;
7893
7894 for child in children {
7895 if let TileNodeKind::Leaf { dirty_tracker, frames_since_modified, .. } = child.kind {
7897 if let Some(dirty_frames) = get_dirty_frames(dirty_tracker, frames_since_modified) {
7898 if dirty_frames == 0 {
7899 static_count += 1;
7901 } else if dirty_frames == 64 {
7902 changing_count += 1;
7904 }
7905 }
7906 }
7907
7908 if static_count == 4 || changing_count == 4 {
7912 tile_mod = Some(TileModification::Merge);
7913 }
7914 }
7915 }
7916 }
7917
7918 match tile_mod {
7919 Some(TileModification::Split) => {
7920 let curr_indices = match self.kind {
7923 TileNodeKind::Node { .. } => {
7924 unreachable!("bug - only leaves can split");
7925 }
7926 TileNodeKind::Leaf { ref mut curr_indices, .. } => {
7927 curr_indices.take()
7928 }
7929 };
7930
7931 let mut child_rects = [PictureBox2D::zero(); 4];
7932 TileNode::get_child_rects(&self.rect, &mut child_rects);
7933
7934 let mut child_indices = [
7935 Vec::new(),
7936 Vec::new(),
7937 Vec::new(),
7938 Vec::new(),
7939 ];
7940
7941 for index in curr_indices {
7944 let prim = &curr_prims[index.0 as usize];
7945 for (child_rect, indices) in child_rects.iter().zip(child_indices.iter_mut()) {
7946 if prim.prim_clip_box.intersects(child_rect) {
7947 indices.push(index);
7948 }
7949 }
7950 }
7951
7952 let children = child_indices
7954 .iter_mut()
7955 .map(|i| TileNode::new_leaf(mem::replace(i, Vec::new())))
7956 .collect();
7957
7958 self.kind = TileNodeKind::Node {
7959 children,
7960 };
7961 }
7962 Some(TileModification::Merge) => {
7963 let merged_indices = match self.kind {
7966 TileNodeKind::Node { ref mut children, .. } => {
7967 let mut merged_indices = Vec::new();
7968
7969 for child in children.iter() {
7970 let child_indices = match child.kind {
7971 TileNodeKind::Leaf { ref curr_indices, .. } => {
7972 curr_indices
7973 }
7974 TileNodeKind::Node { .. } => {
7975 unreachable!("bug: child is not a leaf");
7976 }
7977 };
7978 merged_indices.extend_from_slice(child_indices);
7979 }
7980
7981 merged_indices.sort();
7982 merged_indices.dedup();
7983
7984 merged_indices
7985 }
7986 TileNodeKind::Leaf { .. } => {
7987 unreachable!("bug - trying to merge a leaf");
7988 }
7989 };
7990
7991 self.kind = TileNodeKind::Leaf {
7993 prev_indices: Vec::new(),
7994 curr_indices: merged_indices,
7995 dirty_tracker: 0,
7996 frames_since_modified: 0,
7997 };
7998 }
7999 None => {
8000 if let TileNodeKind::Node { ref mut children, .. } = self.kind {
8003 for child in children.iter_mut() {
8004 child.maybe_merge_or_split(
8005 level+1,
8006 curr_prims,
8007 max_split_levels,
8008 );
8009 }
8010 }
8011 }
8012 }
8013 }
8014
8015 fn update_dirty_rects(
8017 &mut self,
8018 prev_prims: &[PrimitiveDescriptor],
8019 curr_prims: &[PrimitiveDescriptor],
8020 prim_comparer: &mut PrimitiveComparer,
8021 dirty_rect: &mut PictureBox2D,
8022 compare_cache: &mut FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
8023 invalidation_reason: &mut Option<InvalidationReason>,
8024 frame_context: &FrameVisibilityContext,
8025 ) {
8026 match self.kind {
8027 TileNodeKind::Node { ref mut children, .. } => {
8028 for child in children.iter_mut() {
8029 child.update_dirty_rects(
8030 prev_prims,
8031 curr_prims,
8032 prim_comparer,
8033 dirty_rect,
8034 compare_cache,
8035 invalidation_reason,
8036 frame_context,
8037 );
8038 }
8039 }
8040 TileNodeKind::Leaf { ref prev_indices, ref curr_indices, ref mut dirty_tracker, .. } => {
8041 if prev_indices.len() == curr_indices.len() {
8043 for (prev_index, curr_index) in prev_indices.iter().zip(curr_indices.iter()) {
8045 let i0 = prev_index.0 as usize;
8046 let i1 = curr_index.0 as usize;
8047
8048 let key = PrimitiveComparisonKey {
8051 prev_index: *prev_index,
8052 curr_index: *curr_index,
8053 };
8054
8055 let prim_compare_result = *compare_cache
8056 .entry(key)
8057 .or_insert_with(|| {
8058 let prev = &prev_prims[i0];
8059 let curr = &curr_prims[i1];
8060 prim_comparer.compare_prim(prev, curr)
8061 });
8062
8063 if prim_compare_result != PrimitiveCompareResult::Equal {
8065 if invalidation_reason.is_none() {
8066 *invalidation_reason = Some(InvalidationReason::Content);
8067 }
8068 *dirty_rect = self.rect.union(dirty_rect);
8069 *dirty_tracker = *dirty_tracker | 1;
8070 break;
8071 }
8072 }
8073 } else {
8074 if invalidation_reason.is_none() {
8075 *invalidation_reason = Some(InvalidationReason::PrimCount);
8076 }
8077 *dirty_rect = self.rect.union(dirty_rect);
8078 *dirty_tracker = *dirty_tracker | 1;
8079 }
8080 }
8081 }
8082 }
8083}
8084
8085impl CompositeState {
8086 pub fn destroy_native_tiles<'a, I: Iterator<Item = &'a mut Box<Tile>>>(
8088 &mut self,
8089 tiles_iter: I,
8090 resource_cache: &mut ResourceCache,
8091 ) {
8092 if let CompositorKind::Native { .. } = self.compositor_kind {
8097 for tile in tiles_iter {
8098 if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
8102 if let Some(id) = id.take() {
8103 resource_cache.destroy_compositor_tile(id);
8104 }
8105 }
8106 }
8107 }
8108 }
8109}
8110
8111fn get_relative_scale_offset(
8112 child_spatial_node_index: SpatialNodeIndex,
8113 parent_spatial_node_index: SpatialNodeIndex,
8114 spatial_tree: &SpatialTree,
8115) -> ScaleOffset {
8116 let transform = spatial_tree.get_relative_transform(
8117 child_spatial_node_index,
8118 parent_spatial_node_index,
8119 );
8120 let mut scale_offset = match transform {
8121 CoordinateSpaceMapping::Local => ScaleOffset::identity(),
8122 CoordinateSpaceMapping::ScaleOffset(scale_offset) => scale_offset,
8123 CoordinateSpaceMapping::Transform(m) => {
8124 ScaleOffset::from_transform(&m).expect("bug: pictures caches don't support complex transforms")
8125 }
8126 };
8127
8128 scale_offset.offset = scale_offset.offset.round();
8132
8133 scale_offset
8134}
8135
8136pub fn calculate_screen_uv(
8137 p: DevicePoint,
8138 clipped: DeviceRect,
8139) -> DeviceHomogeneousVector {
8140 DeviceHomogeneousVector::new(
8142 (p.x - clipped.min.x) / (clipped.max.x - clipped.min.x),
8143 (p.y - clipped.min.y) / (clipped.max.y - clipped.min.y),
8144 0.0,
8145 1.0,
8146 )
8147}
8148
8149fn get_surface_rects(
8150 surface_index: SurfaceIndex,
8151 composite_mode: &PictureCompositeMode,
8152 parent_surface_index: SurfaceIndex,
8153 surfaces: &mut [SurfaceInfo],
8154 spatial_tree: &SpatialTree,
8155 max_surface_size: f32,
8156 force_scissor_rect: bool,
8157) -> Option<SurfaceAllocInfo> {
8158 let parent_surface = &surfaces[parent_surface_index.0];
8159
8160 let local_to_parent = SpaceMapper::new_with_target(
8161 parent_surface.surface_spatial_node_index,
8162 surfaces[surface_index.0].surface_spatial_node_index,
8163 parent_surface.clipping_rect,
8164 spatial_tree,
8165 );
8166
8167 let local_clip_rect = local_to_parent
8168 .unmap(&parent_surface.clipping_rect)
8169 .unwrap_or(PictureRect::max_rect())
8170 .cast_unit();
8171
8172 let surface = &mut surfaces[surface_index.0];
8173
8174 let (clipped_local, unclipped_local, source_local) = match composite_mode {
8175 PictureCompositeMode::SVGFEGraph(ref filters) => {
8176 let prim_subregion = composite_mode.get_rect(surface, None);
8188
8189 let visible_subregion: LayoutRect =
8192 prim_subregion.cast_unit()
8193 .intersection(&local_clip_rect)
8194 .unwrap_or(PictureRect::zero())
8195 .cast_unit();
8196
8197 if visible_subregion.is_empty() {
8201 return None;
8202 }
8203
8204 let source_potential_subregion = composite_mode.get_coverage_source_svgfe(
8209 filters, visible_subregion.cast_unit());
8210 let source_subregion =
8211 source_potential_subregion
8212 .intersection(&surface.unclipped_local_rect.cast_unit())
8213 .unwrap_or(LayoutRect::zero());
8214
8215 let coverage_subregion = source_subregion.union(&visible_subregion);
8221
8222 (coverage_subregion.cast_unit(), prim_subregion.cast_unit(), source_subregion.cast_unit())
8223 }
8224 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
8225 let local_prim_rect = surface.clipped_local_rect;
8226
8227 let mut required_local_rect = local_prim_rect
8228 .intersection(&local_clip_rect)
8229 .unwrap_or(PictureRect::zero());
8230
8231 for shadow in shadows {
8232 let (blur_radius_x, blur_radius_y) = surface.clamp_blur_radius(
8233 shadow.blur_radius,
8234 shadow.blur_radius,
8235 );
8236 let blur_inflation_x = blur_radius_x * BLUR_SAMPLE_SCALE;
8237 let blur_inflation_y = blur_radius_y * BLUR_SAMPLE_SCALE;
8238
8239 let local_shadow_rect = local_prim_rect
8240 .translate(shadow.offset.cast_unit())
8241 .inflate(blur_inflation_x, blur_inflation_y);
8242
8243 if let Some(clipped_shadow_rect) = local_clip_rect.intersection(&local_shadow_rect) {
8244 let required_shadow_rect = clipped_shadow_rect.inflate(blur_inflation_x, blur_inflation_y);
8245
8246 let local_clipped_shadow_rect = required_shadow_rect.translate(-shadow.offset.cast_unit());
8247
8248 required_local_rect = required_local_rect.union(&local_clipped_shadow_rect);
8249 }
8250 }
8251
8252 let unclipped = composite_mode.get_rect(surface, None);
8253 let clipped = required_local_rect;
8254
8255 let clipped = match clipped.intersection(&unclipped.cast_unit()) {
8256 Some(rect) => rect,
8257 None => return None,
8258 };
8259
8260 (clipped, unclipped, clipped)
8261 }
8262 _ => {
8263 let surface_origin = surface.clipped_local_rect.min.to_vector().cast_unit();
8264
8265 let normalized_prim_rect = composite_mode
8266 .get_rect(surface, None)
8267 .translate(-surface_origin);
8268
8269 let normalized_clip_rect = local_clip_rect
8270 .cast_unit()
8271 .translate(-surface_origin);
8272
8273 let norm_clipped_rect = match normalized_prim_rect.intersection(&normalized_clip_rect) {
8274 Some(rect) => rect,
8275 None => return None,
8276 };
8277
8278 let norm_clipped_rect = composite_mode.get_rect(surface, Some(norm_clipped_rect));
8279
8280 let norm_clipped_rect = match norm_clipped_rect.intersection(&normalized_prim_rect) {
8281 Some(rect) => rect,
8282 None => return None,
8283 };
8284
8285 let unclipped = normalized_prim_rect.translate(surface_origin);
8286 let clipped = norm_clipped_rect.translate(surface_origin);
8287
8288 (clipped.cast_unit(), unclipped.cast_unit(), clipped.cast_unit())
8289 }
8290 };
8291
8292 let (mut clipped, mut unclipped, mut source) = if surface.raster_spatial_node_index != surface.surface_spatial_node_index {
8296 assert_eq!(surface.device_pixel_scale.0, 1.0);
8298
8299 let local_to_world = SpaceMapper::new_with_target(
8300 spatial_tree.root_reference_frame_index(),
8301 surface.surface_spatial_node_index,
8302 WorldRect::max_rect(),
8303 spatial_tree,
8304 );
8305
8306 let clipped = local_to_world.map(&clipped_local.cast_unit()).unwrap() * surface.device_pixel_scale;
8307 let unclipped = local_to_world.map(&unclipped_local).unwrap() * surface.device_pixel_scale;
8308 let source = local_to_world.map(&source_local.cast_unit()).unwrap() * surface.device_pixel_scale;
8309
8310 (clipped, unclipped, source)
8311 } else {
8312 let clipped = clipped_local.cast_unit() * surface.device_pixel_scale;
8314 let unclipped = unclipped_local.cast_unit() * surface.device_pixel_scale;
8315 let source = source_local.cast_unit() * surface.device_pixel_scale;
8316
8317 (clipped, unclipped, source)
8318 };
8319 let mut clipped_snapped = clipped.round_out();
8320 let mut source_snapped = source.round_out();
8321
8322 let max_dimension =
8335 clipped_snapped.width().max(
8336 clipped_snapped.height().max(
8337 source_snapped.width().max(
8338 source_snapped.height()
8339 ))).ceil();
8340 if max_dimension > max_surface_size {
8341 let max_dimension =
8344 clipped_local.width().max(
8345 clipped_local.height().max(
8346 source_local.width().max(
8347 source_local.height()
8348 ))).ceil();
8349 surface.raster_spatial_node_index = surface.surface_spatial_node_index;
8350 surface.device_pixel_scale = Scale::new(max_surface_size / max_dimension);
8351 surface.local_scale = (1.0, 1.0);
8352
8353 let add_markers = profiler::thread_is_being_profiled();
8354 if add_markers {
8355 let new_clipped = (clipped_local.cast_unit() * surface.device_pixel_scale).round();
8356 let new_source = (source_local.cast_unit() * surface.device_pixel_scale).round();
8357 profiler::add_text_marker("SurfaceSizeLimited",
8358 format!("Surface for {:?} reduced from raster {:?} (source {:?}) to local {:?} (source {:?})",
8359 composite_mode.kind(),
8360 clipped.size(), source.size(),
8361 new_clipped, new_source).as_str(),
8362 Duration::from_secs_f32(new_clipped.width() * new_clipped.height() / 1000000000.0));
8363 }
8364
8365 clipped = clipped_local.cast_unit() * surface.device_pixel_scale;
8366 unclipped = unclipped_local.cast_unit() * surface.device_pixel_scale;
8367 source = source_local.cast_unit() * surface.device_pixel_scale;
8368 clipped_snapped = clipped.round();
8369 source_snapped = source.round();
8370 }
8371
8372 let task_size = clipped_snapped.size().to_i32();
8373 let task_size = task_size.min(DeviceIntSize::new(max_surface_size as i32, max_surface_size as i32));
8379 debug_assert!(
8380 task_size.width <= max_surface_size as i32 &&
8381 task_size.height <= max_surface_size as i32,
8382 "task_size {:?} for {:?} must be within max_surface_size {}",
8383 task_size,
8384 composite_mode.kind(),
8385 max_surface_size);
8386
8387 let uv_rect_kind = calculate_uv_rect_kind(
8388 clipped_snapped,
8389 unclipped,
8390 );
8391
8392 if task_size.width == 0 || task_size.height == 0 {
8394 return None;
8395 }
8396
8397 let needs_scissor_rect = force_scissor_rect || !clipped_local.contains_box(&surface.unclipped_local_rect);
8404
8405 Some(SurfaceAllocInfo {
8406 task_size,
8407 needs_scissor_rect,
8408 clipped: clipped_snapped,
8409 unclipped,
8410 source: source_snapped,
8411 clipped_notsnapped: clipped,
8412 clipped_local,
8413 uv_rect_kind,
8414 })
8415}
8416
8417pub fn calculate_uv_rect_kind(
8418 clipped: DeviceRect,
8419 unclipped: DeviceRect,
8420) -> UvRectKind {
8421 let top_left = calculate_screen_uv(
8422 unclipped.top_left().cast_unit(),
8423 clipped,
8424 );
8425
8426 let top_right = calculate_screen_uv(
8427 unclipped.top_right().cast_unit(),
8428 clipped,
8429 );
8430
8431 let bottom_left = calculate_screen_uv(
8432 unclipped.bottom_left().cast_unit(),
8433 clipped,
8434 );
8435
8436 let bottom_right = calculate_screen_uv(
8437 unclipped.bottom_right().cast_unit(),
8438 clipped,
8439 );
8440
8441 UvRectKind::Quad {
8442 top_left,
8443 top_right,
8444 bottom_left,
8445 bottom_right,
8446 }
8447}
8448
8449#[test]
8450fn test_large_surface_scale_1() {
8451 use crate::spatial_tree::{SceneSpatialTree, SpatialTree};
8452
8453 let mut cst = SceneSpatialTree::new();
8454 let root_reference_frame_index = cst.root_reference_frame_index();
8455
8456 let mut spatial_tree = SpatialTree::new();
8457 spatial_tree.apply_updates(cst.end_frame_and_get_pending_updates());
8458 spatial_tree.update_tree(&SceneProperties::new());
8459
8460 let map_local_to_picture = SpaceMapper::new_with_target(
8461 root_reference_frame_index,
8462 root_reference_frame_index,
8463 PictureRect::max_rect(),
8464 &spatial_tree,
8465 );
8466
8467 let mut surfaces = vec![
8468 SurfaceInfo {
8469 unclipped_local_rect: PictureRect::max_rect(),
8470 clipped_local_rect: PictureRect::max_rect(),
8471 is_opaque: true,
8472 clipping_rect: PictureRect::max_rect(),
8473 culling_rect: VisRect::max_rect(),
8474 map_local_to_picture: map_local_to_picture.clone(),
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 },
8484 SurfaceInfo {
8485 unclipped_local_rect: PictureRect::new(
8486 PicturePoint::new(52.76350021362305, 0.0),
8487 PicturePoint::new(159.6738739013672, 35.0),
8488 ),
8489 clipped_local_rect: PictureRect::max_rect(),
8490 is_opaque: true,
8491 clipping_rect: PictureRect::max_rect(),
8492 culling_rect: VisRect::max_rect(),
8493 map_local_to_picture,
8494 raster_spatial_node_index: root_reference_frame_index,
8495 surface_spatial_node_index: root_reference_frame_index,
8496 visibility_spatial_node_index: root_reference_frame_index,
8497 device_pixel_scale: DevicePixelScale::new(43.82798767089844),
8498 world_scale_factors: (1.0, 1.0),
8499 local_scale: (1.0, 1.0),
8500 allow_snapping: true,
8501 force_scissor_rect: false,
8502 },
8503 ];
8504
8505 get_surface_rects(
8506 SurfaceIndex(1),
8507 &PictureCompositeMode::Blit(BlitReason::BLEND_MODE),
8508 SurfaceIndex(0),
8509 &mut surfaces,
8510 &spatial_tree,
8511 MAX_SURFACE_SIZE as f32,
8512 false,
8513 );
8514}
8515
8516#[test]
8517fn test_drop_filter_dirty_region_outside_prim() {
8518 use api::Shadow;
8524 use crate::spatial_tree::{SceneSpatialTree, SpatialTree};
8525
8526 let mut cst = SceneSpatialTree::new();
8527 let root_reference_frame_index = cst.root_reference_frame_index();
8528
8529 let mut spatial_tree = SpatialTree::new();
8530 spatial_tree.apply_updates(cst.end_frame_and_get_pending_updates());
8531 spatial_tree.update_tree(&SceneProperties::new());
8532
8533 let map_local_to_picture = SpaceMapper::new_with_target(
8534 root_reference_frame_index,
8535 root_reference_frame_index,
8536 PictureRect::max_rect(),
8537 &spatial_tree,
8538 );
8539
8540 let mut surfaces = vec![
8541 SurfaceInfo {
8542 unclipped_local_rect: PictureRect::max_rect(),
8543 clipped_local_rect: PictureRect::max_rect(),
8544 is_opaque: true,
8545 clipping_rect: PictureRect::max_rect(),
8546 map_local_to_picture: map_local_to_picture.clone(),
8547 raster_spatial_node_index: root_reference_frame_index,
8548 surface_spatial_node_index: root_reference_frame_index,
8549 visibility_spatial_node_index: root_reference_frame_index,
8550 device_pixel_scale: DevicePixelScale::new(1.0),
8551 world_scale_factors: (1.0, 1.0),
8552 local_scale: (1.0, 1.0),
8553 allow_snapping: true,
8554 force_scissor_rect: false,
8555 culling_rect: VisRect::max_rect(),
8556 },
8557 SurfaceInfo {
8558 unclipped_local_rect: PictureRect::new(
8559 PicturePoint::new(0.0, 0.0),
8560 PicturePoint::new(750.0, 450.0),
8561 ),
8562 clipped_local_rect: PictureRect::new(
8563 PicturePoint::new(0.0, 0.0),
8564 PicturePoint::new(750.0, 450.0),
8565 ),
8566 is_opaque: true,
8567 clipping_rect: PictureRect::max_rect(),
8568 map_local_to_picture,
8569 raster_spatial_node_index: root_reference_frame_index,
8570 surface_spatial_node_index: root_reference_frame_index,
8571 visibility_spatial_node_index: root_reference_frame_index,
8572 device_pixel_scale: DevicePixelScale::new(1.0),
8573 world_scale_factors: (1.0, 1.0),
8574 local_scale: (1.0, 1.0),
8575 allow_snapping: true,
8576 force_scissor_rect: false,
8577 culling_rect: VisRect::max_rect(),
8578 },
8579 ];
8580
8581 let shadows = smallvec![
8582 Shadow {
8583 offset: LayoutVector2D::zero(),
8584 color: ColorF::BLACK,
8585 blur_radius: 75.0,
8586 },
8587 ];
8588
8589 let composite_mode = PictureCompositeMode::Filter(Filter::DropShadows(shadows));
8590
8591 let info = get_surface_rects(
8593 SurfaceIndex(1),
8594 &composite_mode,
8595 SurfaceIndex(0),
8596 &mut surfaces,
8597 &spatial_tree,
8598 MAX_SURFACE_SIZE as f32,
8599 false,
8600 ).expect("No surface rect");
8601 assert_eq!(info.task_size, DeviceIntSize::new(1200, 900));
8602
8603 surfaces[0].clipping_rect = PictureRect::new(
8605 PicturePoint::new(768.0, 128.0),
8606 PicturePoint::new(1024.0, 256.0),
8607 );
8608 let info = get_surface_rects(
8609 SurfaceIndex(1),
8610 &composite_mode,
8611 SurfaceIndex(0),
8612 &mut surfaces,
8613 &spatial_tree,
8614 MAX_SURFACE_SIZE as f32,
8615 false,
8616 ).expect("No surface rect");
8617 assert_eq!(info.task_size, DeviceIntSize::new(432, 578));
8618}
8619
8620fn request_render_task(
8621 frame_state: &mut FrameBuildingState,
8622 snapshot: &Option<SnapshotInfo>,
8623 surface_rects: &SurfaceAllocInfo,
8624 is_opaque: bool,
8625 f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF, &mut GpuCache) -> RenderTaskId,
8626) -> RenderTaskId {
8627
8628 let task_id = match snapshot {
8629 Some(info) => {
8630 let adjustment = AdjustedImageSource::from_rects(
8631 &info.area,
8632 &surface_rects.clipped_local.cast_unit()
8633 );
8634 let task_id = frame_state.resource_cache.render_as_image(
8635 info.key.as_image(),
8636 surface_rects.task_size,
8637 frame_state.rg_builder,
8638 &mut frame_state.frame_gpu_data.f32,
8639 frame_state.gpu_cache,
8640 is_opaque,
8641 &adjustment,
8642 f
8643 );
8644
8645 frame_state.surface_builder.add_child_render_task(
8650 task_id,
8651 frame_state.rg_builder,
8652 );
8653
8654 frame_state.image_dependencies.insert(info.key.as_image(), task_id);
8655
8656 task_id
8657 }
8658 None => {
8659 f(
8660 frame_state.rg_builder,
8661 &mut frame_state.frame_gpu_data.f32,
8662 frame_state.gpu_cache
8663 )
8664 }
8665 };
8666
8667 task_id
8668}