1use api::{ColorF, DocumentId, ExternalImageId, PrimitiveFlags, Parameter, RenderReasons};
6use api::{ImageFormat, NotificationRequest, Shadow, FilterOpGraphPictureBufferId, FilterOpGraphPictureReference, FilterOpGraphNode, FilterOp, ImageBufferKind};
7use api::FramePublishId;
8use api::units::*;
9use crate::render_api::DebugCommand;
10use crate::composite::NativeSurfaceOperation;
11use crate::device::TextureFilter;
12use crate::renderer::{FullFrameStats, PipelineInfo};
13use crate::gpu_cache::GpuCacheUpdateList;
14use crate::frame_builder::Frame;
15use crate::profiler::TransactionProfile;
16use crate::spatial_tree::SpatialNodeIndex;
17use crate::prim_store::PrimitiveInstanceIndex;
18use crate::filterdata::FilterDataHandle;
19use fxhash::FxHasher;
20use plane_split::BspSplitter;
21use smallvec::SmallVec;
22use std::{usize, i32};
23use std::collections::{HashMap, HashSet};
24use std::f32;
25use std::hash::BuildHasherDefault;
26use std::path::PathBuf;
27use std::sync::Arc;
28use std::time::{UNIX_EPOCH, SystemTime};
29use peek_poke::PeekPoke;
30
31#[cfg(any(feature = "capture", feature = "replay"))]
32use crate::capture::CaptureConfig;
33#[cfg(feature = "capture")]
34use crate::capture::ExternalCaptureImage;
35#[cfg(feature = "replay")]
36use crate::capture::PlainExternalImage;
37
38pub use crate::frame_allocator::{FrameAllocator, FrameMemory};
39pub type FrameVec<T> = allocator_api2::vec::Vec<T, FrameAllocator>;
40pub fn size_of_frame_vec<T>(vec: &FrameVec<T>) -> usize {
41 vec.capacity() * std::mem::size_of::<T>()
42}
43
44pub type FastHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
45pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
46
47#[derive(Copy, Clone, Hash, MallocSizeOf, PartialEq, PartialOrd, Debug, Eq, Ord, PeekPoke)]
48#[cfg_attr(feature = "capture", derive(Serialize))]
49#[cfg_attr(feature = "replay", derive(Deserialize))]
50pub struct FrameId(u64);
51
52impl FrameId {
53 pub fn first() -> Self {
61 FrameId(0)
62 }
63
64 pub fn as_u64(&self) -> u64 {
66 self.0
67 }
68
69 pub fn advance(&mut self) {
71 self.0 += 1;
72 }
73
74 pub const INVALID: FrameId = FrameId(0);
77}
78
79impl Default for FrameId {
80 fn default() -> Self {
81 FrameId::INVALID
82 }
83}
84
85impl ::std::ops::Add<u64> for FrameId {
86 type Output = Self;
87 fn add(self, other: u64) -> FrameId {
88 FrameId(self.0 + other)
89 }
90}
91
92impl ::std::ops::Sub<u64> for FrameId {
93 type Output = Self;
94 fn sub(self, other: u64) -> FrameId {
95 assert!(self.0 >= other, "Underflow subtracting FrameIds");
96 FrameId(self.0 - other)
97 }
98}
99
100#[derive(Copy, Clone, Debug, MallocSizeOf)]
108#[cfg_attr(feature = "capture", derive(Serialize))]
109#[cfg_attr(feature = "replay", derive(Deserialize))]
110pub struct FrameStamp {
111 id: FrameId,
112 time: SystemTime,
113 document_id: DocumentId,
114}
115
116impl Eq for FrameStamp {}
117
118impl PartialEq for FrameStamp {
119 fn eq(&self, other: &Self) -> bool {
120 debug_assert!(self.document_id == other.document_id);
122 self.id == other.id
123 }
124}
125
126impl PartialOrd for FrameStamp {
127 fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
128 self.id.partial_cmp(&other.id)
129 }
130}
131
132impl FrameStamp {
133 pub fn frame_id(&self) -> FrameId {
135 self.id
136 }
137
138 pub fn time(&self) -> SystemTime {
140 self.time
141 }
142
143 pub fn document_id(&self) -> DocumentId {
145 self.document_id
146 }
147
148 pub fn is_valid(&self) -> bool {
149 debug_assert!((self.time != UNIX_EPOCH && self.id != FrameId(0) && self.document_id != DocumentId::INVALID) ||
151 *self == Self::INVALID);
152 self.document_id != DocumentId::INVALID
153 }
154
155 pub fn first(document_id: DocumentId) -> Self {
157 FrameStamp {
158 id: FrameId::first(),
159 time: SystemTime::now(),
160 document_id,
161 }
162 }
163
164 pub fn advance(&mut self) {
166 self.id.advance();
167 self.time = SystemTime::now();
168 }
169
170 pub const INVALID: FrameStamp = FrameStamp {
172 id: FrameId(0),
173 time: UNIX_EPOCH,
174 document_id: DocumentId::INVALID,
175 };
176}
177
178#[derive(Copy, Clone, Debug)]
180#[cfg_attr(feature = "capture", derive(Serialize))]
181pub struct PlaneSplitAnchor {
182 pub spatial_node_index: SpatialNodeIndex,
183 pub instance_index: PrimitiveInstanceIndex,
184}
185
186impl PlaneSplitAnchor {
187 pub fn new(
188 spatial_node_index: SpatialNodeIndex,
189 instance_index: PrimitiveInstanceIndex,
190 ) -> Self {
191 PlaneSplitAnchor {
192 spatial_node_index,
193 instance_index,
194 }
195 }
196}
197
198impl Default for PlaneSplitAnchor {
199 fn default() -> Self {
200 PlaneSplitAnchor {
201 spatial_node_index: SpatialNodeIndex::INVALID,
202 instance_index: PrimitiveInstanceIndex(!0),
203 }
204 }
205}
206
207pub type PlaneSplitter = BspSplitter<PlaneSplitAnchor>;
209
210#[derive(Debug, Copy, Clone)]
212#[cfg_attr(feature = "capture", derive(Serialize))]
213pub struct PlaneSplitterIndex(pub usize);
214
215const OPACITY_EPSILON: f32 = 0.001;
217
218#[derive(Clone, Copy, Debug)]
219#[cfg_attr(feature = "capture", derive(Serialize))]
220#[cfg_attr(feature = "replay", derive(Deserialize))]
221pub struct FilterGraphPictureReference {
222 pub buffer_id: FilterOpGraphPictureBufferId,
226 pub subregion: LayoutRect,
229 pub offset: LayoutVector2D,
236 pub inflate: i16,
238 pub source_padding: LayoutRect,
242 pub target_padding: LayoutRect,
248}
249
250impl From<FilterOpGraphPictureReference> for FilterGraphPictureReference {
251 fn from(pic: FilterOpGraphPictureReference) -> Self {
252 FilterGraphPictureReference{
253 buffer_id: pic.buffer_id,
254 subregion: LayoutRect::zero(),
256 offset: LayoutVector2D::zero(),
257 inflate: 0,
258 source_padding: LayoutRect::zero(),
259 target_padding: LayoutRect::zero(),
260 }
261 }
262}
263
264pub const SVGFE_CONVOLVE_DIAMETER_LIMIT: usize = 5;
265pub const SVGFE_CONVOLVE_VALUES_LIMIT: usize = SVGFE_CONVOLVE_DIAMETER_LIMIT *
266 SVGFE_CONVOLVE_DIAMETER_LIMIT;
267
268#[derive(Clone, Debug)]
269#[cfg_attr(feature = "capture", derive(Serialize))]
270#[cfg_attr(feature = "replay", derive(Deserialize))]
271pub enum FilterGraphOp {
272 SVGFESourceGraphic,
278 SVGFESourceAlpha,
284 SVGFEIdentity,
290 SVGFEOpacity{valuebinding: api::PropertyBinding<f32>, value: f32},
296 SVGFEToAlpha,
299 SVGFEBlendDarken,
305 SVGFEBlendLighten,
311 SVGFEBlendMultiply,
317 SVGFEBlendNormal,
323 SVGFEBlendScreen,
329 SVGFEBlendOverlay,
335 SVGFEBlendColorDodge,
341 SVGFEBlendColorBurn,
347 SVGFEBlendHardLight,
353 SVGFEBlendSoftLight,
359 SVGFEBlendDifference,
365 SVGFEBlendExclusion,
371 SVGFEBlendHue,
377 SVGFEBlendSaturation,
383 SVGFEBlendColor,
389 SVGFEBlendLuminosity,
395 SVGFEColorMatrix{values: [f32; 20]},
402 SVGFEComponentTransfer,
409 SVGFEComponentTransferInterned{handle: FilterDataHandle, creates_pixels: bool},
414 SVGFECompositeArithmetic{k1: f32, k2: f32, k3: f32, k4: f32},
421 SVGFECompositeATop,
428 SVGFECompositeIn,
435 SVGFECompositeLighter,
442 SVGFECompositeOut,
449 SVGFECompositeOver,
456 SVGFECompositeXOR,
463 SVGFEConvolveMatrixEdgeModeDuplicate{order_x: i32, order_y: i32,
472 kernel: [f32; SVGFE_CONVOLVE_VALUES_LIMIT], divisor: f32, bias: f32,
473 target_x: i32, target_y: i32, kernel_unit_length_x: f32,
474 kernel_unit_length_y: f32, preserve_alpha: i32},
475 SVGFEConvolveMatrixEdgeModeNone{order_x: i32, order_y: i32,
484 kernel: [f32; SVGFE_CONVOLVE_VALUES_LIMIT], divisor: f32, bias: f32,
485 target_x: i32, target_y: i32, kernel_unit_length_x: f32,
486 kernel_unit_length_y: f32, preserve_alpha: i32},
487 SVGFEConvolveMatrixEdgeModeWrap{order_x: i32, order_y: i32,
496 kernel: [f32; SVGFE_CONVOLVE_VALUES_LIMIT], divisor: f32, bias: f32,
497 target_x: i32, target_y: i32, kernel_unit_length_x: f32,
498 kernel_unit_length_y: f32, preserve_alpha: i32},
499 SVGFEDiffuseLightingDistant{surface_scale: f32, diffuse_constant: f32,
508 kernel_unit_length_x: f32, kernel_unit_length_y: f32, azimuth: f32,
509 elevation: f32},
510 SVGFEDiffuseLightingPoint{surface_scale: f32, diffuse_constant: f32,
519 kernel_unit_length_x: f32, kernel_unit_length_y: f32, x: f32, y: f32,
520 z: f32},
521 SVGFEDiffuseLightingSpot{surface_scale: f32, diffuse_constant: f32,
532 kernel_unit_length_x: f32, kernel_unit_length_y: f32, x: f32, y: f32,
533 z: f32, points_at_x: f32, points_at_y: f32, points_at_z: f32,
534 cone_exponent: f32, limiting_cone_angle: f32},
535 SVGFEDisplacementMap{scale: f32, x_channel_selector: u32,
542 y_channel_selector: u32},
543 SVGFEDropShadow{color: ColorF, dx: f32, dy: f32, std_deviation_x: f32,
551 std_deviation_y: f32},
552 SVGFEFlood{color: ColorF},
558 SVGFEGaussianBlur{std_deviation_x: f32, std_deviation_y: f32},
564 SVGFEImage{sampling_filter: u32, matrix: [f32; 6]},
571 SVGFEMorphologyDilate{radius_x: f32, radius_y: f32},
578 SVGFEMorphologyErode{radius_x: f32, radius_y: f32},
585 SVGFESpecularLightingDistant{surface_scale: f32, specular_constant: f32,
594 specular_exponent: f32, kernel_unit_length_x: f32,
595 kernel_unit_length_y: f32, azimuth: f32, elevation: f32},
596 SVGFESpecularLightingPoint{surface_scale: f32, specular_constant: f32,
605 specular_exponent: f32, kernel_unit_length_x: f32,
606 kernel_unit_length_y: f32, x: f32, y: f32, z: f32},
607 SVGFESpecularLightingSpot{surface_scale: f32, specular_constant: f32,
618 specular_exponent: f32, kernel_unit_length_x: f32,
619 kernel_unit_length_y: f32, x: f32, y: f32, z: f32, points_at_x: f32,
620 points_at_y: f32, points_at_z: f32, cone_exponent: f32,
621 limiting_cone_angle: f32},
622 SVGFETile,
629 SVGFETurbulenceWithFractalNoiseWithNoStitching{base_frequency_x: f32,
637 base_frequency_y: f32, num_octaves: u32, seed: u32},
638 SVGFETurbulenceWithFractalNoiseWithStitching{base_frequency_x: f32,
646 base_frequency_y: f32, num_octaves: u32, seed: u32},
647 SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{base_frequency_x: f32,
654 base_frequency_y: f32, num_octaves: u32, seed: u32},
655 SVGFETurbulenceWithTurbulenceNoiseWithStitching{base_frequency_x: f32,
662 base_frequency_y: f32, num_octaves: u32, seed: u32},
663}
664
665impl FilterGraphOp {
666 pub fn kind(&self) -> &'static str {
667 match *self {
668 FilterGraphOp::SVGFEBlendColor => "SVGFEBlendColor",
669 FilterGraphOp::SVGFEBlendColorBurn => "SVGFEBlendColorBurn",
670 FilterGraphOp::SVGFEBlendColorDodge => "SVGFEBlendColorDodge",
671 FilterGraphOp::SVGFEBlendDarken => "SVGFEBlendDarken",
672 FilterGraphOp::SVGFEBlendDifference => "SVGFEBlendDifference",
673 FilterGraphOp::SVGFEBlendExclusion => "SVGFEBlendExclusion",
674 FilterGraphOp::SVGFEBlendHardLight => "SVGFEBlendHardLight",
675 FilterGraphOp::SVGFEBlendHue => "SVGFEBlendHue",
676 FilterGraphOp::SVGFEBlendLighten => "SVGFEBlendLighten",
677 FilterGraphOp::SVGFEBlendLuminosity => "SVGFEBlendLuminosity",
678 FilterGraphOp::SVGFEBlendMultiply => "SVGFEBlendMultiply",
679 FilterGraphOp::SVGFEBlendNormal => "SVGFEBlendNormal",
680 FilterGraphOp::SVGFEBlendOverlay => "SVGFEBlendOverlay",
681 FilterGraphOp::SVGFEBlendSaturation => "SVGFEBlendSaturation",
682 FilterGraphOp::SVGFEBlendScreen => "SVGFEBlendScreen",
683 FilterGraphOp::SVGFEBlendSoftLight => "SVGFEBlendSoftLight",
684 FilterGraphOp::SVGFEColorMatrix{..} => "SVGFEColorMatrix",
685 FilterGraphOp::SVGFEComponentTransfer => "SVGFEComponentTransfer",
686 FilterGraphOp::SVGFEComponentTransferInterned{..} => "SVGFEComponentTransferInterned",
687 FilterGraphOp::SVGFECompositeArithmetic{..} => "SVGFECompositeArithmetic",
688 FilterGraphOp::SVGFECompositeATop => "SVGFECompositeATop",
689 FilterGraphOp::SVGFECompositeIn => "SVGFECompositeIn",
690 FilterGraphOp::SVGFECompositeLighter => "SVGFECompositeLighter",
691 FilterGraphOp::SVGFECompositeOut => "SVGFECompositeOut",
692 FilterGraphOp::SVGFECompositeOver => "SVGFECompositeOver",
693 FilterGraphOp::SVGFECompositeXOR => "SVGFECompositeXOR",
694 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{..} => "SVGFEConvolveMatrixEdgeModeDuplicate",
695 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{..} => "SVGFEConvolveMatrixEdgeModeNone",
696 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{..} => "SVGFEConvolveMatrixEdgeModeWrap",
697 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => "SVGFEDiffuseLightingDistant",
698 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => "SVGFEDiffuseLightingPoint",
699 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => "SVGFEDiffuseLightingSpot",
700 FilterGraphOp::SVGFEDisplacementMap{..} => "SVGFEDisplacementMap",
701 FilterGraphOp::SVGFEDropShadow{..} => "SVGFEDropShadow",
702 FilterGraphOp::SVGFEFlood{..} => "SVGFEFlood",
703 FilterGraphOp::SVGFEGaussianBlur{..} => "SVGFEGaussianBlur",
704 FilterGraphOp::SVGFEIdentity => "SVGFEIdentity",
705 FilterGraphOp::SVGFEImage{..} => "SVGFEImage",
706 FilterGraphOp::SVGFEMorphologyDilate{..} => "SVGFEMorphologyDilate",
707 FilterGraphOp::SVGFEMorphologyErode{..} => "SVGFEMorphologyErode",
708 FilterGraphOp::SVGFEOpacity{..} => "SVGFEOpacity",
709 FilterGraphOp::SVGFESourceAlpha => "SVGFESourceAlpha",
710 FilterGraphOp::SVGFESourceGraphic => "SVGFESourceGraphic",
711 FilterGraphOp::SVGFESpecularLightingDistant{..} => "SVGFESpecularLightingDistant",
712 FilterGraphOp::SVGFESpecularLightingPoint{..} => "SVGFESpecularLightingPoint",
713 FilterGraphOp::SVGFESpecularLightingSpot{..} => "SVGFESpecularLightingSpot",
714 FilterGraphOp::SVGFETile => "SVGFETile",
715 FilterGraphOp::SVGFEToAlpha => "SVGFEToAlpha",
716 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} => "SVGFETurbulenceWithFractalNoiseWithNoStitching",
717 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} => "SVGFETurbulenceWithFractalNoiseWithStitching",
718 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} => "SVGFETurbulenceWithTurbulenceNoiseWithNoStitching",
719 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => "SVGFETurbulenceWithTurbulenceNoiseWithStitching",
720 }
721 }
722}
723
724#[derive(Clone, Debug)]
725#[cfg_attr(feature = "capture", derive(Serialize))]
726#[cfg_attr(feature = "replay", derive(Deserialize))]
727pub struct FilterGraphNode {
728 pub kept_by_optimizer: bool,
730 pub linear: bool,
734 pub inflate: i16,
737 pub inputs: Vec<FilterGraphPictureReference>,
740 pub subregion: LayoutRect,
742}
743
744impl From<FilterOpGraphNode> for FilterGraphNode {
745 fn from(node: FilterOpGraphNode) -> Self {
746 let mut inputs: Vec<FilterGraphPictureReference> = Vec::new();
747 if node.input.buffer_id != FilterOpGraphPictureBufferId::None {
748 inputs.push(node.input.into());
749 }
750 if node.input2.buffer_id != FilterOpGraphPictureBufferId::None {
751 inputs.push(node.input2.into());
752 }
753 FilterGraphNode{
756 linear: node.linear,
757 inputs,
758 subregion: node.subregion,
759 kept_by_optimizer: true,
761 inflate: 0,
762 }
763 }
764}
765
766
767#[derive(Clone, Debug)]
769#[cfg_attr(feature = "capture", derive(Serialize))]
770#[cfg_attr(feature = "replay", derive(Deserialize))]
771pub enum Filter {
772 Identity,
773 Blur {
774 width: f32,
775 height: f32,
776 should_inflate: bool,
777 },
778 Brightness(f32),
779 Contrast(f32),
780 Grayscale(f32),
781 HueRotate(f32),
782 Invert(f32),
783 Opacity(api::PropertyBinding<f32>, f32),
784 Saturate(f32),
785 Sepia(f32),
786 DropShadows(SmallVec<[Shadow; 1]>),
787 ColorMatrix(Box<[f32; 20]>),
788 SrgbToLinear,
789 LinearToSrgb,
790 ComponentTransfer,
791 Flood(ColorF),
792 SVGGraphNode(FilterGraphNode, FilterGraphOp),
793}
794
795impl Filter {
796 pub fn is_visible(&self) -> bool {
797 match *self {
798 Filter::Identity |
799 Filter::Blur { .. } |
800 Filter::Brightness(..) |
801 Filter::Contrast(..) |
802 Filter::Grayscale(..) |
803 Filter::HueRotate(..) |
804 Filter::Invert(..) |
805 Filter::Saturate(..) |
806 Filter::Sepia(..) |
807 Filter::DropShadows(..) |
808 Filter::ColorMatrix(..) |
809 Filter::SrgbToLinear |
810 Filter::LinearToSrgb |
811 Filter::ComponentTransfer => true,
812 Filter::Opacity(_, amount) => {
813 amount > OPACITY_EPSILON
814 },
815 Filter::Flood(color) => {
816 color.a > OPACITY_EPSILON
817 }
818 Filter::SVGGraphNode(..) => true,
819 }
820 }
821
822 pub fn is_noop(&self) -> bool {
823 match *self {
824 Filter::Identity => false, Filter::Blur { width, height, .. } => width == 0.0 && height == 0.0,
826 Filter::Brightness(amount) => amount == 1.0,
827 Filter::Contrast(amount) => amount == 1.0,
828 Filter::Grayscale(amount) => amount == 0.0,
829 Filter::HueRotate(amount) => amount == 0.0,
830 Filter::Invert(amount) => amount == 0.0,
831 Filter::Opacity(api::PropertyBinding::Value(amount), _) => amount >= 1.0,
832 Filter::Saturate(amount) => amount == 1.0,
833 Filter::Sepia(amount) => amount == 0.0,
834 Filter::DropShadows(ref shadows) => {
835 for shadow in shadows {
836 if shadow.offset.x != 0.0 || shadow.offset.y != 0.0 || shadow.blur_radius != 0.0 {
837 return false;
838 }
839 }
840
841 true
842 }
843 Filter::ColorMatrix(ref matrix) => {
844 **matrix == [
845 1.0, 0.0, 0.0, 0.0,
846 0.0, 1.0, 0.0, 0.0,
847 0.0, 0.0, 1.0, 0.0,
848 0.0, 0.0, 0.0, 1.0,
849 0.0, 0.0, 0.0, 0.0
850 ]
851 }
852 Filter::Opacity(api::PropertyBinding::Binding(..), _) |
853 Filter::SrgbToLinear |
854 Filter::LinearToSrgb |
855 Filter::ComponentTransfer |
856 Filter::Flood(..) => false,
857 Filter::SVGGraphNode(..) => false,
858 }
859 }
860
861
862 pub fn as_int(&self) -> i32 {
863 match *self {
865 Filter::Identity => 0, Filter::Contrast(..) => 0,
867 Filter::Grayscale(..) => 1,
868 Filter::HueRotate(..) => 2,
869 Filter::Invert(..) => 3,
870 Filter::Saturate(..) => 4,
871 Filter::Sepia(..) => 5,
872 Filter::Brightness(..) => 6,
873 Filter::ColorMatrix(..) => 7,
874 Filter::SrgbToLinear => 8,
875 Filter::LinearToSrgb => 9,
876 Filter::Flood(..) => 10,
877 Filter::ComponentTransfer => 11,
878 Filter::Blur { .. } => 12,
879 Filter::DropShadows(..) => 13,
880 Filter::Opacity(..) => 14,
881 Filter::SVGGraphNode(..) => unreachable!("SVGGraphNode handled elsewhere"),
882 }
883 }
884}
885
886impl From<FilterOp> for Filter {
887 fn from(op: FilterOp) -> Self {
888 match op {
889 FilterOp::Identity => Filter::Identity,
890 FilterOp::Blur(width, height) => Filter::Blur { width, height, should_inflate: true },
891 FilterOp::Brightness(b) => Filter::Brightness(b),
892 FilterOp::Contrast(c) => Filter::Contrast(c),
893 FilterOp::Grayscale(g) => Filter::Grayscale(g),
894 FilterOp::HueRotate(h) => Filter::HueRotate(h),
895 FilterOp::Invert(i) => Filter::Invert(i),
896 FilterOp::Opacity(binding, opacity) => Filter::Opacity(binding, opacity),
897 FilterOp::Saturate(s) => Filter::Saturate(s),
898 FilterOp::Sepia(s) => Filter::Sepia(s),
899 FilterOp::ColorMatrix(mat) => Filter::ColorMatrix(Box::new(mat)),
900 FilterOp::SrgbToLinear => Filter::SrgbToLinear,
901 FilterOp::LinearToSrgb => Filter::LinearToSrgb,
902 FilterOp::ComponentTransfer => Filter::ComponentTransfer,
903 FilterOp::DropShadow(shadow) => Filter::DropShadows(smallvec![shadow]),
904 FilterOp::Flood(color) => Filter::Flood(color),
905 FilterOp::SVGFEBlendColor{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendColor),
906 FilterOp::SVGFEBlendColorBurn{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendColorBurn),
907 FilterOp::SVGFEBlendColorDodge{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendColorDodge),
908 FilterOp::SVGFEBlendDarken{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendDarken),
909 FilterOp::SVGFEBlendDifference{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendDifference),
910 FilterOp::SVGFEBlendExclusion{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendExclusion),
911 FilterOp::SVGFEBlendHardLight{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendHardLight),
912 FilterOp::SVGFEBlendHue{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendHue),
913 FilterOp::SVGFEBlendLighten{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendLighten),
914 FilterOp::SVGFEBlendLuminosity{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendLuminosity),
915 FilterOp::SVGFEBlendMultiply{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendMultiply),
916 FilterOp::SVGFEBlendNormal{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendNormal),
917 FilterOp::SVGFEBlendOverlay{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendOverlay),
918 FilterOp::SVGFEBlendSaturation{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendSaturation),
919 FilterOp::SVGFEBlendScreen{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendScreen),
920 FilterOp::SVGFEBlendSoftLight{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendSoftLight),
921 FilterOp::SVGFEColorMatrix{node, values} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEColorMatrix{values}),
922 FilterOp::SVGFEComponentTransfer{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEComponentTransfer),
923 FilterOp::SVGFECompositeArithmetic{node, k1, k2, k3, k4} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeArithmetic{k1, k2, k3, k4}),
924 FilterOp::SVGFECompositeATop{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeATop),
925 FilterOp::SVGFECompositeIn{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeIn),
926 FilterOp::SVGFECompositeLighter{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeLighter),
927 FilterOp::SVGFECompositeOut{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeOut),
928 FilterOp::SVGFECompositeOver{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeOver),
929 FilterOp::SVGFECompositeXOR{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeXOR),
930 FilterOp::SVGFEConvolveMatrixEdgeModeDuplicate{node, order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha}),
931 FilterOp::SVGFEConvolveMatrixEdgeModeNone{node, order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha}),
932 FilterOp::SVGFEConvolveMatrixEdgeModeWrap{node, order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha}),
933 FilterOp::SVGFEDiffuseLightingDistant{node, surface_scale, diffuse_constant, kernel_unit_length_x, kernel_unit_length_y, azimuth, elevation} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEDiffuseLightingDistant{surface_scale, diffuse_constant, kernel_unit_length_x, kernel_unit_length_y, azimuth, elevation}),
934 FilterOp::SVGFEDiffuseLightingPoint{node, surface_scale, diffuse_constant, kernel_unit_length_x, kernel_unit_length_y, x, y, z} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEDiffuseLightingPoint{surface_scale, diffuse_constant, kernel_unit_length_x, kernel_unit_length_y, x, y, z}),
935 FilterOp::SVGFEDiffuseLightingSpot{node, surface_scale, diffuse_constant, kernel_unit_length_x, kernel_unit_length_y, x, y, z, points_at_x, points_at_y, points_at_z, cone_exponent, limiting_cone_angle} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEDiffuseLightingSpot{surface_scale, diffuse_constant, kernel_unit_length_x, kernel_unit_length_y, x, y, z, points_at_x, points_at_y, points_at_z, cone_exponent, limiting_cone_angle}),
936 FilterOp::SVGFEDisplacementMap{node, scale, x_channel_selector, y_channel_selector} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEDisplacementMap{scale, x_channel_selector, y_channel_selector}),
937 FilterOp::SVGFEDropShadow{node, color, dx, dy, std_deviation_x, std_deviation_y} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEDropShadow{color, dx, dy, std_deviation_x, std_deviation_y}),
938 FilterOp::SVGFEFlood{node, color} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEFlood{color}),
939 FilterOp::SVGFEGaussianBlur{node, std_deviation_x, std_deviation_y} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEGaussianBlur{std_deviation_x, std_deviation_y}),
940 FilterOp::SVGFEIdentity{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEIdentity),
941 FilterOp::SVGFEImage{node, sampling_filter, matrix} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEImage{sampling_filter, matrix}),
942 FilterOp::SVGFEMorphologyDilate{node, radius_x, radius_y} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEMorphologyDilate{radius_x, radius_y}),
943 FilterOp::SVGFEMorphologyErode{node, radius_x, radius_y} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEMorphologyErode{radius_x, radius_y}),
944 FilterOp::SVGFEOffset{node, offset_x, offset_y} => {
945 Filter::SVGGraphNode(
946 FilterGraphNode {
947 kept_by_optimizer: true, linear: node.linear,
949 inflate: 0, inputs: [FilterGraphPictureReference {
951 buffer_id: node.input.buffer_id,
952 offset: LayoutVector2D::new(offset_x, offset_y),
953 subregion: LayoutRect::zero(),
954 inflate: 0,
955 source_padding: LayoutRect::zero(),
956 target_padding: LayoutRect::zero(),
957 }].to_vec(),
958 subregion: node.subregion,
959 },
960 FilterGraphOp::SVGFEIdentity,
961 )
962 },
963 FilterOp::SVGFEOpacity{node, valuebinding, value} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEOpacity{valuebinding, value}),
964 FilterOp::SVGFESourceAlpha{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFESourceAlpha),
965 FilterOp::SVGFESourceGraphic{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFESourceGraphic),
966 FilterOp::SVGFESpecularLightingDistant{node, surface_scale, specular_constant, specular_exponent, kernel_unit_length_x, kernel_unit_length_y, azimuth, elevation} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFESpecularLightingDistant{surface_scale, specular_constant, specular_exponent, kernel_unit_length_x, kernel_unit_length_y, azimuth, elevation}),
967 FilterOp::SVGFESpecularLightingPoint{node, surface_scale, specular_constant, specular_exponent, kernel_unit_length_x, kernel_unit_length_y, x, y, z} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFESpecularLightingPoint{surface_scale, specular_constant, specular_exponent, kernel_unit_length_x, kernel_unit_length_y, x, y, z}),
968 FilterOp::SVGFESpecularLightingSpot{node, surface_scale, specular_constant, specular_exponent, kernel_unit_length_x, kernel_unit_length_y, x, y, z, points_at_x, points_at_y, points_at_z, cone_exponent, limiting_cone_angle} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFESpecularLightingSpot{surface_scale, specular_constant, specular_exponent, kernel_unit_length_x, kernel_unit_length_y, x, y, z, points_at_x, points_at_y, points_at_z, cone_exponent, limiting_cone_angle}),
969 FilterOp::SVGFETile{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFETile),
970 FilterOp::SVGFEToAlpha{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEToAlpha),
971 FilterOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{node, base_frequency_x, base_frequency_y, num_octaves, seed} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{base_frequency_x, base_frequency_y, num_octaves, seed}),
972 FilterOp::SVGFETurbulenceWithFractalNoiseWithStitching{node, base_frequency_x, base_frequency_y, num_octaves, seed} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{base_frequency_x, base_frequency_y, num_octaves, seed}),
973 FilterOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{node, base_frequency_x, base_frequency_y, num_octaves, seed} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{base_frequency_x, base_frequency_y, num_octaves, seed}),
974 FilterOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{node, base_frequency_x, base_frequency_y, num_octaves, seed} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{base_frequency_x, base_frequency_y, num_octaves, seed}),
975 }
976 }
977}
978
979#[cfg_attr(feature = "capture", derive(Serialize))]
980#[cfg_attr(feature = "replay", derive(Deserialize))]
981#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
982pub enum Swizzle {
983 Rgba,
984 Bgra,
985}
986
987impl Default for Swizzle {
988 fn default() -> Self {
989 Swizzle::Rgba
990 }
991}
992
993#[cfg_attr(feature = "capture", derive(Serialize))]
995#[cfg_attr(feature = "replay", derive(Deserialize))]
996#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
997pub struct SwizzleSettings {
998 pub bgra8_sampling_swizzle: Swizzle,
1000}
1001
1002#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1011#[cfg_attr(feature = "capture", derive(Serialize))]
1012#[cfg_attr(feature = "replay", derive(Deserialize))]
1013pub struct CacheTextureId(pub u32);
1014
1015impl CacheTextureId {
1016 pub const INVALID: CacheTextureId = CacheTextureId(!0);
1017}
1018
1019#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1020#[cfg_attr(feature = "capture", derive(Serialize))]
1021#[cfg_attr(feature = "replay", derive(Deserialize))]
1022pub struct DeferredResolveIndex(pub u32);
1023
1024#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1025#[cfg_attr(feature = "capture", derive(Serialize))]
1026#[cfg_attr(feature = "replay", derive(Deserialize))]
1027pub struct TextureSourceExternal {
1028 pub index: DeferredResolveIndex,
1029 pub kind: ImageBufferKind,
1030 pub normalized_uvs: bool,
1031}
1032
1033#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1035#[cfg_attr(feature = "capture", derive(Serialize))]
1036#[cfg_attr(feature = "replay", derive(Deserialize))]
1037pub enum TextureSource {
1038 Invalid,
1040 TextureCache(CacheTextureId, Swizzle),
1042 External(TextureSourceExternal),
1044 Dummy,
1047}
1048
1049impl TextureSource {
1050 pub fn image_buffer_kind(&self) -> ImageBufferKind {
1051 match *self {
1052 TextureSource::TextureCache(..) => ImageBufferKind::Texture2D,
1053
1054 TextureSource::External(TextureSourceExternal { kind, .. }) => kind,
1055
1056 TextureSource::Dummy => ImageBufferKind::Texture2D,
1058
1059 TextureSource::Invalid => ImageBufferKind::Texture2D,
1060 }
1061 }
1062
1063 pub fn uses_normalized_uvs(&self) -> bool {
1064 match *self {
1065 TextureSource::External(TextureSourceExternal { normalized_uvs, .. }) => normalized_uvs,
1066 _ => false,
1067 }
1068 }
1069
1070 #[inline]
1071 pub fn is_compatible(
1072 &self,
1073 other: &TextureSource,
1074 ) -> bool {
1075 *self == TextureSource::Invalid ||
1076 *other == TextureSource::Invalid ||
1077 self == other
1078 }
1079}
1080
1081#[derive(Copy, Clone, Debug, PartialEq)]
1082#[cfg_attr(feature = "capture", derive(Serialize))]
1083#[cfg_attr(feature = "replay", derive(Deserialize))]
1084pub struct RenderTargetInfo {
1085 pub has_depth: bool,
1086}
1087
1088#[derive(Debug)]
1089pub enum TextureUpdateSource {
1090 External {
1091 id: ExternalImageId,
1092 channel_index: u8,
1093 },
1094 Bytes { data: Arc<Vec<u8>> },
1095 DebugClear,
1098}
1099
1100#[derive(Debug)]
1102pub struct TextureCacheAllocation {
1103 pub id: CacheTextureId,
1105 pub kind: TextureCacheAllocationKind,
1107}
1108
1109#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1111#[cfg_attr(feature = "capture", derive(Serialize))]
1112#[cfg_attr(feature = "replay", derive(Deserialize))]
1113pub enum TextureCacheCategory {
1114 Atlas,
1115 Standalone,
1116 PictureTile,
1117 RenderTarget,
1118}
1119
1120#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1122pub struct TextureCacheAllocInfo {
1123 pub width: i32,
1124 pub height: i32,
1125 pub format: ImageFormat,
1126 pub filter: TextureFilter,
1127 pub target: ImageBufferKind,
1128 pub is_shared_cache: bool,
1130 pub has_depth: bool,
1132 pub category: TextureCacheCategory
1133}
1134
1135#[derive(Debug)]
1137pub enum TextureCacheAllocationKind {
1138 Alloc(TextureCacheAllocInfo),
1140 Reset(TextureCacheAllocInfo),
1142 Free,
1144}
1145
1146#[derive(Debug)]
1148pub struct TextureCacheUpdate {
1149 pub rect: DeviceIntRect,
1150 pub stride: Option<i32>,
1151 pub offset: i32,
1152 pub format_override: Option<ImageFormat>,
1153 pub source: TextureUpdateSource,
1154}
1155
1156#[derive(Debug)]
1158pub struct TextureCacheCopy {
1159 pub src_rect: DeviceIntRect,
1160 pub dst_rect: DeviceIntRect,
1161}
1162
1163#[derive(Default)]
1169pub struct TextureUpdateList {
1170 pub clears_shared_cache: bool,
1173 pub allocations: Vec<TextureCacheAllocation>,
1175 pub updates: FastHashMap<CacheTextureId, Vec<TextureCacheUpdate>>,
1177 pub copies: FastHashMap<(CacheTextureId, CacheTextureId), Vec<TextureCacheCopy>>,
1180}
1181
1182impl TextureUpdateList {
1183 pub fn new() -> Self {
1185 TextureUpdateList {
1186 clears_shared_cache: false,
1187 allocations: Vec::new(),
1188 updates: FastHashMap::default(),
1189 copies: FastHashMap::default(),
1190 }
1191 }
1192
1193 pub fn is_nop(&self) -> bool {
1195 self.allocations.is_empty() && self.updates.is_empty()
1196 }
1197
1198 #[inline]
1200 pub fn note_clear(&mut self) {
1201 self.clears_shared_cache = true;
1202 }
1203
1204 #[inline]
1206 pub fn push_update(&mut self, id: CacheTextureId, update: TextureCacheUpdate) {
1207 self.updates
1208 .entry(id)
1209 .or_default()
1210 .push(update);
1211 }
1212
1213 #[cold]
1216 pub fn push_debug_clear(
1217 &mut self,
1218 id: CacheTextureId,
1219 origin: DeviceIntPoint,
1220 width: i32,
1221 height: i32,
1222 ) {
1223 let size = DeviceIntSize::new(width, height);
1224 let rect = DeviceIntRect::from_origin_and_size(origin, size);
1225 self.push_update(id, TextureCacheUpdate {
1226 rect,
1227 stride: None,
1228 offset: 0,
1229 format_override: None,
1230 source: TextureUpdateSource::DebugClear,
1231 });
1232 }
1233
1234
1235 pub fn push_alloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
1237 debug_assert!(!self.allocations.iter().any(|x| x.id == id));
1238 self.allocations.push(TextureCacheAllocation {
1239 id,
1240 kind: TextureCacheAllocationKind::Alloc(info),
1241 });
1242 }
1243
1244 pub fn push_reset(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
1247 self.debug_assert_coalesced(id);
1248
1249 self.updates.remove(&id);
1251
1252 if let Some(cur) = self.allocations.iter_mut().find(|x| x.id == id) {
1254 match cur.kind {
1255 TextureCacheAllocationKind::Alloc(ref mut i) => *i = info,
1256 TextureCacheAllocationKind::Reset(ref mut i) => *i = info,
1257 TextureCacheAllocationKind::Free => panic!("Resetting freed texture"),
1258 }
1259 return
1260 }
1261
1262 self.allocations.push(TextureCacheAllocation {
1263 id,
1264 kind: TextureCacheAllocationKind::Reset(info),
1265 });
1266 }
1267
1268 pub fn push_free(&mut self, id: CacheTextureId) {
1271 self.debug_assert_coalesced(id);
1272
1273 self.updates.remove(&id);
1275
1276 let idx = self.allocations.iter().position(|x| x.id == id);
1279 let removed_kind = idx.map(|i| self.allocations.remove(i).kind);
1280 match removed_kind {
1281 Some(TextureCacheAllocationKind::Alloc(..)) => { },
1282 Some(TextureCacheAllocationKind::Free) => panic!("Double free"),
1283 Some(TextureCacheAllocationKind::Reset(..)) |
1284 None => {
1285 self.allocations.push(TextureCacheAllocation {
1286 id,
1287 kind: TextureCacheAllocationKind::Free,
1288 });
1289 }
1290 };
1291 }
1292
1293 pub fn push_copy(
1299 &mut self,
1300 src_id: CacheTextureId, src_rect: &DeviceIntRect,
1301 dst_id: CacheTextureId, dst_rect: &DeviceIntRect,
1302 ) {
1303 debug_assert_eq!(src_rect.size(), dst_rect.size());
1304 self.copies.entry((src_id, dst_id))
1305 .or_insert_with(Vec::new)
1306 .push(TextureCacheCopy {
1307 src_rect: *src_rect,
1308 dst_rect: *dst_rect,
1309 });
1310 }
1311
1312 fn debug_assert_coalesced(&self, id: CacheTextureId) {
1313 debug_assert!(
1314 self.allocations.iter().filter(|x| x.id == id).count() <= 1,
1315 "Allocations should have been coalesced",
1316 );
1317 }
1318}
1319
1320pub struct ResourceUpdateList {
1323 pub native_surface_updates: Vec<NativeSurfaceOperation>,
1325
1326 pub texture_updates: TextureUpdateList,
1328}
1329
1330impl ResourceUpdateList {
1331 pub fn is_nop(&self) -> bool {
1333 self.texture_updates.is_nop() && self.native_surface_updates.is_empty()
1334 }
1335}
1336
1337pub struct RenderedDocument {
1339 pub frame: Frame,
1340 pub profile: TransactionProfile,
1341 pub render_reasons: RenderReasons,
1342 pub frame_stats: Option<FullFrameStats>
1343}
1344
1345pub enum DebugOutput {
1346 #[cfg(feature = "capture")]
1347 SaveCapture(CaptureConfig, Vec<ExternalCaptureImage>),
1348 #[cfg(feature = "replay")]
1349 LoadCapture(CaptureConfig, Vec<PlainExternalImage>),
1350}
1351
1352#[allow(dead_code)]
1353pub enum ResultMsg {
1354 DebugCommand(DebugCommand),
1355 DebugOutput(DebugOutput),
1356 RefreshShader(PathBuf),
1357 UpdateGpuCache(GpuCacheUpdateList),
1358 UpdateResources {
1359 resource_updates: ResourceUpdateList,
1360 memory_pressure: bool,
1361 },
1362 PublishPipelineInfo(PipelineInfo),
1363 PublishDocument(
1364 FramePublishId,
1365 DocumentId,
1366 RenderedDocument,
1367 ResourceUpdateList,
1368 ),
1369 AppendNotificationRequests(Vec<NotificationRequest>),
1370 SetParameter(Parameter),
1371 ForceRedraw,
1372}
1373
1374#[derive(Copy, Clone, Debug)]
1376pub struct LayoutPrimitiveInfo {
1377 pub rect: LayoutRect,
1380 pub clip_rect: LayoutRect,
1381 pub flags: PrimitiveFlags,
1382}
1383
1384impl LayoutPrimitiveInfo {
1385 pub fn with_clip_rect(rect: LayoutRect, clip_rect: LayoutRect) -> Self {
1386 Self {
1387 rect,
1388 clip_rect,
1389 flags: PrimitiveFlags::default(),
1390 }
1391 }
1392}
1393
1394#[cfg_attr(feature = "capture", derive(Serialize))]
1397#[cfg_attr(feature = "replay", derive(Deserialize))]
1398#[derive(Copy, Clone, PartialEq, Debug, Eq, Hash)]
1399pub struct PipelineInstanceId(u32);
1400
1401impl PipelineInstanceId {
1402 pub fn new(id: u32) -> Self {
1403 PipelineInstanceId(id)
1404 }
1405}