webrender/
internal_types.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use 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    /// Returns a FrameId corresponding to the first frame.
54    ///
55    /// Note that we use 0 as the internal id here because the current code
56    /// increments the frame id at the beginning of the frame, rather than
57    /// at the end, and we want the first frame to be 1. It would probably
58    /// be sensible to move the advance() call to after frame-building, and
59    /// then make this method return FrameId(1).
60    pub fn first() -> Self {
61        FrameId(0)
62    }
63
64    /// Returns the backing u64 for this FrameId.
65    pub fn as_u64(&self) -> u64 {
66        self.0
67    }
68
69    /// Advances this FrameId to the next frame.
70    pub fn advance(&mut self) {
71        self.0 += 1;
72    }
73
74    /// An invalid sentinel FrameId, which will always compare less than
75    /// any valid FrameId.
76    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/// Identifier to track a sequence of frames.
101///
102/// This is effectively a `FrameId` with a ridealong timestamp corresponding
103/// to when advance() was called, which allows for more nuanced cache eviction
104/// decisions. As such, we use the `FrameId` for equality and comparison, since
105/// we should never have two `FrameStamps` with the same id but different
106/// timestamps.
107#[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        // We should not be checking equality unless the documents are the same
121        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    /// Gets the FrameId in this stamp.
134    pub fn frame_id(&self) -> FrameId {
135        self.id
136    }
137
138    /// Gets the time associated with this FrameStamp.
139    pub fn time(&self) -> SystemTime {
140        self.time
141    }
142
143    /// Gets the DocumentId in this stamp.
144    pub fn document_id(&self) -> DocumentId {
145        self.document_id
146    }
147
148    pub fn is_valid(&self) -> bool {
149        // If any fields are their default values, the whole struct should equal INVALID
150        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    /// Returns a FrameStamp corresponding to the first frame.
156    pub fn first(document_id: DocumentId) -> Self {
157        FrameStamp {
158            id: FrameId::first(),
159            time: SystemTime::now(),
160            document_id,
161        }
162    }
163
164    /// Advances to a new frame.
165    pub fn advance(&mut self) {
166        self.id.advance();
167        self.time = SystemTime::now();
168    }
169
170    /// An invalid sentinel FrameStamp.
171    pub const INVALID: FrameStamp = FrameStamp {
172        id: FrameId(0),
173        time: UNIX_EPOCH,
174        document_id: DocumentId::INVALID,
175    };
176}
177
178/// Custom field embedded inside the Polygon struct of the plane-split crate.
179#[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
207/// A concrete plane splitter type used in WebRender.
208pub type PlaneSplitter = BspSplitter<PlaneSplitAnchor>;
209
210/// An index into the scene's list of plane splitters
211#[derive(Debug, Copy, Clone)]
212#[cfg_attr(feature = "capture", derive(Serialize))]
213pub struct PlaneSplitterIndex(pub usize);
214
215/// An arbitrary number which we assume opacity is invisible below.
216const 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    /// Id of the picture in question in a namespace unique to this filter DAG,
223    /// some are special values like
224    /// FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic.
225    pub buffer_id: FilterOpGraphPictureBufferId,
226    /// Set by wrap_prim_with_filters to the subregion of the input node, may
227    /// also have been offset for feDropShadow or feOffset
228    pub subregion: LayoutRect,
229    /// During scene build this is the offset to apply to the input subregion
230    /// for feOffset, which can be optimized away by pushing its offset and
231    /// subregion crop to downstream nodes.  This is always zero in render tasks
232    /// where it has already been applied to subregion by that point.  Not used
233    /// in get_coverage_svgfe because source_padding/target_padding represent
234    /// the offset there.
235    pub offset: LayoutVector2D,
236    /// Equal to the inflate value of the referenced buffer, or 0
237    pub inflate: i16,
238    /// Padding on each side to represent how this input is read relative to the
239    /// node's output subregion, this represents what the operation needs to
240    /// read from ths input, which may be blurred or offset.
241    pub source_padding: LayoutRect,
242    /// Padding on each side to represent how this input affects the node's
243    /// subregion, this can be used to calculate target subregion based on
244    /// SourceGraphic subregion.  This is usually equal to source_padding except
245    /// offset in the opposite direction, inflates typically do the same thing
246    /// to both types of padding.
247    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            // All of these are set by wrap_prim_with_filters
255            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    /// Filter that copies the SourceGraphic image into the specified subregion,
273    /// This is intentionally the only way to get SourceGraphic into the graph,
274    /// as the filter region must be applied before it is used.
275    /// parameters: FilterOpGraphNode
276    /// SVG filter semantics - no inputs, no linear
277    SVGFESourceGraphic,
278    /// Filter that copies the SourceAlpha image into the specified subregion,
279    /// This is intentionally the only way to get SourceAlpha into the graph,
280    /// as the filter region must be applied before it is used.
281    /// parameters: FilterOpGraphNode
282    /// SVG filter semantics - no inputs, no linear
283    SVGFESourceAlpha,
284    /// Filter that does no transformation of the colors, used to implement a
285    /// few things like SVGFEOffset, and this is the default value in
286    /// impl_default_for_enums.
287    /// parameters: FilterGraphNode
288    /// SVG filter semantics - selectable input with offset
289    SVGFEIdentity,
290    /// represents CSS opacity property as a graph node like the rest of the
291    /// SVGFE* filters
292    /// parameters: FilterGraphNode
293    /// SVG filter semantics - selectable input(s), selectable between linear
294    /// (default) and sRGB color space for calculations
295    SVGFEOpacity{valuebinding: api::PropertyBinding<f32>, value: f32},
296    /// convert a color image to an alpha channel - internal use; generated by
297    /// SVGFilterInstance::GetOrCreateSourceAlphaIndex().
298    SVGFEToAlpha,
299    /// combine 2 images with SVG_FEBLEND_MODE_DARKEN
300    /// parameters: FilterGraphNode
301    /// SVG filter semantics - selectable input(s), selectable between linear
302    /// (default) and sRGB color space for calculations
303    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
304    SVGFEBlendDarken,
305    /// combine 2 images with SVG_FEBLEND_MODE_LIGHTEN
306    /// parameters: FilterGraphNode
307    /// SVG filter semantics - selectable input(s), selectable between linear
308    /// (default) and sRGB color space for calculations
309    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
310    SVGFEBlendLighten,
311    /// combine 2 images with SVG_FEBLEND_MODE_MULTIPLY
312    /// parameters: FilterGraphNode
313    /// SVG filter semantics - selectable input(s), selectable between linear
314    /// (default) and sRGB color space for calculations
315    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
316    SVGFEBlendMultiply,
317    /// combine 2 images with SVG_FEBLEND_MODE_NORMAL
318    /// parameters: FilterGraphNode
319    /// SVG filter semantics - selectable input(s), selectable between linear
320    /// (default) and sRGB color space for calculations
321    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
322    SVGFEBlendNormal,
323    /// combine 2 images with SVG_FEBLEND_MODE_SCREEN
324    /// parameters: FilterGraphNode
325    /// SVG filter semantics - selectable input(s), selectable between linear
326    /// (default) and sRGB color space for calculations
327    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
328    SVGFEBlendScreen,
329    /// combine 2 images with SVG_FEBLEND_MODE_OVERLAY
330    /// parameters: FilterOpGraphNode
331    /// SVG filter semantics - selectable input(s), selectable between linear
332    /// (default) and sRGB color space for calculations
333    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
334    SVGFEBlendOverlay,
335    /// combine 2 images with SVG_FEBLEND_MODE_COLOR_DODGE
336    /// parameters: FilterOpGraphNode
337    /// SVG filter semantics - selectable input(s), selectable between linear
338    /// (default) and sRGB color space for calculations
339    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
340    SVGFEBlendColorDodge,
341    /// combine 2 images with SVG_FEBLEND_MODE_COLOR_BURN
342    /// parameters: FilterOpGraphNode
343    /// SVG filter semantics - selectable input(s), selectable between linear
344    /// (default) and sRGB color space for calculations
345    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
346    SVGFEBlendColorBurn,
347    /// combine 2 images with SVG_FEBLEND_MODE_HARD_LIGHT
348    /// parameters: FilterOpGraphNode
349    /// SVG filter semantics - selectable input(s), selectable between linear
350    /// (default) and sRGB color space for calculations
351    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
352    SVGFEBlendHardLight,
353    /// combine 2 images with SVG_FEBLEND_MODE_SOFT_LIGHT
354    /// parameters: FilterOpGraphNode
355    /// SVG filter semantics - selectable input(s), selectable between linear
356    /// (default) and sRGB color space for calculations
357    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
358    SVGFEBlendSoftLight,
359    /// combine 2 images with SVG_FEBLEND_MODE_DIFFERENCE
360    /// parameters: FilterOpGraphNode
361    /// SVG filter semantics - selectable input(s), selectable between linear
362    /// (default) and sRGB color space for calculations
363    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
364    SVGFEBlendDifference,
365    /// combine 2 images with SVG_FEBLEND_MODE_EXCLUSION
366    /// parameters: FilterOpGraphNode
367    /// SVG filter semantics - selectable input(s), selectable between linear
368    /// (default) and sRGB color space for calculations
369    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
370    SVGFEBlendExclusion,
371    /// combine 2 images with SVG_FEBLEND_MODE_HUE
372    /// parameters: FilterOpGraphNode
373    /// SVG filter semantics - selectable input(s), selectable between linear
374    /// (default) and sRGB color space for calculations
375    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
376    SVGFEBlendHue,
377    /// combine 2 images with SVG_FEBLEND_MODE_SATURATION
378    /// parameters: FilterOpGraphNode
379    /// SVG filter semantics - selectable input(s), selectable between linear
380    /// (default) and sRGB color space for calculations
381    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
382    SVGFEBlendSaturation,
383    /// combine 2 images with SVG_FEBLEND_MODE_COLOR
384    /// parameters: FilterOpGraphNode
385    /// SVG filter semantics - selectable input(s), selectable between linear
386    /// (default) and sRGB color space for calculations
387    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
388    SVGFEBlendColor,
389    /// combine 2 images with SVG_FEBLEND_MODE_LUMINOSITY
390    /// parameters: FilterOpGraphNode
391    /// SVG filter semantics - selectable input(s), selectable between linear
392    /// (default) and sRGB color space for calculations
393    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
394    SVGFEBlendLuminosity,
395    /// transform colors of image through 5x4 color matrix (transposed for
396    /// efficiency)
397    /// parameters: FilterGraphNode, matrix[5][4]
398    /// SVG filter semantics - selectable input(s), selectable between linear
399    /// (default) and sRGB color space for calculations
400    /// Spec: https://www.w3.org/TR/filter-effects-1/#feColorMatrixElement
401    SVGFEColorMatrix{values: [f32; 20]},
402    /// transform colors of image through configurable gradients with component
403    /// swizzle
404    /// parameters: FilterGraphNode
405    /// SVG filter semantics - selectable input(s), selectable between linear
406    /// (default) and sRGB color space for calculations
407    /// Spec: https://www.w3.org/TR/filter-effects-1/#feComponentTransferElement
408    SVGFEComponentTransfer,
409    /// Processed version of SVGFEComponentTransfer with the FilterData
410    /// replaced by an interned handle, this is made in wrap_prim_with_filters.
411    /// Aside from the interned handle, creates_pixels indicates if the transfer
412    /// parameters will probably fill the entire subregion with non-zero alpha.
413    SVGFEComponentTransferInterned{handle: FilterDataHandle, creates_pixels: bool},
414    /// composite 2 images with chosen composite mode with parameters for that
415    /// mode
416    /// parameters: FilterGraphNode, k1, k2, k3, k4
417    /// SVG filter semantics - selectable input(s), selectable between linear
418    /// (default) and sRGB color space for calculations
419    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
420    SVGFECompositeArithmetic{k1: f32, k2: f32, k3: f32, k4: f32},
421    /// composite 2 images with chosen composite mode with parameters for that
422    /// mode
423    /// parameters: FilterGraphNode
424    /// SVG filter semantics - selectable input(s), selectable between linear
425    /// (default) and sRGB color space for calculations
426    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
427    SVGFECompositeATop,
428    /// composite 2 images with chosen composite mode with parameters for that
429    /// mode
430    /// parameters: FilterGraphNode
431    /// SVG filter semantics - selectable input(s), selectable between linear
432    /// (default) and sRGB color space for calculations
433    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
434    SVGFECompositeIn,
435    /// composite 2 images with chosen composite mode with parameters for that
436    /// mode
437    /// parameters: FilterOpGraphNode
438    /// SVG filter semantics - selectable input(s), selectable between linear
439    /// (default) and sRGB color space for calculations
440    /// Docs: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feComposite
441    SVGFECompositeLighter,
442    /// composite 2 images with chosen composite mode with parameters for that
443    /// mode
444    /// parameters: FilterGraphNode
445    /// SVG filter semantics - selectable input(s), selectable between linear
446    /// (default) and sRGB color space for calculations
447    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
448    SVGFECompositeOut,
449    /// composite 2 images with chosen composite mode with parameters for that
450    /// mode
451    /// parameters: FilterGraphNode
452    /// SVG filter semantics - selectable input(s), selectable between linear
453    /// (default) and sRGB color space for calculations
454    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
455    SVGFECompositeOver,
456    /// composite 2 images with chosen composite mode with parameters for that
457    /// mode
458    /// parameters: FilterGraphNode
459    /// SVG filter semantics - selectable input(s), selectable between linear
460    /// (default) and sRGB color space for calculations
461    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
462    SVGFECompositeXOR,
463    /// transform image through convolution matrix of up to 25 values (spec
464    /// allows more but for performance reasons we do not)
465    /// parameters: FilterGraphNode, orderX, orderY, kernelValues[25], divisor,
466    ///  bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY,
467    ///  preserveAlpha
468    /// SVG filter semantics - selectable input(s), selectable between linear
469    /// (default) and sRGB color space for calculations
470    /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement
471    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    /// transform image through convolution matrix of up to 25 values (spec
476    /// allows more but for performance reasons we do not)
477    /// parameters: FilterGraphNode, orderX, orderY, kernelValues[25], divisor,
478    ///  bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY,
479    ///  preserveAlpha
480    /// SVG filter semantics - selectable input(s), selectable between linear
481    /// (default) and sRGB color space for calculations
482    /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement
483    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    /// transform image through convolution matrix of up to 25 values (spec
488    /// allows more but for performance reasons we do not)
489    /// parameters: FilterGraphNode, orderX, orderY, kernelValues[25], divisor,
490    ///  bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY,
491    ///  preserveAlpha
492    /// SVG filter semantics - selectable input(s), selectable between linear
493    /// (default) and sRGB color space for calculations
494    /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement
495    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    /// calculate lighting based on heightmap image with provided values for a
500    /// distant light source with specified direction
501    /// parameters: FilterGraphNode, surfaceScale, diffuseConstant,
502    ///  kernelUnitLengthX, kernelUnitLengthY, azimuth, elevation
503    /// SVG filter semantics - selectable input(s), selectable between linear
504    /// (default) and sRGB color space for calculations
505    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement
506    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDistantLightElement
507    SVGFEDiffuseLightingDistant{surface_scale: f32, diffuse_constant: f32,
508        kernel_unit_length_x: f32, kernel_unit_length_y: f32, azimuth: f32,
509        elevation: f32},
510    /// calculate lighting based on heightmap image with provided values for a
511    /// point light source at specified location
512    /// parameters: FilterGraphNode, surfaceScale, diffuseConstant,
513    ///  kernelUnitLengthX, kernelUnitLengthY, x, y, z
514    /// SVG filter semantics - selectable input(s), selectable between linear
515    /// (default) and sRGB color space for calculations
516    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement
517    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEPointLightElement
518    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    /// calculate lighting based on heightmap image with provided values for a
522    /// spot light source at specified location pointing at specified target
523    /// location with specified hotspot sharpness and cone angle
524    /// parameters: FilterGraphNode, surfaceScale, diffuseConstant,
525    ///  kernelUnitLengthX, kernelUnitLengthY, x, y, z, pointsAtX, pointsAtY,
526    ///  pointsAtZ, specularExponent, limitingConeAngle
527    /// SVG filter semantics - selectable input(s), selectable between linear
528    /// (default) and sRGB color space for calculations
529    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement
530    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpotLightElement
531    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    /// calculate a distorted version of first input image using offset values
536    /// from second input image at specified intensity
537    /// parameters: FilterGraphNode, scale, xChannelSelector, yChannelSelector
538    /// SVG filter semantics - selectable input(s), selectable between linear
539    /// (default) and sRGB color space for calculations
540    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDisplacementMapElement
541    SVGFEDisplacementMap{scale: f32, x_channel_selector: u32,
542        y_channel_selector: u32},
543    /// create and merge a dropshadow version of the specified image's alpha
544    /// channel with specified offset and blur radius
545    /// parameters: FilterGraphNode, flood_color, flood_opacity, dx, dy,
546    ///  stdDeviationX, stdDeviationY
547    /// SVG filter semantics - selectable input(s), selectable between linear
548    /// (default) and sRGB color space for calculations
549    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDropShadowElement
550    SVGFEDropShadow{color: ColorF, dx: f32, dy: f32, std_deviation_x: f32,
551        std_deviation_y: f32},
552    /// synthesize a new image of specified size containing a solid color
553    /// parameters: FilterGraphNode, color
554    /// SVG filter semantics - selectable input(s), selectable between linear
555    /// (default) and sRGB color space for calculations
556    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEFloodElement
557    SVGFEFlood{color: ColorF},
558    /// create a blurred version of the input image
559    /// parameters: FilterGraphNode, stdDeviationX, stdDeviationY
560    /// SVG filter semantics - selectable input(s), selectable between linear
561    /// (default) and sRGB color space for calculations
562    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEGaussianBlurElement
563    SVGFEGaussianBlur{std_deviation_x: f32, std_deviation_y: f32},
564    /// synthesize a new image based on a url (i.e. blob image source)
565    /// parameters: FilterGraphNode,
566    ///  samplingFilter (see SamplingFilter in Types.h), transform
567    /// SVG filter semantics - selectable input(s), selectable between linear
568    /// (default) and sRGB color space for calculations
569    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEImageElement
570    SVGFEImage{sampling_filter: u32, matrix: [f32; 6]},
571    /// create a new image based on the input image with the contour stretched
572    /// outward (dilate operator)
573    /// parameters: FilterGraphNode, radiusX, radiusY
574    /// SVG filter semantics - selectable input(s), selectable between linear
575    /// (default) and sRGB color space for calculations
576    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEMorphologyElement
577    SVGFEMorphologyDilate{radius_x: f32, radius_y: f32},
578    /// create a new image based on the input image with the contour shrunken
579    /// inward (erode operator)
580    /// parameters: FilterGraphNode, radiusX, radiusY
581    /// SVG filter semantics - selectable input(s), selectable between linear
582    /// (default) and sRGB color space for calculations
583    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEMorphologyElement
584    SVGFEMorphologyErode{radius_x: f32, radius_y: f32},
585    /// calculate lighting based on heightmap image with provided values for a
586    /// distant light source with specified direction
587    /// parameters: FilerData, surfaceScale, specularConstant, specularExponent,
588    ///  kernelUnitLengthX, kernelUnitLengthY, azimuth, elevation
589    /// SVG filter semantics - selectable input(s), selectable between linear
590    /// (default) and sRGB color space for calculations
591    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement
592    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDistantLightElement
593    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    /// calculate lighting based on heightmap image with provided values for a
597    /// point light source at specified location
598    /// parameters: FilterGraphNode, surfaceScale, specularConstant,
599    ///  specularExponent, kernelUnitLengthX, kernelUnitLengthY, x, y, z
600    /// SVG filter semantics - selectable input(s), selectable between linear
601    /// (default) and sRGB color space for calculations
602    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement
603    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEPointLightElement
604    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    /// calculate lighting based on heightmap image with provided values for a
608    /// spot light source at specified location pointing at specified target
609    /// location with specified hotspot sharpness and cone angle
610    /// parameters: FilterGraphNode, surfaceScale, specularConstant,
611    ///  specularExponent, kernelUnitLengthX, kernelUnitLengthY, x, y, z,
612    ///  pointsAtX, pointsAtY, pointsAtZ, specularExponent, limitingConeAngle
613    /// SVG filter semantics - selectable input(s), selectable between linear
614    /// (default) and sRGB color space for calculations
615    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement
616    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpotLightElement
617    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    /// create a new image based on the input image, repeated throughout the
623    /// output rectangle
624    /// parameters: FilterGraphNode
625    /// SVG filter semantics - selectable input(s), selectable between linear
626    /// (default) and sRGB color space for calculations
627    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETileElement
628    SVGFETile,
629    /// synthesize a new image based on Fractal Noise (Perlin) with the chosen
630    /// stitching mode
631    /// parameters: FilterGraphNode, baseFrequencyX, baseFrequencyY, numOctaves,
632    ///  seed
633    /// SVG filter semantics - selectable input(s), selectable between linear
634    /// (default) and sRGB color space for calculations
635    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
636    SVGFETurbulenceWithFractalNoiseWithNoStitching{base_frequency_x: f32,
637        base_frequency_y: f32, num_octaves: u32, seed: u32},
638    /// synthesize a new image based on Fractal Noise (Perlin) with the chosen
639    /// stitching mode
640    /// parameters: FilterGraphNode, baseFrequencyX, baseFrequencyY, numOctaves,
641    ///  seed
642    /// SVG filter semantics - selectable input(s), selectable between linear
643    /// (default) and sRGB color space for calculations
644    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
645    SVGFETurbulenceWithFractalNoiseWithStitching{base_frequency_x: f32,
646        base_frequency_y: f32, num_octaves: u32, seed: u32},
647    /// synthesize a new image based on Turbulence Noise (offset vectors)
648    /// parameters: FilterGraphNode, baseFrequencyX, baseFrequencyY, numOctaves,
649    ///  seed
650    /// SVG filter semantics - selectable input(s), selectable between linear
651    /// (default) and sRGB color space for calculations
652    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
653    SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{base_frequency_x: f32,
654        base_frequency_y: f32, num_octaves: u32, seed: u32},
655    /// synthesize a new image based on Turbulence Noise (offset vectors)
656    /// parameters: FilterGraphNode, baseFrequencyX, baseFrequencyY, numOctaves,
657    ///  seed
658    /// SVG filter semantics - selectable input(s), selectable between linear
659    /// (default) and sRGB color space for calculations
660    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
661    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    /// Indicates this graph node was marked as necessary by the DAG optimizer
729    pub kept_by_optimizer: bool,
730    /// true if color_interpolation_filter == LinearRgb; shader will convert
731    /// sRGB texture pixel colors on load and convert back on store, for correct
732    /// interpolation
733    pub linear: bool,
734    /// padding for output rect if we need a border to get correct clamping, or
735    /// to account for larger final subregion than source rect (see bug 1869672)
736    pub inflate: i16,
737    /// virtualized picture input bindings, these refer to other filter outputs
738    /// by number within the graph, usually there is one element
739    pub inputs: Vec<FilterGraphPictureReference>,
740    /// clipping rect for filter node output
741    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        // If the op used by this node is a feMerge, it will add more inputs
754        // after this invocation.
755        FilterGraphNode{
756            linear: node.linear,
757            inputs,
758            subregion: node.subregion,
759            // These are computed later in scene_building
760            kept_by_optimizer: true,
761            inflate: 0,
762        }
763    }
764}
765
766
767/// Equivalent to api::FilterOp with added internal information
768#[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, // this is intentional
825            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        // Must be kept in sync with brush_blend.glsl
864        match *self {
865            Filter::Identity => 0, // matches `Contrast(1)`
866            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, // computed later in scene_building
948                        linear: node.linear,
949                        inflate: 0, // computed later in scene_building
950                        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/// Swizzle settings of the texture cache.
994#[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    /// Swizzle required on sampling a texture with BGRA8 format.
999    pub bgra8_sampling_swizzle: Swizzle,
1000}
1001
1002/// An ID for a texture that is owned by the `texture_cache` module.
1003///
1004/// This can include atlases or standalone textures allocated via the texture
1005/// cache (e.g.  if an image is too large to be added to an atlas). The texture
1006/// cache manages the allocation and freeing of these IDs, and the rendering
1007/// thread maintains a map from cache texture ID to native texture.
1008///
1009/// We never reuse IDs, so we use a u64 here to be safe.
1010#[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/// Identifies the source of an input texture to a shader.
1034#[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    /// Equivalent to `None`, allowing us to avoid using `Option`s everywhere.
1039    Invalid,
1040    /// An entry in the texture cache.
1041    TextureCache(CacheTextureId, Swizzle),
1042    /// An external image texture, mananged by the embedding.
1043    External(TextureSourceExternal),
1044    /// Select a dummy 1x1 white texture. This can be used by image
1045    /// shaders that want to draw a solid color.
1046    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            // Render tasks use texture arrays for now.
1057            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    /// Clears the target area, rather than uploading any pixels. Used when the
1096    /// texture cache debug display is active.
1097    DebugClear,
1098}
1099
1100/// Command to allocate, reallocate, or free a texture for the texture cache.
1101#[derive(Debug)]
1102pub struct TextureCacheAllocation {
1103    /// The virtual ID (i.e. distinct from device ID) of the texture.
1104    pub id: CacheTextureId,
1105    /// Details corresponding to the operation in question.
1106    pub kind: TextureCacheAllocationKind,
1107}
1108
1109/// A little bit of extra information to make memory reports more useful
1110#[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/// Information used when allocating / reallocating.
1121#[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    /// Indicates whether this corresponds to one of the shared texture caches.
1129    pub is_shared_cache: bool,
1130    /// If true, this texture requires a depth target.
1131    pub has_depth: bool,
1132    pub category: TextureCacheCategory
1133}
1134
1135/// Sub-operation-specific information for allocation operations.
1136#[derive(Debug)]
1137pub enum TextureCacheAllocationKind {
1138    /// Performs an initial texture allocation.
1139    Alloc(TextureCacheAllocInfo),
1140    /// Reallocates the texture without preserving its contents.
1141    Reset(TextureCacheAllocInfo),
1142    /// Frees the texture and the corresponding cache ID.
1143    Free,
1144}
1145
1146/// Command to update the contents of the texture cache.
1147#[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/// Command to update the contents of the texture cache.
1157#[derive(Debug)]
1158pub struct TextureCacheCopy {
1159    pub src_rect: DeviceIntRect,
1160    pub dst_rect: DeviceIntRect,
1161}
1162
1163/// Atomic set of commands to manipulate the texture cache, generated on the
1164/// RenderBackend thread and executed on the Renderer thread.
1165///
1166/// The list of allocation operations is processed before the updates. This is
1167/// important to allow coalescing of certain allocation operations.
1168#[derive(Default)]
1169pub struct TextureUpdateList {
1170    /// Indicates that there was some kind of cleanup clear operation. Used for
1171    /// sanity checks.
1172    pub clears_shared_cache: bool,
1173    /// Commands to alloc/realloc/free the textures. Processed first.
1174    pub allocations: Vec<TextureCacheAllocation>,
1175    /// Commands to update the contents of the textures. Processed second.
1176    pub updates: FastHashMap<CacheTextureId, Vec<TextureCacheUpdate>>,
1177    /// Commands to move items within the cache, these are applied before everything
1178    /// else in the update list.
1179    pub copies: FastHashMap<(CacheTextureId, CacheTextureId), Vec<TextureCacheCopy>>,
1180}
1181
1182impl TextureUpdateList {
1183    /// Mints a new `TextureUpdateList`.
1184    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    /// Returns true if this is a no-op (no updates to be applied).
1194    pub fn is_nop(&self) -> bool {
1195        self.allocations.is_empty() && self.updates.is_empty()
1196    }
1197
1198    /// Sets the clears_shared_cache flag for renderer-side sanity checks.
1199    #[inline]
1200    pub fn note_clear(&mut self) {
1201        self.clears_shared_cache = true;
1202    }
1203
1204    /// Pushes an update operation onto the list.
1205    #[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    /// Sends a command to the Renderer to clear the portion of the shared region
1214    /// we just freed. Used when the texture cache debugger is enabled.
1215    #[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    /// Pushes an allocation operation onto the list.
1236    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    /// Pushes a reallocation operation onto the list, potentially coalescing
1245    /// with previous operations.
1246    pub fn push_reset(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
1247        self.debug_assert_coalesced(id);
1248
1249        // Drop any unapplied updates to the to-be-freed texture.
1250        self.updates.remove(&id);
1251
1252        // Coallesce this realloc into a previous alloc or realloc, if available.
1253        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    /// Pushes a free operation onto the list, potentially coalescing with
1269    /// previous operations.
1270    pub fn push_free(&mut self, id: CacheTextureId) {
1271        self.debug_assert_coalesced(id);
1272
1273        // Drop any unapplied updates to the to-be-freed texture.
1274        self.updates.remove(&id);
1275
1276        // Drop any allocations for it as well. If we happen to be allocating and
1277        // freeing in the same batch, we can collapse them to a no-op.
1278        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(..)) => { /* no-op! */ },
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    /// Push a copy operation from a texture to another.
1294    ///
1295    /// The source and destination rectangles must have the same size.
1296    /// The copies are applied before every other operations in the
1297    /// texture update list.
1298    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
1320/// A list of updates built by the render backend that should be applied
1321/// by the renderer thread.
1322pub struct ResourceUpdateList {
1323    /// List of OS native surface create / destroy operations to apply.
1324    pub native_surface_updates: Vec<NativeSurfaceOperation>,
1325
1326    /// Atomic set of texture cache updates to apply.
1327    pub texture_updates: TextureUpdateList,
1328}
1329
1330impl ResourceUpdateList {
1331    /// Returns true if this update list has no effect.
1332    pub fn is_nop(&self) -> bool {
1333        self.texture_updates.is_nop() && self.native_surface_updates.is_empty()
1334    }
1335}
1336
1337/// Wraps a frame_builder::Frame, but conceptually could hold more information
1338pub 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/// Primitive metadata we pass around in a bunch of places
1375#[derive(Copy, Clone, Debug)]
1376pub struct LayoutPrimitiveInfo {
1377    /// NOTE: this is *ideally* redundant with the clip_rect
1378    /// but that's an ongoing project, so for now it exists and is used :(
1379    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// In some cases (e.g. printing) a pipeline is referenced multiple times by
1395// a parent display list. This allows us to distinguish between them.
1396#[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}