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::gpu_types::BlurEdgeMode;
15use crate::frame_builder::Frame;
16use crate::profiler::TransactionProfile;
17use crate::spatial_tree::SpatialNodeIndex;
18use crate::prim_store::PrimitiveInstanceIndex;
19use crate::filterdata::FilterDataHandle;
20use rustc_hash::FxHasher;
21use plane_split::BspSplitter;
22use smallvec::SmallVec;
23use std::{usize, i32};
24use std::collections::{HashMap, HashSet};
25use std::f32;
26use std::hash::BuildHasherDefault;
27use std::path::PathBuf;
28use std::sync::Arc;
29use std::time::{UNIX_EPOCH, SystemTime};
30use peek_poke::PeekPoke;
31
32#[cfg(any(feature = "capture", feature = "replay"))]
33use crate::capture::CaptureConfig;
34#[cfg(feature = "capture")]
35use crate::capture::ExternalCaptureImage;
36#[cfg(feature = "replay")]
37use crate::capture::PlainExternalImage;
38
39pub use crate::frame_allocator::{FrameAllocator, FrameMemory};
40pub type FrameVec<T> = allocator_api2::vec::Vec<T, FrameAllocator>;
41pub fn size_of_frame_vec<T>(vec: &FrameVec<T>) -> usize {
42    vec.capacity() * std::mem::size_of::<T>()
43}
44
45pub type FastHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
46pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
47
48#[derive(Copy, Clone, Hash, MallocSizeOf, PartialEq, PartialOrd, Debug, Eq, Ord, PeekPoke)]
49#[cfg_attr(feature = "capture", derive(Serialize))]
50#[cfg_attr(feature = "replay", derive(Deserialize))]
51pub struct FrameId(u64);
52
53impl FrameId {
54    /// Returns a FrameId corresponding to the first frame.
55    ///
56    /// Note that we use 0 as the internal id here because the current code
57    /// increments the frame id at the beginning of the frame, rather than
58    /// at the end, and we want the first frame to be 1. It would probably
59    /// be sensible to move the advance() call to after frame-building, and
60    /// then make this method return FrameId(1).
61    pub fn first() -> Self {
62        FrameId(0)
63    }
64
65    /// Returns the backing u64 for this FrameId.
66    pub fn as_u64(&self) -> u64 {
67        self.0
68    }
69
70    /// Advances this FrameId to the next frame.
71    pub fn advance(&mut self) {
72        self.0 += 1;
73    }
74
75    /// An invalid sentinel FrameId, which will always compare less than
76    /// any valid FrameId.
77    pub const INVALID: FrameId = FrameId(0);
78}
79
80impl Default for FrameId {
81    fn default() -> Self {
82        FrameId::INVALID
83    }
84}
85
86impl ::std::ops::Add<u64> for FrameId {
87    type Output = Self;
88    fn add(self, other: u64) -> FrameId {
89        FrameId(self.0 + other)
90    }
91}
92
93impl ::std::ops::Sub<u64> for FrameId {
94    type Output = Self;
95    fn sub(self, other: u64) -> FrameId {
96        assert!(self.0 >= other, "Underflow subtracting FrameIds");
97        FrameId(self.0 - other)
98    }
99}
100
101/// Identifier to track a sequence of frames.
102///
103/// This is effectively a `FrameId` with a ridealong timestamp corresponding
104/// to when advance() was called, which allows for more nuanced cache eviction
105/// decisions. As such, we use the `FrameId` for equality and comparison, since
106/// we should never have two `FrameStamps` with the same id but different
107/// timestamps.
108#[derive(Copy, Clone, Debug, MallocSizeOf)]
109#[cfg_attr(feature = "capture", derive(Serialize))]
110#[cfg_attr(feature = "replay", derive(Deserialize))]
111pub struct FrameStamp {
112    id: FrameId,
113    time: SystemTime,
114    document_id: DocumentId,
115}
116
117impl Eq for FrameStamp {}
118
119impl PartialEq for FrameStamp {
120    fn eq(&self, other: &Self) -> bool {
121        // We should not be checking equality unless the documents are the same
122        debug_assert_eq!(self.document_id, other.document_id);
123        self.id == other.id
124    }
125}
126
127impl PartialOrd for FrameStamp {
128    fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
129        self.id.partial_cmp(&other.id)
130    }
131}
132
133impl FrameStamp {
134    /// Gets the FrameId in this stamp.
135    pub fn frame_id(&self) -> FrameId {
136        self.id
137    }
138
139    /// Gets the time associated with this FrameStamp.
140    pub fn time(&self) -> SystemTime {
141        self.time
142    }
143
144    /// Gets the DocumentId in this stamp.
145    pub fn document_id(&self) -> DocumentId {
146        self.document_id
147    }
148
149    pub fn is_valid(&self) -> bool {
150        // If any fields are their default values, the whole struct should equal INVALID
151        debug_assert!((self.time != UNIX_EPOCH && self.id != FrameId(0) && self.document_id != DocumentId::INVALID) ||
152                      *self == Self::INVALID);
153        self.document_id != DocumentId::INVALID
154    }
155
156    /// Returns a FrameStamp corresponding to the first frame.
157    pub fn first(document_id: DocumentId) -> Self {
158        FrameStamp {
159            id: FrameId::first(),
160            time: SystemTime::now(),
161            document_id,
162        }
163    }
164
165    /// Advances to a new frame.
166    pub fn advance(&mut self) {
167        self.id.advance();
168        self.time = SystemTime::now();
169    }
170
171    /// An invalid sentinel FrameStamp.
172    pub const INVALID: FrameStamp = FrameStamp {
173        id: FrameId(0),
174        time: UNIX_EPOCH,
175        document_id: DocumentId::INVALID,
176    };
177}
178
179/// Custom field embedded inside the Polygon struct of the plane-split crate.
180#[derive(Copy, Clone, Debug)]
181#[cfg_attr(feature = "capture", derive(Serialize))]
182pub struct PlaneSplitAnchor {
183    pub spatial_node_index: SpatialNodeIndex,
184    pub instance_index: PrimitiveInstanceIndex,
185}
186
187impl PlaneSplitAnchor {
188    pub fn new(
189        spatial_node_index: SpatialNodeIndex,
190        instance_index: PrimitiveInstanceIndex,
191    ) -> Self {
192        PlaneSplitAnchor {
193            spatial_node_index,
194            instance_index,
195        }
196    }
197}
198
199impl Default for PlaneSplitAnchor {
200    fn default() -> Self {
201        PlaneSplitAnchor {
202            spatial_node_index: SpatialNodeIndex::INVALID,
203            instance_index: PrimitiveInstanceIndex(!0),
204        }
205    }
206}
207
208/// A concrete plane splitter type used in WebRender.
209pub type PlaneSplitter = BspSplitter<PlaneSplitAnchor>;
210
211/// An index into the scene's list of plane splitters
212#[derive(Debug, Copy, Clone)]
213#[cfg_attr(feature = "capture", derive(Serialize))]
214pub struct PlaneSplitterIndex(pub usize);
215
216/// An arbitrary number which we assume opacity is invisible below.
217const OPACITY_EPSILON: f32 = 0.001;
218
219#[derive(Clone, Copy, Debug)]
220#[cfg_attr(feature = "capture", derive(Serialize))]
221#[cfg_attr(feature = "replay", derive(Deserialize))]
222pub struct FilterGraphPictureReference {
223    /// Id of the picture in question in a namespace unique to this filter DAG,
224    /// some are special values like
225    /// FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic.
226    pub buffer_id: FilterOpGraphPictureBufferId,
227    /// Set by wrap_prim_with_filters to the subregion of the input node, may
228    /// also have been offset for feDropShadow or feOffset
229    pub subregion: LayoutRect,
230    /// During scene build this is the offset to apply to the input subregion
231    /// for feOffset, which can be optimized away by pushing its offset and
232    /// subregion crop to downstream nodes.  This is always zero in render tasks
233    /// where it has already been applied to subregion by that point.  Not used
234    /// in get_coverage_svgfe because source_padding/target_padding represent
235    /// the offset there.
236    pub offset: LayoutVector2D,
237    /// Equal to the inflate value of the referenced buffer, or 0
238    pub inflate: i16,
239    /// Padding on each side to represent how this input is read relative to the
240    /// node's output subregion, this represents what the operation needs to
241    /// read from ths input, which may be blurred or offset.
242    pub source_padding: LayoutRect,
243    /// Padding on each side to represent how this input affects the node's
244    /// subregion, this can be used to calculate target subregion based on
245    /// SourceGraphic subregion.  This is usually equal to source_padding except
246    /// offset in the opposite direction, inflates typically do the same thing
247    /// to both types of padding.
248    pub target_padding: LayoutRect,
249}
250
251impl From<FilterOpGraphPictureReference> for FilterGraphPictureReference {
252    fn from(pic: FilterOpGraphPictureReference) -> Self {
253        FilterGraphPictureReference{
254            buffer_id: pic.buffer_id,
255            // All of these are set by wrap_prim_with_filters
256            subregion: LayoutRect::zero(),
257            offset: LayoutVector2D::zero(),
258            inflate: 0,
259            source_padding: LayoutRect::zero(),
260            target_padding: LayoutRect::zero(),
261        }
262    }
263}
264
265pub const SVGFE_CONVOLVE_DIAMETER_LIMIT: usize = 5;
266pub const SVGFE_CONVOLVE_VALUES_LIMIT: usize = SVGFE_CONVOLVE_DIAMETER_LIMIT *
267    SVGFE_CONVOLVE_DIAMETER_LIMIT;
268
269#[derive(Clone, Debug)]
270#[cfg_attr(feature = "capture", derive(Serialize))]
271#[cfg_attr(feature = "replay", derive(Deserialize))]
272pub enum FilterGraphOp {
273    /// Filter that copies the SourceGraphic image into the specified subregion,
274    /// This is intentionally the only way to get SourceGraphic into the graph,
275    /// as the filter region must be applied before it is used.
276    /// parameters: FilterOpGraphNode
277    /// SVG filter semantics - no inputs, no linear
278    SVGFESourceGraphic,
279    /// Filter that copies the SourceAlpha image into the specified subregion,
280    /// This is intentionally the only way to get SourceAlpha into the graph,
281    /// as the filter region must be applied before it is used.
282    /// parameters: FilterOpGraphNode
283    /// SVG filter semantics - no inputs, no linear
284    SVGFESourceAlpha,
285    /// Filter that does no transformation of the colors, used to implement a
286    /// few things like SVGFEOffset, and this is the default value in
287    /// impl_default_for_enums.
288    /// parameters: FilterGraphNode
289    /// SVG filter semantics - selectable input with offset
290    SVGFEIdentity,
291    /// represents CSS opacity property as a graph node like the rest of the
292    /// SVGFE* filters
293    /// parameters: FilterGraphNode
294    /// SVG filter semantics - selectable input(s), selectable between linear
295    /// (default) and sRGB color space for calculations
296    SVGFEOpacity{valuebinding: api::PropertyBinding<f32>, value: f32},
297    /// convert a color image to an alpha channel - internal use; generated by
298    /// SVGFilterInstance::GetOrCreateSourceAlphaIndex().
299    SVGFEToAlpha,
300    /// combine 2 images with SVG_FEBLEND_MODE_DARKEN
301    /// parameters: FilterGraphNode
302    /// SVG filter semantics - selectable input(s), selectable between linear
303    /// (default) and sRGB color space for calculations
304    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
305    SVGFEBlendDarken,
306    /// combine 2 images with SVG_FEBLEND_MODE_LIGHTEN
307    /// parameters: FilterGraphNode
308    /// SVG filter semantics - selectable input(s), selectable between linear
309    /// (default) and sRGB color space for calculations
310    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
311    SVGFEBlendLighten,
312    /// combine 2 images with SVG_FEBLEND_MODE_MULTIPLY
313    /// parameters: FilterGraphNode
314    /// SVG filter semantics - selectable input(s), selectable between linear
315    /// (default) and sRGB color space for calculations
316    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
317    SVGFEBlendMultiply,
318    /// combine 2 images with SVG_FEBLEND_MODE_NORMAL
319    /// parameters: FilterGraphNode
320    /// SVG filter semantics - selectable input(s), selectable between linear
321    /// (default) and sRGB color space for calculations
322    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
323    SVGFEBlendNormal,
324    /// combine 2 images with SVG_FEBLEND_MODE_SCREEN
325    /// parameters: FilterGraphNode
326    /// SVG filter semantics - selectable input(s), selectable between linear
327    /// (default) and sRGB color space for calculations
328    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
329    SVGFEBlendScreen,
330    /// combine 2 images with SVG_FEBLEND_MODE_OVERLAY
331    /// parameters: FilterOpGraphNode
332    /// SVG filter semantics - selectable input(s), selectable between linear
333    /// (default) and sRGB color space for calculations
334    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
335    SVGFEBlendOverlay,
336    /// combine 2 images with SVG_FEBLEND_MODE_COLOR_DODGE
337    /// parameters: FilterOpGraphNode
338    /// SVG filter semantics - selectable input(s), selectable between linear
339    /// (default) and sRGB color space for calculations
340    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
341    SVGFEBlendColorDodge,
342    /// combine 2 images with SVG_FEBLEND_MODE_COLOR_BURN
343    /// parameters: FilterOpGraphNode
344    /// SVG filter semantics - selectable input(s), selectable between linear
345    /// (default) and sRGB color space for calculations
346    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
347    SVGFEBlendColorBurn,
348    /// combine 2 images with SVG_FEBLEND_MODE_HARD_LIGHT
349    /// parameters: FilterOpGraphNode
350    /// SVG filter semantics - selectable input(s), selectable between linear
351    /// (default) and sRGB color space for calculations
352    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
353    SVGFEBlendHardLight,
354    /// combine 2 images with SVG_FEBLEND_MODE_SOFT_LIGHT
355    /// parameters: FilterOpGraphNode
356    /// SVG filter semantics - selectable input(s), selectable between linear
357    /// (default) and sRGB color space for calculations
358    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
359    SVGFEBlendSoftLight,
360    /// combine 2 images with SVG_FEBLEND_MODE_DIFFERENCE
361    /// parameters: FilterOpGraphNode
362    /// SVG filter semantics - selectable input(s), selectable between linear
363    /// (default) and sRGB color space for calculations
364    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
365    SVGFEBlendDifference,
366    /// combine 2 images with SVG_FEBLEND_MODE_EXCLUSION
367    /// parameters: FilterOpGraphNode
368    /// SVG filter semantics - selectable input(s), selectable between linear
369    /// (default) and sRGB color space for calculations
370    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
371    SVGFEBlendExclusion,
372    /// combine 2 images with SVG_FEBLEND_MODE_HUE
373    /// parameters: FilterOpGraphNode
374    /// SVG filter semantics - selectable input(s), selectable between linear
375    /// (default) and sRGB color space for calculations
376    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
377    SVGFEBlendHue,
378    /// combine 2 images with SVG_FEBLEND_MODE_SATURATION
379    /// parameters: FilterOpGraphNode
380    /// SVG filter semantics - selectable input(s), selectable between linear
381    /// (default) and sRGB color space for calculations
382    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
383    SVGFEBlendSaturation,
384    /// combine 2 images with SVG_FEBLEND_MODE_COLOR
385    /// parameters: FilterOpGraphNode
386    /// SVG filter semantics - selectable input(s), selectable between linear
387    /// (default) and sRGB color space for calculations
388    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
389    SVGFEBlendColor,
390    /// combine 2 images with SVG_FEBLEND_MODE_LUMINOSITY
391    /// parameters: FilterOpGraphNode
392    /// SVG filter semantics - selectable input(s), selectable between linear
393    /// (default) and sRGB color space for calculations
394    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
395    SVGFEBlendLuminosity,
396    /// transform colors of image through 5x4 color matrix (transposed for
397    /// efficiency)
398    /// parameters: FilterGraphNode, matrix[5][4]
399    /// SVG filter semantics - selectable input(s), selectable between linear
400    /// (default) and sRGB color space for calculations
401    /// Spec: https://www.w3.org/TR/filter-effects-1/#feColorMatrixElement
402    SVGFEColorMatrix{values: [f32; 20]},
403    /// transform colors of image through configurable gradients with component
404    /// swizzle
405    /// parameters: FilterGraphNode
406    /// SVG filter semantics - selectable input(s), selectable between linear
407    /// (default) and sRGB color space for calculations
408    /// Spec: https://www.w3.org/TR/filter-effects-1/#feComponentTransferElement
409    SVGFEComponentTransfer,
410    /// Processed version of SVGFEComponentTransfer with the FilterData
411    /// replaced by an interned handle, this is made in wrap_prim_with_filters.
412    /// Aside from the interned handle, creates_pixels indicates if the transfer
413    /// parameters will probably fill the entire subregion with non-zero alpha.
414    SVGFEComponentTransferInterned{handle: FilterDataHandle, creates_pixels: bool},
415    /// composite 2 images with chosen composite mode with parameters for that
416    /// mode
417    /// parameters: FilterGraphNode, k1, k2, k3, k4
418    /// SVG filter semantics - selectable input(s), selectable between linear
419    /// (default) and sRGB color space for calculations
420    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
421    SVGFECompositeArithmetic{k1: f32, k2: f32, k3: f32, k4: f32},
422    /// composite 2 images with chosen composite mode with parameters for that
423    /// mode
424    /// parameters: FilterGraphNode
425    /// SVG filter semantics - selectable input(s), selectable between linear
426    /// (default) and sRGB color space for calculations
427    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
428    SVGFECompositeATop,
429    /// composite 2 images with chosen composite mode with parameters for that
430    /// mode
431    /// parameters: FilterGraphNode
432    /// SVG filter semantics - selectable input(s), selectable between linear
433    /// (default) and sRGB color space for calculations
434    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
435    SVGFECompositeIn,
436    /// composite 2 images with chosen composite mode with parameters for that
437    /// mode
438    /// parameters: FilterOpGraphNode
439    /// SVG filter semantics - selectable input(s), selectable between linear
440    /// (default) and sRGB color space for calculations
441    /// Docs: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feComposite
442    SVGFECompositeLighter,
443    /// composite 2 images with chosen composite mode with parameters for that
444    /// mode
445    /// parameters: FilterGraphNode
446    /// SVG filter semantics - selectable input(s), selectable between linear
447    /// (default) and sRGB color space for calculations
448    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
449    SVGFECompositeOut,
450    /// composite 2 images with chosen composite mode with parameters for that
451    /// mode
452    /// parameters: FilterGraphNode
453    /// SVG filter semantics - selectable input(s), selectable between linear
454    /// (default) and sRGB color space for calculations
455    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
456    SVGFECompositeOver,
457    /// composite 2 images with chosen composite mode with parameters for that
458    /// mode
459    /// parameters: FilterGraphNode
460    /// SVG filter semantics - selectable input(s), selectable between linear
461    /// (default) and sRGB color space for calculations
462    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
463    SVGFECompositeXOR,
464    /// transform image through convolution matrix of up to 25 values (spec
465    /// allows more but for performance reasons we do not)
466    /// parameters: FilterGraphNode, orderX, orderY, kernelValues[25], divisor,
467    ///  bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY,
468    ///  preserveAlpha
469    /// SVG filter semantics - selectable input(s), selectable between linear
470    /// (default) and sRGB color space for calculations
471    /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement
472    SVGFEConvolveMatrixEdgeModeDuplicate{order_x: i32, order_y: i32,
473        kernel: [f32; SVGFE_CONVOLVE_VALUES_LIMIT], divisor: f32, bias: f32,
474        target_x: i32, target_y: i32, kernel_unit_length_x: f32,
475        kernel_unit_length_y: f32, preserve_alpha: i32},
476    /// transform image through convolution matrix of up to 25 values (spec
477    /// allows more but for performance reasons we do not)
478    /// parameters: FilterGraphNode, orderX, orderY, kernelValues[25], divisor,
479    ///  bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY,
480    ///  preserveAlpha
481    /// SVG filter semantics - selectable input(s), selectable between linear
482    /// (default) and sRGB color space for calculations
483    /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement
484    SVGFEConvolveMatrixEdgeModeNone{order_x: i32, order_y: i32,
485        kernel: [f32; SVGFE_CONVOLVE_VALUES_LIMIT], divisor: f32, bias: f32,
486        target_x: i32, target_y: i32, kernel_unit_length_x: f32,
487        kernel_unit_length_y: f32, preserve_alpha: i32},
488    /// transform image through convolution matrix of up to 25 values (spec
489    /// allows more but for performance reasons we do not)
490    /// parameters: FilterGraphNode, orderX, orderY, kernelValues[25], divisor,
491    ///  bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY,
492    ///  preserveAlpha
493    /// SVG filter semantics - selectable input(s), selectable between linear
494    /// (default) and sRGB color space for calculations
495    /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement
496    SVGFEConvolveMatrixEdgeModeWrap{order_x: i32, order_y: i32,
497        kernel: [f32; SVGFE_CONVOLVE_VALUES_LIMIT], divisor: f32, bias: f32,
498        target_x: i32, target_y: i32, kernel_unit_length_x: f32,
499        kernel_unit_length_y: f32, preserve_alpha: i32},
500    /// calculate lighting based on heightmap image with provided values for a
501    /// distant light source with specified direction
502    /// parameters: FilterGraphNode, surfaceScale, diffuseConstant,
503    ///  kernelUnitLengthX, kernelUnitLengthY, azimuth, elevation
504    /// SVG filter semantics - selectable input(s), selectable between linear
505    /// (default) and sRGB color space for calculations
506    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement
507    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDistantLightElement
508    SVGFEDiffuseLightingDistant{surface_scale: f32, diffuse_constant: f32,
509        kernel_unit_length_x: f32, kernel_unit_length_y: f32, azimuth: f32,
510        elevation: f32},
511    /// calculate lighting based on heightmap image with provided values for a
512    /// point light source at specified location
513    /// parameters: FilterGraphNode, surfaceScale, diffuseConstant,
514    ///  kernelUnitLengthX, kernelUnitLengthY, x, y, z
515    /// SVG filter semantics - selectable input(s), selectable between linear
516    /// (default) and sRGB color space for calculations
517    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement
518    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEPointLightElement
519    SVGFEDiffuseLightingPoint{surface_scale: f32, diffuse_constant: f32,
520        kernel_unit_length_x: f32, kernel_unit_length_y: f32, x: f32, y: f32,
521        z: f32},
522    /// calculate lighting based on heightmap image with provided values for a
523    /// spot light source at specified location pointing at specified target
524    /// location with specified hotspot sharpness and cone angle
525    /// parameters: FilterGraphNode, surfaceScale, diffuseConstant,
526    ///  kernelUnitLengthX, kernelUnitLengthY, x, y, z, pointsAtX, pointsAtY,
527    ///  pointsAtZ, specularExponent, limitingConeAngle
528    /// SVG filter semantics - selectable input(s), selectable between linear
529    /// (default) and sRGB color space for calculations
530    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement
531    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpotLightElement
532    SVGFEDiffuseLightingSpot{surface_scale: f32, diffuse_constant: f32,
533        kernel_unit_length_x: f32, kernel_unit_length_y: f32, x: f32, y: f32,
534        z: f32, points_at_x: f32, points_at_y: f32, points_at_z: f32,
535        cone_exponent: f32, limiting_cone_angle: f32},
536    /// calculate a distorted version of first input image using offset values
537    /// from second input image at specified intensity
538    /// parameters: FilterGraphNode, scale, xChannelSelector, yChannelSelector
539    /// SVG filter semantics - selectable input(s), selectable between linear
540    /// (default) and sRGB color space for calculations
541    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDisplacementMapElement
542    SVGFEDisplacementMap{scale: f32, x_channel_selector: u32,
543        y_channel_selector: u32},
544    /// create and merge a dropshadow version of the specified image's alpha
545    /// channel with specified offset and blur radius
546    /// parameters: FilterGraphNode, flood_color, flood_opacity, dx, dy,
547    ///  stdDeviationX, stdDeviationY
548    /// SVG filter semantics - selectable input(s), selectable between linear
549    /// (default) and sRGB color space for calculations
550    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDropShadowElement
551    SVGFEDropShadow{color: ColorF, dx: f32, dy: f32, std_deviation_x: f32,
552        std_deviation_y: f32},
553    /// synthesize a new image of specified size containing a solid color
554    /// parameters: FilterGraphNode, color
555    /// SVG filter semantics - selectable input(s), selectable between linear
556    /// (default) and sRGB color space for calculations
557    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEFloodElement
558    SVGFEFlood{color: ColorF},
559    /// create a blurred version of the input image
560    /// parameters: FilterGraphNode, stdDeviationX, stdDeviationY
561    /// SVG filter semantics - selectable input(s), selectable between linear
562    /// (default) and sRGB color space for calculations
563    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEGaussianBlurElement
564    SVGFEGaussianBlur{std_deviation_x: f32, std_deviation_y: f32},
565    /// synthesize a new image based on a url (i.e. blob image source)
566    /// parameters: FilterGraphNode,
567    ///  samplingFilter (see SamplingFilter in Types.h), transform
568    /// SVG filter semantics - selectable input(s), selectable between linear
569    /// (default) and sRGB color space for calculations
570    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEImageElement
571    SVGFEImage{sampling_filter: u32, matrix: [f32; 6]},
572    /// create a new image based on the input image with the contour stretched
573    /// outward (dilate operator)
574    /// parameters: FilterGraphNode, radiusX, radiusY
575    /// SVG filter semantics - selectable input(s), selectable between linear
576    /// (default) and sRGB color space for calculations
577    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEMorphologyElement
578    SVGFEMorphologyDilate{radius_x: f32, radius_y: f32},
579    /// create a new image based on the input image with the contour shrunken
580    /// inward (erode operator)
581    /// parameters: FilterGraphNode, radiusX, radiusY
582    /// SVG filter semantics - selectable input(s), selectable between linear
583    /// (default) and sRGB color space for calculations
584    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEMorphologyElement
585    SVGFEMorphologyErode{radius_x: f32, radius_y: f32},
586    /// calculate lighting based on heightmap image with provided values for a
587    /// distant light source with specified direction
588    /// parameters: FilerData, surfaceScale, specularConstant, specularExponent,
589    ///  kernelUnitLengthX, kernelUnitLengthY, azimuth, elevation
590    /// SVG filter semantics - selectable input(s), selectable between linear
591    /// (default) and sRGB color space for calculations
592    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement
593    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDistantLightElement
594    SVGFESpecularLightingDistant{surface_scale: f32, specular_constant: f32,
595        specular_exponent: f32, kernel_unit_length_x: f32,
596        kernel_unit_length_y: f32, azimuth: f32, elevation: f32},
597    /// calculate lighting based on heightmap image with provided values for a
598    /// point light source at specified location
599    /// parameters: FilterGraphNode, surfaceScale, specularConstant,
600    ///  specularExponent, kernelUnitLengthX, kernelUnitLengthY, x, y, z
601    /// SVG filter semantics - selectable input(s), selectable between linear
602    /// (default) and sRGB color space for calculations
603    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement
604    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEPointLightElement
605    SVGFESpecularLightingPoint{surface_scale: f32, specular_constant: f32,
606        specular_exponent: f32, kernel_unit_length_x: f32,
607        kernel_unit_length_y: f32, x: f32, y: f32, z: f32},
608    /// calculate lighting based on heightmap image with provided values for a
609    /// spot light source at specified location pointing at specified target
610    /// location with specified hotspot sharpness and cone angle
611    /// parameters: FilterGraphNode, surfaceScale, specularConstant,
612    ///  specularExponent, kernelUnitLengthX, kernelUnitLengthY, x, y, z,
613    ///  pointsAtX, pointsAtY, pointsAtZ, specularExponent, limitingConeAngle
614    /// SVG filter semantics - selectable input(s), selectable between linear
615    /// (default) and sRGB color space for calculations
616    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement
617    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpotLightElement
618    SVGFESpecularLightingSpot{surface_scale: f32, specular_constant: f32,
619        specular_exponent: f32, kernel_unit_length_x: f32,
620        kernel_unit_length_y: f32, x: f32, y: f32, z: f32, points_at_x: f32,
621        points_at_y: f32, points_at_z: f32, cone_exponent: f32,
622        limiting_cone_angle: f32},
623    /// create a new image based on the input image, repeated throughout the
624    /// output rectangle
625    /// parameters: FilterGraphNode
626    /// SVG filter semantics - selectable input(s), selectable between linear
627    /// (default) and sRGB color space for calculations
628    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETileElement
629    SVGFETile,
630    /// synthesize a new image based on Fractal Noise (Perlin) with the chosen
631    /// stitching mode
632    /// parameters: FilterGraphNode, baseFrequencyX, baseFrequencyY, numOctaves,
633    ///  seed
634    /// SVG filter semantics - selectable input(s), selectable between linear
635    /// (default) and sRGB color space for calculations
636    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
637    SVGFETurbulenceWithFractalNoiseWithNoStitching{base_frequency_x: f32,
638        base_frequency_y: f32, num_octaves: u32, seed: u32},
639    /// synthesize a new image based on Fractal Noise (Perlin) with the chosen
640    /// stitching mode
641    /// parameters: FilterGraphNode, baseFrequencyX, baseFrequencyY, numOctaves,
642    ///  seed
643    /// SVG filter semantics - selectable input(s), selectable between linear
644    /// (default) and sRGB color space for calculations
645    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
646    SVGFETurbulenceWithFractalNoiseWithStitching{base_frequency_x: f32,
647        base_frequency_y: f32, num_octaves: u32, seed: u32},
648    /// synthesize a new image based on Turbulence Noise (offset vectors)
649    /// parameters: FilterGraphNode, baseFrequencyX, baseFrequencyY, numOctaves,
650    ///  seed
651    /// SVG filter semantics - selectable input(s), selectable between linear
652    /// (default) and sRGB color space for calculations
653    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
654    SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{base_frequency_x: f32,
655        base_frequency_y: f32, num_octaves: u32, seed: u32},
656    /// synthesize a new image based on Turbulence Noise (offset vectors)
657    /// parameters: FilterGraphNode, baseFrequencyX, baseFrequencyY, numOctaves,
658    ///  seed
659    /// SVG filter semantics - selectable input(s), selectable between linear
660    /// (default) and sRGB color space for calculations
661    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
662    SVGFETurbulenceWithTurbulenceNoiseWithStitching{base_frequency_x: f32,
663        base_frequency_y: f32, num_octaves: u32, seed: u32},
664}
665
666impl FilterGraphOp {
667    pub fn kind(&self) -> &'static str {
668        match *self {
669            FilterGraphOp::SVGFEBlendColor => "SVGFEBlendColor",
670            FilterGraphOp::SVGFEBlendColorBurn => "SVGFEBlendColorBurn",
671            FilterGraphOp::SVGFEBlendColorDodge => "SVGFEBlendColorDodge",
672            FilterGraphOp::SVGFEBlendDarken => "SVGFEBlendDarken",
673            FilterGraphOp::SVGFEBlendDifference => "SVGFEBlendDifference",
674            FilterGraphOp::SVGFEBlendExclusion => "SVGFEBlendExclusion",
675            FilterGraphOp::SVGFEBlendHardLight => "SVGFEBlendHardLight",
676            FilterGraphOp::SVGFEBlendHue => "SVGFEBlendHue",
677            FilterGraphOp::SVGFEBlendLighten => "SVGFEBlendLighten",
678            FilterGraphOp::SVGFEBlendLuminosity => "SVGFEBlendLuminosity",
679            FilterGraphOp::SVGFEBlendMultiply => "SVGFEBlendMultiply",
680            FilterGraphOp::SVGFEBlendNormal => "SVGFEBlendNormal",
681            FilterGraphOp::SVGFEBlendOverlay => "SVGFEBlendOverlay",
682            FilterGraphOp::SVGFEBlendSaturation => "SVGFEBlendSaturation",
683            FilterGraphOp::SVGFEBlendScreen => "SVGFEBlendScreen",
684            FilterGraphOp::SVGFEBlendSoftLight => "SVGFEBlendSoftLight",
685            FilterGraphOp::SVGFEColorMatrix{..} => "SVGFEColorMatrix",
686            FilterGraphOp::SVGFEComponentTransfer => "SVGFEComponentTransfer",
687            FilterGraphOp::SVGFEComponentTransferInterned{..} => "SVGFEComponentTransferInterned",
688            FilterGraphOp::SVGFECompositeArithmetic{..} => "SVGFECompositeArithmetic",
689            FilterGraphOp::SVGFECompositeATop => "SVGFECompositeATop",
690            FilterGraphOp::SVGFECompositeIn => "SVGFECompositeIn",
691            FilterGraphOp::SVGFECompositeLighter => "SVGFECompositeLighter",
692            FilterGraphOp::SVGFECompositeOut => "SVGFECompositeOut",
693            FilterGraphOp::SVGFECompositeOver => "SVGFECompositeOver",
694            FilterGraphOp::SVGFECompositeXOR => "SVGFECompositeXOR",
695            FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{..} => "SVGFEConvolveMatrixEdgeModeDuplicate",
696            FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{..} => "SVGFEConvolveMatrixEdgeModeNone",
697            FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{..} => "SVGFEConvolveMatrixEdgeModeWrap",
698            FilterGraphOp::SVGFEDiffuseLightingDistant{..} => "SVGFEDiffuseLightingDistant",
699            FilterGraphOp::SVGFEDiffuseLightingPoint{..} => "SVGFEDiffuseLightingPoint",
700            FilterGraphOp::SVGFEDiffuseLightingSpot{..} => "SVGFEDiffuseLightingSpot",
701            FilterGraphOp::SVGFEDisplacementMap{..} => "SVGFEDisplacementMap",
702            FilterGraphOp::SVGFEDropShadow{..} => "SVGFEDropShadow",
703            FilterGraphOp::SVGFEFlood{..} => "SVGFEFlood",
704            FilterGraphOp::SVGFEGaussianBlur{..} => "SVGFEGaussianBlur",
705            FilterGraphOp::SVGFEIdentity => "SVGFEIdentity",
706            FilterGraphOp::SVGFEImage{..} => "SVGFEImage",
707            FilterGraphOp::SVGFEMorphologyDilate{..} => "SVGFEMorphologyDilate",
708            FilterGraphOp::SVGFEMorphologyErode{..} => "SVGFEMorphologyErode",
709            FilterGraphOp::SVGFEOpacity{..} => "SVGFEOpacity",
710            FilterGraphOp::SVGFESourceAlpha => "SVGFESourceAlpha",
711            FilterGraphOp::SVGFESourceGraphic => "SVGFESourceGraphic",
712            FilterGraphOp::SVGFESpecularLightingDistant{..} => "SVGFESpecularLightingDistant",
713            FilterGraphOp::SVGFESpecularLightingPoint{..} => "SVGFESpecularLightingPoint",
714            FilterGraphOp::SVGFESpecularLightingSpot{..} => "SVGFESpecularLightingSpot",
715            FilterGraphOp::SVGFETile => "SVGFETile",
716            FilterGraphOp::SVGFEToAlpha => "SVGFEToAlpha",
717            FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} => "SVGFETurbulenceWithFractalNoiseWithNoStitching",
718            FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} => "SVGFETurbulenceWithFractalNoiseWithStitching",
719            FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} => "SVGFETurbulenceWithTurbulenceNoiseWithNoStitching",
720            FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => "SVGFETurbulenceWithTurbulenceNoiseWithStitching",
721        }
722    }
723}
724
725#[derive(Clone, Debug)]
726#[cfg_attr(feature = "capture", derive(Serialize))]
727#[cfg_attr(feature = "replay", derive(Deserialize))]
728pub struct FilterGraphNode {
729    /// Indicates this graph node was marked as necessary by the DAG optimizer
730    pub kept_by_optimizer: bool,
731    /// true if color_interpolation_filter == LinearRgb; shader will convert
732    /// sRGB texture pixel colors on load and convert back on store, for correct
733    /// interpolation
734    pub linear: bool,
735    /// padding for output rect if we need a border to get correct clamping, or
736    /// to account for larger final subregion than source rect (see bug 1869672)
737    pub inflate: i16,
738    /// virtualized picture input bindings, these refer to other filter outputs
739    /// by number within the graph, usually there is one element
740    pub inputs: Vec<FilterGraphPictureReference>,
741    /// clipping rect for filter node output
742    pub subregion: LayoutRect,
743}
744
745impl From<FilterOpGraphNode> for FilterGraphNode {
746    fn from(node: FilterOpGraphNode) -> Self {
747        let mut inputs: Vec<FilterGraphPictureReference> = Vec::new();
748        if node.input.buffer_id != FilterOpGraphPictureBufferId::None {
749            inputs.push(node.input.into());
750        }
751        if node.input2.buffer_id != FilterOpGraphPictureBufferId::None {
752            inputs.push(node.input2.into());
753        }
754        // If the op used by this node is a feMerge, it will add more inputs
755        // after this invocation.
756        FilterGraphNode{
757            linear: node.linear,
758            inputs,
759            subregion: node.subregion,
760            // These are computed later in scene_building
761            kept_by_optimizer: true,
762            inflate: 0,
763        }
764    }
765}
766
767
768/// Equivalent to api::FilterOp with added internal information
769#[derive(Clone, Debug)]
770#[cfg_attr(feature = "capture", derive(Serialize))]
771#[cfg_attr(feature = "replay", derive(Deserialize))]
772pub enum Filter {
773    Identity,
774    Blur {
775        width: f32,
776        height: f32,
777        should_inflate: bool,
778        edge_mode: BlurEdgeMode,
779    },
780    Brightness(f32),
781    Contrast(f32),
782    Grayscale(f32),
783    HueRotate(f32),
784    Invert(f32),
785    Opacity(api::PropertyBinding<f32>, f32),
786    Saturate(f32),
787    Sepia(f32),
788    DropShadows(SmallVec<[Shadow; 1]>),
789    ColorMatrix(Box<[f32; 20]>),
790    SrgbToLinear,
791    LinearToSrgb,
792    ComponentTransfer,
793    Flood(ColorF),
794    SVGGraphNode(FilterGraphNode, FilterGraphOp),
795}
796
797impl Filter {
798    pub fn is_visible(&self) -> bool {
799        match *self {
800            Filter::Identity |
801            Filter::Blur { .. } |
802            Filter::Brightness(..) |
803            Filter::Contrast(..) |
804            Filter::Grayscale(..) |
805            Filter::HueRotate(..) |
806            Filter::Invert(..) |
807            Filter::Saturate(..) |
808            Filter::Sepia(..) |
809            Filter::DropShadows(..) |
810            Filter::ColorMatrix(..) |
811            Filter::SrgbToLinear |
812            Filter::LinearToSrgb |
813            Filter::ComponentTransfer  => true,
814            Filter::Opacity(_, amount) => {
815                amount > OPACITY_EPSILON
816            },
817            Filter::Flood(color) => {
818                color.a > OPACITY_EPSILON
819            }
820            Filter::SVGGraphNode(..) => true,
821        }
822    }
823
824    pub fn is_noop(&self) -> bool {
825        match *self {
826            Filter::Identity => false, // this is intentional
827            Filter::Blur { width, height, .. } => width == 0.0 && height == 0.0,
828            Filter::Brightness(amount) => amount == 1.0,
829            Filter::Contrast(amount) => amount == 1.0,
830            Filter::Grayscale(amount) => amount == 0.0,
831            Filter::HueRotate(amount) => amount == 0.0,
832            Filter::Invert(amount) => amount == 0.0,
833            Filter::Opacity(api::PropertyBinding::Value(amount), _) => amount >= 1.0,
834            Filter::Saturate(amount) => amount == 1.0,
835            Filter::Sepia(amount) => amount == 0.0,
836            Filter::DropShadows(ref shadows) => {
837                for shadow in shadows {
838                    if shadow.offset.x != 0.0 || shadow.offset.y != 0.0 || shadow.blur_radius != 0.0 {
839                        return false;
840                    }
841                }
842
843                true
844            }
845            Filter::ColorMatrix(ref matrix) => {
846                **matrix == [
847                    1.0, 0.0, 0.0, 0.0,
848                    0.0, 1.0, 0.0, 0.0,
849                    0.0, 0.0, 1.0, 0.0,
850                    0.0, 0.0, 0.0, 1.0,
851                    0.0, 0.0, 0.0, 0.0
852                ]
853            }
854            Filter::Opacity(api::PropertyBinding::Binding(..), _) |
855            Filter::SrgbToLinear |
856            Filter::LinearToSrgb |
857            Filter::ComponentTransfer |
858            Filter::Flood(..) => false,
859            Filter::SVGGraphNode(..) => false,
860        }
861    }
862
863
864    pub fn as_int(&self) -> i32 {
865        // Must be kept in sync with brush_blend.glsl
866        match *self {
867            Filter::Identity => 0, // matches `Contrast(1)`
868            Filter::Contrast(..) => 0,
869            Filter::Grayscale(..) => 1,
870            Filter::HueRotate(..) => 2,
871            Filter::Invert(..) => 3,
872            Filter::Saturate(..) => 4,
873            Filter::Sepia(..) => 5,
874            Filter::Brightness(..) => 6,
875            Filter::ColorMatrix(..) => 7,
876            Filter::SrgbToLinear => 8,
877            Filter::LinearToSrgb => 9,
878            Filter::Flood(..) => 10,
879            Filter::ComponentTransfer => 11,
880            Filter::Blur { .. } => 12,
881            Filter::DropShadows(..) => 13,
882            Filter::Opacity(..) => 14,
883            Filter::SVGGraphNode(..) => unreachable!("SVGGraphNode handled elsewhere"),
884        }
885    }
886}
887
888impl From<FilterOp> for Filter {
889    fn from(op: FilterOp) -> Self {
890        match op {
891            FilterOp::Identity => Filter::Identity,
892            FilterOp::Blur(width, height) => Filter::Blur {
893                width,
894                height,
895                should_inflate: true,
896                edge_mode: BlurEdgeMode::Duplicate,
897            },
898            FilterOp::Brightness(b) => Filter::Brightness(b),
899            FilterOp::Contrast(c) => Filter::Contrast(c),
900            FilterOp::Grayscale(g) => Filter::Grayscale(g),
901            FilterOp::HueRotate(h) => Filter::HueRotate(h),
902            FilterOp::Invert(i) => Filter::Invert(i),
903            FilterOp::Opacity(binding, opacity) => Filter::Opacity(binding, opacity),
904            FilterOp::Saturate(s) => Filter::Saturate(s),
905            FilterOp::Sepia(s) => Filter::Sepia(s),
906            FilterOp::ColorMatrix(mat) => Filter::ColorMatrix(Box::new(mat)),
907            FilterOp::SrgbToLinear => Filter::SrgbToLinear,
908            FilterOp::LinearToSrgb => Filter::LinearToSrgb,
909            FilterOp::ComponentTransfer => Filter::ComponentTransfer,
910            FilterOp::DropShadow(shadow) => Filter::DropShadows(smallvec![shadow]),
911            FilterOp::Flood(color) => Filter::Flood(color),
912            FilterOp::SVGFEBlendColor{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendColor),
913            FilterOp::SVGFEBlendColorBurn{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendColorBurn),
914            FilterOp::SVGFEBlendColorDodge{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendColorDodge),
915            FilterOp::SVGFEBlendDarken{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendDarken),
916            FilterOp::SVGFEBlendDifference{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendDifference),
917            FilterOp::SVGFEBlendExclusion{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendExclusion),
918            FilterOp::SVGFEBlendHardLight{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendHardLight),
919            FilterOp::SVGFEBlendHue{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendHue),
920            FilterOp::SVGFEBlendLighten{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendLighten),
921            FilterOp::SVGFEBlendLuminosity{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendLuminosity),
922            FilterOp::SVGFEBlendMultiply{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendMultiply),
923            FilterOp::SVGFEBlendNormal{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendNormal),
924            FilterOp::SVGFEBlendOverlay{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendOverlay),
925            FilterOp::SVGFEBlendSaturation{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendSaturation),
926            FilterOp::SVGFEBlendScreen{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendScreen),
927            FilterOp::SVGFEBlendSoftLight{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendSoftLight),
928            FilterOp::SVGFEColorMatrix{node, values} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEColorMatrix{values}),
929            FilterOp::SVGFEComponentTransfer{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEComponentTransfer),
930            FilterOp::SVGFECompositeArithmetic{node, k1, k2, k3, k4} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeArithmetic{k1, k2, k3, k4}),
931            FilterOp::SVGFECompositeATop{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeATop),
932            FilterOp::SVGFECompositeIn{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeIn),
933            FilterOp::SVGFECompositeLighter{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeLighter),
934            FilterOp::SVGFECompositeOut{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeOut),
935            FilterOp::SVGFECompositeOver{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeOver),
936            FilterOp::SVGFECompositeXOR{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeXOR),
937            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}),
938            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}),
939            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}),
940            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}),
941            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}),
942            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}),
943            FilterOp::SVGFEDisplacementMap{node, scale, x_channel_selector, y_channel_selector} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEDisplacementMap{scale, x_channel_selector, y_channel_selector}),
944            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}),
945            FilterOp::SVGFEFlood{node, color} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEFlood{color}),
946            FilterOp::SVGFEGaussianBlur{node, std_deviation_x, std_deviation_y} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEGaussianBlur{std_deviation_x, std_deviation_y}),
947            FilterOp::SVGFEIdentity{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEIdentity),
948            FilterOp::SVGFEImage{node, sampling_filter, matrix} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEImage{sampling_filter, matrix}),
949            FilterOp::SVGFEMorphologyDilate{node, radius_x, radius_y} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEMorphologyDilate{radius_x, radius_y}),
950            FilterOp::SVGFEMorphologyErode{node, radius_x, radius_y} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEMorphologyErode{radius_x, radius_y}),
951            FilterOp::SVGFEOffset{node, offset_x, offset_y} => {
952                Filter::SVGGraphNode(
953                    FilterGraphNode {
954                        kept_by_optimizer: true, // computed later in scene_building
955                        linear: node.linear,
956                        inflate: 0, // computed later in scene_building
957                        inputs: [FilterGraphPictureReference {
958                            buffer_id: node.input.buffer_id,
959                            offset: LayoutVector2D::new(offset_x, offset_y),
960                            subregion: LayoutRect::zero(),
961                            inflate: 0,
962                            source_padding: LayoutRect::zero(),
963                            target_padding: LayoutRect::zero(),
964                        }].to_vec(),
965                        subregion: node.subregion,
966                    },
967                    FilterGraphOp::SVGFEIdentity,
968                )
969            },
970            FilterOp::SVGFEOpacity{node, valuebinding, value} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEOpacity{valuebinding, value}),
971            FilterOp::SVGFESourceAlpha{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFESourceAlpha),
972            FilterOp::SVGFESourceGraphic{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFESourceGraphic),
973            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}),
974            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}),
975            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}),
976            FilterOp::SVGFETile{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFETile),
977            FilterOp::SVGFEToAlpha{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEToAlpha),
978            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}),
979            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}),
980            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}),
981            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}),
982        }
983    }
984}
985
986#[cfg_attr(feature = "capture", derive(Serialize))]
987#[cfg_attr(feature = "replay", derive(Deserialize))]
988#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
989pub enum Swizzle {
990    Rgba,
991    Bgra,
992}
993
994impl Default for Swizzle {
995    fn default() -> Self {
996        Swizzle::Rgba
997    }
998}
999
1000/// Swizzle settings of the texture cache.
1001#[cfg_attr(feature = "capture", derive(Serialize))]
1002#[cfg_attr(feature = "replay", derive(Deserialize))]
1003#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
1004pub struct SwizzleSettings {
1005    /// Swizzle required on sampling a texture with BGRA8 format.
1006    pub bgra8_sampling_swizzle: Swizzle,
1007}
1008
1009/// An ID for a texture that is owned by the `texture_cache` module.
1010///
1011/// This can include atlases or standalone textures allocated via the texture
1012/// cache (e.g.  if an image is too large to be added to an atlas). The texture
1013/// cache manages the allocation and freeing of these IDs, and the rendering
1014/// thread maintains a map from cache texture ID to native texture.
1015///
1016/// We never reuse IDs, so we use a u64 here to be safe.
1017#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1018#[cfg_attr(feature = "capture", derive(Serialize))]
1019#[cfg_attr(feature = "replay", derive(Deserialize))]
1020pub struct CacheTextureId(pub u32);
1021
1022impl CacheTextureId {
1023    pub const INVALID: CacheTextureId = CacheTextureId(!0);
1024}
1025
1026#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1027#[cfg_attr(feature = "capture", derive(Serialize))]
1028#[cfg_attr(feature = "replay", derive(Deserialize))]
1029pub struct DeferredResolveIndex(pub u32);
1030
1031#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1032#[cfg_attr(feature = "capture", derive(Serialize))]
1033#[cfg_attr(feature = "replay", derive(Deserialize))]
1034pub struct TextureSourceExternal {
1035    pub index: DeferredResolveIndex,
1036    pub kind: ImageBufferKind,
1037    pub normalized_uvs: bool,
1038}
1039
1040/// Identifies the source of an input texture to a shader.
1041#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1042#[cfg_attr(feature = "capture", derive(Serialize))]
1043#[cfg_attr(feature = "replay", derive(Deserialize))]
1044pub enum TextureSource {
1045    /// Equivalent to `None`, allowing us to avoid using `Option`s everywhere.
1046    Invalid,
1047    /// An entry in the texture cache.
1048    TextureCache(CacheTextureId, Swizzle),
1049    /// An external image texture, mananged by the embedding.
1050    External(TextureSourceExternal),
1051    /// Select a dummy 1x1 white texture. This can be used by image
1052    /// shaders that want to draw a solid color.
1053    Dummy,
1054}
1055
1056impl TextureSource {
1057    pub fn image_buffer_kind(&self) -> ImageBufferKind {
1058        match *self {
1059            TextureSource::TextureCache(..) => ImageBufferKind::Texture2D,
1060
1061            TextureSource::External(TextureSourceExternal { kind, .. }) => kind,
1062
1063            // Render tasks use texture arrays for now.
1064            TextureSource::Dummy => ImageBufferKind::Texture2D,
1065
1066            TextureSource::Invalid => ImageBufferKind::Texture2D,
1067        }
1068    }
1069
1070    pub fn uses_normalized_uvs(&self) -> bool {
1071        match *self {
1072            TextureSource::External(TextureSourceExternal { normalized_uvs, .. }) => normalized_uvs,
1073            _ => false,
1074        }
1075    }
1076
1077    #[inline]
1078    pub fn is_compatible(
1079        &self,
1080        other: &TextureSource,
1081    ) -> bool {
1082        *self == TextureSource::Invalid ||
1083        *other == TextureSource::Invalid ||
1084        self == other
1085    }
1086}
1087
1088#[derive(Copy, Clone, Debug, PartialEq)]
1089#[cfg_attr(feature = "capture", derive(Serialize))]
1090#[cfg_attr(feature = "replay", derive(Deserialize))]
1091pub struct RenderTargetInfo {
1092    pub has_depth: bool,
1093}
1094
1095#[derive(Debug)]
1096pub enum TextureUpdateSource {
1097    External {
1098        id: ExternalImageId,
1099        channel_index: u8,
1100    },
1101    Bytes { data: Arc<Vec<u8>> },
1102    /// Clears the target area, rather than uploading any pixels. Used when the
1103    /// texture cache debug display is active.
1104    DebugClear,
1105}
1106
1107/// Command to allocate, reallocate, or free a texture for the texture cache.
1108#[derive(Debug)]
1109pub struct TextureCacheAllocation {
1110    /// The virtual ID (i.e. distinct from device ID) of the texture.
1111    pub id: CacheTextureId,
1112    /// Details corresponding to the operation in question.
1113    pub kind: TextureCacheAllocationKind,
1114}
1115
1116/// A little bit of extra information to make memory reports more useful
1117#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1118#[cfg_attr(feature = "capture", derive(Serialize))]
1119#[cfg_attr(feature = "replay", derive(Deserialize))]
1120pub enum TextureCacheCategory {
1121    Atlas,
1122    Standalone,
1123    PictureTile,
1124    RenderTarget,
1125}
1126
1127/// Information used when allocating / reallocating.
1128#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1129pub struct TextureCacheAllocInfo {
1130    pub width: i32,
1131    pub height: i32,
1132    pub format: ImageFormat,
1133    pub filter: TextureFilter,
1134    pub target: ImageBufferKind,
1135    /// Indicates whether this corresponds to one of the shared texture caches.
1136    pub is_shared_cache: bool,
1137    /// If true, this texture requires a depth target.
1138    pub has_depth: bool,
1139    pub category: TextureCacheCategory
1140}
1141
1142/// Sub-operation-specific information for allocation operations.
1143#[derive(Debug)]
1144pub enum TextureCacheAllocationKind {
1145    /// Performs an initial texture allocation.
1146    Alloc(TextureCacheAllocInfo),
1147    /// Reallocates the texture without preserving its contents.
1148    Reset(TextureCacheAllocInfo),
1149    /// Frees the texture and the corresponding cache ID.
1150    Free,
1151}
1152
1153/// Command to update the contents of the texture cache.
1154#[derive(Debug)]
1155pub struct TextureCacheUpdate {
1156    pub rect: DeviceIntRect,
1157    pub stride: Option<i32>,
1158    pub offset: i32,
1159    pub format_override: Option<ImageFormat>,
1160    pub source: TextureUpdateSource,
1161}
1162
1163/// Command to update the contents of the texture cache.
1164#[derive(Debug)]
1165pub struct TextureCacheCopy {
1166    pub src_rect: DeviceIntRect,
1167    pub dst_rect: DeviceIntRect,
1168}
1169
1170/// Atomic set of commands to manipulate the texture cache, generated on the
1171/// RenderBackend thread and executed on the Renderer thread.
1172///
1173/// The list of allocation operations is processed before the updates. This is
1174/// important to allow coalescing of certain allocation operations.
1175#[derive(Default)]
1176pub struct TextureUpdateList {
1177    /// Indicates that there was some kind of cleanup clear operation. Used for
1178    /// sanity checks.
1179    pub clears_shared_cache: bool,
1180    /// Commands to alloc/realloc/free the textures. Processed first.
1181    pub allocations: Vec<TextureCacheAllocation>,
1182    /// Commands to update the contents of the textures. Processed second.
1183    pub updates: FastHashMap<CacheTextureId, Vec<TextureCacheUpdate>>,
1184    /// Commands to move items within the cache, these are applied before everything
1185    /// else in the update list.
1186    pub copies: FastHashMap<(CacheTextureId, CacheTextureId), Vec<TextureCacheCopy>>,
1187}
1188
1189impl TextureUpdateList {
1190    /// Mints a new `TextureUpdateList`.
1191    pub fn new() -> Self {
1192        TextureUpdateList {
1193            clears_shared_cache: false,
1194            allocations: Vec::new(),
1195            updates: FastHashMap::default(),
1196            copies: FastHashMap::default(),
1197        }
1198    }
1199
1200    /// Returns true if this is a no-op (no updates to be applied).
1201    pub fn is_nop(&self) -> bool {
1202        self.allocations.is_empty() && self.updates.is_empty()
1203    }
1204
1205    /// Sets the clears_shared_cache flag for renderer-side sanity checks.
1206    #[inline]
1207    pub fn note_clear(&mut self) {
1208        self.clears_shared_cache = true;
1209    }
1210
1211    /// Pushes an update operation onto the list.
1212    #[inline]
1213    pub fn push_update(&mut self, id: CacheTextureId, update: TextureCacheUpdate) {
1214        self.updates
1215            .entry(id)
1216            .or_default()
1217            .push(update);
1218    }
1219
1220    /// Sends a command to the Renderer to clear the portion of the shared region
1221    /// we just freed. Used when the texture cache debugger is enabled.
1222    #[cold]
1223    pub fn push_debug_clear(
1224        &mut self,
1225        id: CacheTextureId,
1226        origin: DeviceIntPoint,
1227        width: i32,
1228        height: i32,
1229    ) {
1230        let size = DeviceIntSize::new(width, height);
1231        let rect = DeviceIntRect::from_origin_and_size(origin, size);
1232        self.push_update(id, TextureCacheUpdate {
1233            rect,
1234            stride: None,
1235            offset: 0,
1236            format_override: None,
1237            source: TextureUpdateSource::DebugClear,
1238        });
1239    }
1240
1241
1242    /// Pushes an allocation operation onto the list.
1243    pub fn push_alloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
1244        debug_assert!(!self.allocations.iter().any(|x| x.id == id));
1245        self.allocations.push(TextureCacheAllocation {
1246            id,
1247            kind: TextureCacheAllocationKind::Alloc(info),
1248        });
1249    }
1250
1251    /// Pushes a reallocation operation onto the list, potentially coalescing
1252    /// with previous operations.
1253    pub fn push_reset(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
1254        self.debug_assert_coalesced(id);
1255
1256        // Drop any unapplied updates to the to-be-freed texture.
1257        self.updates.remove(&id);
1258
1259        // Coallesce this realloc into a previous alloc or realloc, if available.
1260        if let Some(cur) = self.allocations.iter_mut().find(|x| x.id == id) {
1261            match cur.kind {
1262                TextureCacheAllocationKind::Alloc(ref mut i) => *i = info,
1263                TextureCacheAllocationKind::Reset(ref mut i) => *i = info,
1264                TextureCacheAllocationKind::Free => panic!("Resetting freed texture"),
1265            }
1266            return
1267        }
1268
1269        self.allocations.push(TextureCacheAllocation {
1270            id,
1271            kind: TextureCacheAllocationKind::Reset(info),
1272        });
1273    }
1274
1275    /// Pushes a free operation onto the list, potentially coalescing with
1276    /// previous operations.
1277    pub fn push_free(&mut self, id: CacheTextureId) {
1278        self.debug_assert_coalesced(id);
1279
1280        // Drop any unapplied updates to the to-be-freed texture.
1281        self.updates.remove(&id);
1282
1283        // Drop any allocations for it as well. If we happen to be allocating and
1284        // freeing in the same batch, we can collapse them to a no-op.
1285        let idx = self.allocations.iter().position(|x| x.id == id);
1286        let removed_kind = idx.map(|i| self.allocations.remove(i).kind);
1287        match removed_kind {
1288            Some(TextureCacheAllocationKind::Alloc(..)) => { /* no-op! */ },
1289            Some(TextureCacheAllocationKind::Free) => panic!("Double free"),
1290            Some(TextureCacheAllocationKind::Reset(..)) |
1291            None => {
1292                self.allocations.push(TextureCacheAllocation {
1293                    id,
1294                    kind: TextureCacheAllocationKind::Free,
1295                });
1296            }
1297        };
1298    }
1299
1300    /// Push a copy operation from a texture to another.
1301    ///
1302    /// The source and destination rectangles must have the same size.
1303    /// The copies are applied before every other operations in the
1304    /// texture update list.
1305    pub fn push_copy(
1306        &mut self,
1307        src_id: CacheTextureId, src_rect: &DeviceIntRect,
1308        dst_id: CacheTextureId, dst_rect: &DeviceIntRect,
1309    ) {
1310        debug_assert_eq!(src_rect.size(), dst_rect.size());
1311        self.copies.entry((src_id, dst_id))
1312            .or_insert_with(Vec::new)
1313            .push(TextureCacheCopy {
1314                src_rect: *src_rect,
1315                dst_rect: *dst_rect,
1316            });
1317    }
1318
1319    fn debug_assert_coalesced(&self, id: CacheTextureId) {
1320        debug_assert!(
1321            self.allocations.iter().filter(|x| x.id == id).count() <= 1,
1322            "Allocations should have been coalesced",
1323        );
1324    }
1325}
1326
1327/// A list of updates built by the render backend that should be applied
1328/// by the renderer thread.
1329pub struct ResourceUpdateList {
1330    /// List of OS native surface create / destroy operations to apply.
1331    pub native_surface_updates: Vec<NativeSurfaceOperation>,
1332
1333    /// Atomic set of texture cache updates to apply.
1334    pub texture_updates: TextureUpdateList,
1335}
1336
1337impl ResourceUpdateList {
1338    /// Returns true if this update list has no effect.
1339    pub fn is_nop(&self) -> bool {
1340        self.texture_updates.is_nop() && self.native_surface_updates.is_empty()
1341    }
1342}
1343
1344/// Wraps a frame_builder::Frame, but conceptually could hold more information
1345pub struct RenderedDocument {
1346    pub frame: Frame,
1347    pub profile: TransactionProfile,
1348    pub render_reasons: RenderReasons,
1349    pub frame_stats: Option<FullFrameStats>
1350}
1351
1352pub enum DebugOutput {
1353    #[cfg(feature = "capture")]
1354    SaveCapture(CaptureConfig, Vec<ExternalCaptureImage>),
1355    #[cfg(feature = "replay")]
1356    LoadCapture(CaptureConfig, Vec<PlainExternalImage>),
1357}
1358
1359#[allow(dead_code)]
1360pub enum ResultMsg {
1361    DebugCommand(DebugCommand),
1362    DebugOutput(DebugOutput),
1363    RefreshShader(PathBuf),
1364    UpdateGpuCache(GpuCacheUpdateList),
1365    UpdateResources {
1366        resource_updates: ResourceUpdateList,
1367        memory_pressure: bool,
1368    },
1369    PublishPipelineInfo(PipelineInfo),
1370    PublishDocument(
1371        FramePublishId,
1372        DocumentId,
1373        RenderedDocument,
1374        ResourceUpdateList,
1375    ),
1376    RenderDocumentOffscreen(
1377        DocumentId,
1378        RenderedDocument,
1379        ResourceUpdateList,
1380    ),
1381    AppendNotificationRequests(Vec<NotificationRequest>),
1382    SetParameter(Parameter),
1383    ForceRedraw,
1384}
1385
1386/// Primitive metadata we pass around in a bunch of places
1387#[derive(Copy, Clone, Debug)]
1388pub struct LayoutPrimitiveInfo {
1389    /// NOTE: this is *ideally* redundant with the clip_rect
1390    /// but that's an ongoing project, so for now it exists and is used :(
1391    pub rect: LayoutRect,
1392    pub clip_rect: LayoutRect,
1393    pub flags: PrimitiveFlags,
1394}
1395
1396impl LayoutPrimitiveInfo {
1397    pub fn with_clip_rect(rect: LayoutRect, clip_rect: LayoutRect) -> Self {
1398        Self {
1399            rect,
1400            clip_rect,
1401            flags: PrimitiveFlags::default(),
1402        }
1403    }
1404}
1405
1406// In some cases (e.g. printing) a pipeline is referenced multiple times by
1407// a parent display list. This allows us to distinguish between them.
1408#[cfg_attr(feature = "capture", derive(Serialize))]
1409#[cfg_attr(feature = "replay", derive(Deserialize))]
1410#[derive(Copy, Clone, PartialEq, Debug, Eq, Hash)]
1411pub struct PipelineInstanceId(u32);
1412
1413impl PipelineInstanceId {
1414    pub fn new(id: u32) -> Self {
1415        PipelineInstanceId(id)
1416    }
1417}