Skip to main content

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, FilterOp, ImageBufferKind};
7use api::{FramePublishId, TextureCacheCategory};
8use api::units::*;
9use crate::render_api::DebugCommand;
10use crate::composite::NativeSurfaceOperation;
11use crate::device::TextureFilter;
12use crate::renderer::{FullFrameStats, PipelineInfo};
13use crate::gpu_types::BlurEdgeMode;
14use crate::frame_builder::Frame;
15use crate::profiler::TransactionProfile;
16use crate::segment::EdgeMask;
17use crate::spatial_tree::SpatialNodeIndex;
18use crate::prim_store::PrimitiveInstanceIndex;
19use crate::svg_filter::{FilterGraphNode, FilterGraphOp, FilterGraphPictureReference};
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/// Equivalent to api::FilterOp with added internal information
220#[derive(Clone, Debug)]
221#[cfg_attr(feature = "capture", derive(Serialize))]
222#[cfg_attr(feature = "replay", derive(Deserialize))]
223pub enum Filter {
224    Identity,
225    Blur {
226        width: f32,
227        height: f32,
228        should_inflate: bool,
229        edge_mode: BlurEdgeMode,
230    },
231    Brightness(f32),
232    Contrast(f32),
233    Grayscale(f32),
234    HueRotate(f32),
235    Invert(f32),
236    Opacity(api::PropertyBinding<f32>, f32),
237    Saturate(f32),
238    Sepia(f32),
239    DropShadows(SmallVec<[Shadow; 1]>),
240    ColorMatrix(Box<[f32; 20]>),
241    SrgbToLinear,
242    LinearToSrgb,
243    ComponentTransfer,
244    Flood(ColorF),
245    SVGGraphNode(FilterGraphNode, FilterGraphOp),
246}
247
248impl Filter {
249    pub fn is_visible(&self) -> bool {
250        match *self {
251            Filter::Identity |
252            Filter::Blur { .. } |
253            Filter::Brightness(..) |
254            Filter::Contrast(..) |
255            Filter::Grayscale(..) |
256            Filter::HueRotate(..) |
257            Filter::Invert(..) |
258            Filter::Saturate(..) |
259            Filter::Sepia(..) |
260            Filter::DropShadows(..) |
261            Filter::ColorMatrix(..) |
262            Filter::SrgbToLinear |
263            Filter::LinearToSrgb |
264            Filter::ComponentTransfer  => true,
265            Filter::Opacity(_, amount) => {
266                amount > OPACITY_EPSILON
267            },
268            Filter::Flood(color) => {
269                color.a > OPACITY_EPSILON
270            }
271            Filter::SVGGraphNode(..) => true,
272        }
273    }
274
275    pub fn is_noop(&self) -> bool {
276        match *self {
277            Filter::Identity => false, // this is intentional
278            Filter::Blur { width, height, .. } => width == 0.0 && height == 0.0,
279            Filter::Brightness(amount) => amount == 1.0,
280            Filter::Contrast(amount) => amount == 1.0,
281            Filter::Grayscale(amount) => amount == 0.0,
282            Filter::HueRotate(amount) => amount == 0.0,
283            Filter::Invert(amount) => amount == 0.0,
284            Filter::Opacity(api::PropertyBinding::Value(amount), _) => amount >= 1.0,
285            Filter::Saturate(amount) => amount == 1.0,
286            Filter::Sepia(amount) => amount == 0.0,
287            Filter::DropShadows(ref shadows) => {
288                for shadow in shadows {
289                    if shadow.offset.x != 0.0 || shadow.offset.y != 0.0 || shadow.blur_radius != 0.0 {
290                        return false;
291                    }
292                }
293
294                true
295            }
296            Filter::ColorMatrix(ref matrix) => {
297                **matrix == [
298                    1.0, 0.0, 0.0, 0.0,
299                    0.0, 1.0, 0.0, 0.0,
300                    0.0, 0.0, 1.0, 0.0,
301                    0.0, 0.0, 0.0, 1.0,
302                    0.0, 0.0, 0.0, 0.0
303                ]
304            }
305            Filter::Opacity(api::PropertyBinding::Binding(..), _) |
306            Filter::SrgbToLinear |
307            Filter::LinearToSrgb |
308            Filter::ComponentTransfer |
309            Filter::Flood(..) => false,
310            Filter::SVGGraphNode(..) => false,
311        }
312    }
313
314
315    pub fn as_int(&self) -> i32 {
316        // Must be kept in sync with brush_blend.glsl
317        match *self {
318            Filter::Identity => 0, // matches `Contrast(1)`
319            Filter::Contrast(..) => 0,
320            Filter::Grayscale(..) => 1,
321            Filter::HueRotate(..) => 2,
322            Filter::Invert(..) => 3,
323            Filter::Saturate(..) => 4,
324            Filter::Sepia(..) => 5,
325            Filter::Brightness(..) => 6,
326            Filter::ColorMatrix(..) => 7,
327            Filter::SrgbToLinear => 8,
328            Filter::LinearToSrgb => 9,
329            Filter::Flood(..) => 10,
330            Filter::ComponentTransfer => 11,
331            Filter::Blur { .. } => 12,
332            Filter::DropShadows(..) => 13,
333            Filter::Opacity(..) => 14,
334            Filter::SVGGraphNode(..) => unreachable!("SVGGraphNode handled elsewhere"),
335        }
336    }
337}
338
339impl From<FilterOp> for Filter {
340    fn from(op: FilterOp) -> Self {
341        match op {
342            FilterOp::Identity => Filter::Identity,
343            FilterOp::Blur(width, height) => Filter::Blur {
344                width,
345                height,
346                should_inflate: true,
347                edge_mode: BlurEdgeMode::Duplicate,
348            },
349            FilterOp::Brightness(b) => Filter::Brightness(b),
350            FilterOp::Contrast(c) => Filter::Contrast(c),
351            FilterOp::Grayscale(g) => Filter::Grayscale(g),
352            FilterOp::HueRotate(h) => Filter::HueRotate(h),
353            FilterOp::Invert(i) => Filter::Invert(i),
354            FilterOp::Opacity(binding, opacity) => Filter::Opacity(binding, opacity),
355            FilterOp::Saturate(s) => Filter::Saturate(s),
356            FilterOp::Sepia(s) => Filter::Sepia(s),
357            FilterOp::ColorMatrix(mat) => Filter::ColorMatrix(Box::new(mat)),
358            FilterOp::SrgbToLinear => Filter::SrgbToLinear,
359            FilterOp::LinearToSrgb => Filter::LinearToSrgb,
360            FilterOp::ComponentTransfer => Filter::ComponentTransfer,
361            FilterOp::DropShadow(shadow) => Filter::DropShadows(smallvec![shadow]),
362            FilterOp::Flood(color) => Filter::Flood(color),
363            FilterOp::SVGFEBlendColor{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendColor),
364            FilterOp::SVGFEBlendColorBurn{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendColorBurn),
365            FilterOp::SVGFEBlendColorDodge{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendColorDodge),
366            FilterOp::SVGFEBlendDarken{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendDarken),
367            FilterOp::SVGFEBlendDifference{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendDifference),
368            FilterOp::SVGFEBlendExclusion{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendExclusion),
369            FilterOp::SVGFEBlendHardLight{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendHardLight),
370            FilterOp::SVGFEBlendHue{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendHue),
371            FilterOp::SVGFEBlendLighten{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendLighten),
372            FilterOp::SVGFEBlendLuminosity{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendLuminosity),
373            FilterOp::SVGFEBlendMultiply{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendMultiply),
374            FilterOp::SVGFEBlendNormal{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendNormal),
375            FilterOp::SVGFEBlendOverlay{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendOverlay),
376            FilterOp::SVGFEBlendSaturation{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendSaturation),
377            FilterOp::SVGFEBlendScreen{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendScreen),
378            FilterOp::SVGFEBlendSoftLight{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEBlendSoftLight),
379            FilterOp::SVGFEColorMatrix{node, values} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEColorMatrix{values}),
380            FilterOp::SVGFEComponentTransfer{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEComponentTransfer),
381            FilterOp::SVGFECompositeArithmetic{node, k1, k2, k3, k4} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeArithmetic{k1, k2, k3, k4}),
382            FilterOp::SVGFECompositeATop{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeATop),
383            FilterOp::SVGFECompositeIn{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeIn),
384            FilterOp::SVGFECompositeLighter{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeLighter),
385            FilterOp::SVGFECompositeOut{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeOut),
386            FilterOp::SVGFECompositeOver{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeOver),
387            FilterOp::SVGFECompositeXOR{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFECompositeXOR),
388            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}),
389            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}),
390            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}),
391            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}),
392            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}),
393            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}),
394            FilterOp::SVGFEDisplacementMap{node, scale, x_channel_selector, y_channel_selector} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEDisplacementMap{scale, x_channel_selector, y_channel_selector}),
395            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}),
396            FilterOp::SVGFEFlood{node, color} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEFlood{color}),
397            FilterOp::SVGFEGaussianBlur{node, std_deviation_x, std_deviation_y} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEGaussianBlur{std_deviation_x, std_deviation_y}),
398            FilterOp::SVGFEIdentity{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEIdentity),
399            FilterOp::SVGFEImage{node, sampling_filter, matrix} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEImage{sampling_filter, matrix}),
400            FilterOp::SVGFEMorphologyDilate{node, radius_x, radius_y} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEMorphologyDilate{radius_x, radius_y}),
401            FilterOp::SVGFEMorphologyErode{node, radius_x, radius_y} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEMorphologyErode{radius_x, radius_y}),
402            FilterOp::SVGFEOffset{node, offset_x, offset_y} => {
403                Filter::SVGGraphNode(
404                    FilterGraphNode {
405                        kept_by_optimizer: true, // computed later in scene_building
406                        linear: node.linear,
407                        inflate: 0, // computed later in scene_building
408                        inputs: [FilterGraphPictureReference {
409                            buffer_id: node.input.buffer_id,
410                            offset: LayoutVector2D::new(offset_x, offset_y),
411                            subregion: LayoutRect::zero(),
412                            inflate: 0,
413                            source_padding: LayoutRect::zero(),
414                            target_padding: LayoutRect::zero(),
415                        }].to_vec(),
416                        subregion: node.subregion,
417                    },
418                    FilterGraphOp::SVGFEIdentity,
419                )
420            },
421            FilterOp::SVGFEOpacity{node, valuebinding, value} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEOpacity{valuebinding, value}),
422            FilterOp::SVGFESourceAlpha{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFESourceAlpha),
423            FilterOp::SVGFESourceGraphic{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFESourceGraphic),
424            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}),
425            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}),
426            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}),
427            FilterOp::SVGFETile{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFETile),
428            FilterOp::SVGFEToAlpha{node} => Filter::SVGGraphNode(node.into(), FilterGraphOp::SVGFEToAlpha),
429            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}),
430            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}),
431            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}),
432            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}),
433        }
434    }
435}
436
437#[cfg_attr(feature = "capture", derive(Serialize))]
438#[cfg_attr(feature = "replay", derive(Deserialize))]
439#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
440pub enum Swizzle {
441    Rgba,
442    Bgra,
443}
444
445impl Default for Swizzle {
446    fn default() -> Self {
447        Swizzle::Rgba
448    }
449}
450
451/// Swizzle settings of the texture cache.
452#[cfg_attr(feature = "capture", derive(Serialize))]
453#[cfg_attr(feature = "replay", derive(Deserialize))]
454#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
455pub struct SwizzleSettings {
456    /// Swizzle required on sampling a texture with BGRA8 format.
457    pub bgra8_sampling_swizzle: Swizzle,
458}
459
460/// An ID for a texture that is owned by the `texture_cache` module.
461///
462/// This can include atlases or standalone textures allocated via the texture
463/// cache (e.g.  if an image is too large to be added to an atlas). The texture
464/// cache manages the allocation and freeing of these IDs, and the rendering
465/// thread maintains a map from cache texture ID to native texture.
466///
467/// We never reuse IDs, so we use a u64 here to be safe.
468#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
469#[cfg_attr(feature = "capture", derive(Serialize))]
470#[cfg_attr(feature = "replay", derive(Deserialize))]
471pub struct CacheTextureId(pub u32);
472
473impl CacheTextureId {
474    pub const INVALID: CacheTextureId = CacheTextureId(!0);
475}
476
477#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
478#[cfg_attr(feature = "capture", derive(Serialize))]
479#[cfg_attr(feature = "replay", derive(Deserialize))]
480pub struct DeferredResolveIndex(pub u32);
481
482#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
483#[cfg_attr(feature = "capture", derive(Serialize))]
484#[cfg_attr(feature = "replay", derive(Deserialize))]
485pub struct TextureSourceExternal {
486    pub index: DeferredResolveIndex,
487    pub kind: ImageBufferKind,
488    pub normalized_uvs: bool,
489}
490
491/// Identifies the source of an input texture to a shader.
492#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
493#[cfg_attr(feature = "capture", derive(Serialize))]
494#[cfg_attr(feature = "replay", derive(Deserialize))]
495pub enum TextureSource {
496    /// Equivalent to `None`, allowing us to avoid using `Option`s everywhere.
497    Invalid,
498    /// An entry in the texture cache.
499    TextureCache(CacheTextureId, Swizzle),
500    /// An external image texture, mananged by the embedding.
501    External(TextureSourceExternal),
502    /// Select a dummy 1x1 white texture. This can be used by image
503    /// shaders that want to draw a solid color.
504    Dummy,
505}
506
507impl TextureSource {
508    pub fn image_buffer_kind(&self) -> ImageBufferKind {
509        match *self {
510            TextureSource::TextureCache(..) => ImageBufferKind::Texture2D,
511
512            TextureSource::External(TextureSourceExternal { kind, .. }) => kind,
513
514            // Render tasks use texture arrays for now.
515            TextureSource::Dummy => ImageBufferKind::Texture2D,
516
517            TextureSource::Invalid => ImageBufferKind::Texture2D,
518        }
519    }
520
521    pub fn uses_normalized_uvs(&self) -> bool {
522        match *self {
523            TextureSource::External(TextureSourceExternal { normalized_uvs, .. }) => normalized_uvs,
524            _ => false,
525        }
526    }
527
528    #[inline]
529    pub fn is_compatible(
530        &self,
531        other: &TextureSource,
532    ) -> bool {
533        *self == TextureSource::Invalid ||
534        *other == TextureSource::Invalid ||
535        self == other
536    }
537}
538
539#[derive(Copy, Clone, Debug, PartialEq)]
540#[cfg_attr(feature = "capture", derive(Serialize))]
541#[cfg_attr(feature = "replay", derive(Deserialize))]
542pub struct RenderTargetInfo {
543    pub has_depth: bool,
544}
545
546#[derive(Debug)]
547pub enum TextureUpdateSource {
548    External {
549        id: ExternalImageId,
550        channel_index: u8,
551    },
552    Bytes { data: Arc<Vec<u8>> },
553    /// Clears the target area, rather than uploading any pixels. Used when the
554    /// texture cache debug display is active.
555    DebugClear,
556}
557
558/// Command to allocate, reallocate, or free a texture for the texture cache.
559#[derive(Debug)]
560pub struct TextureCacheAllocation {
561    /// The virtual ID (i.e. distinct from device ID) of the texture.
562    pub id: CacheTextureId,
563    /// Details corresponding to the operation in question.
564    pub kind: TextureCacheAllocationKind,
565}
566
567/// Information used when allocating / reallocating.
568#[derive(Copy, Clone, Debug, Eq, PartialEq)]
569pub struct TextureCacheAllocInfo {
570    pub width: i32,
571    pub height: i32,
572    pub format: ImageFormat,
573    pub filter: TextureFilter,
574    pub target: ImageBufferKind,
575    /// Indicates whether this corresponds to one of the shared texture caches.
576    pub is_shared_cache: bool,
577    /// If true, this texture requires a depth target.
578    pub has_depth: bool,
579    pub category: TextureCacheCategory
580}
581
582/// Sub-operation-specific information for allocation operations.
583#[derive(Debug)]
584pub enum TextureCacheAllocationKind {
585    /// Performs an initial texture allocation.
586    Alloc(TextureCacheAllocInfo),
587    /// Reallocates the texture without preserving its contents.
588    Reset(TextureCacheAllocInfo),
589    /// Frees the texture and the corresponding cache ID.
590    Free,
591}
592
593/// Command to update the contents of the texture cache.
594#[derive(Debug)]
595pub struct TextureCacheUpdate {
596    pub rect: DeviceIntRect,
597    pub stride: Option<i32>,
598    pub offset: i32,
599    pub format_override: Option<ImageFormat>,
600    pub source: TextureUpdateSource,
601}
602
603/// Command to update the contents of the texture cache.
604#[derive(Debug)]
605pub struct TextureCacheCopy {
606    pub src_rect: DeviceIntRect,
607    pub dst_rect: DeviceIntRect,
608}
609
610/// Atomic set of commands to manipulate the texture cache, generated on the
611/// RenderBackend thread and executed on the Renderer thread.
612///
613/// The list of allocation operations is processed before the updates. This is
614/// important to allow coalescing of certain allocation operations.
615#[derive(Default)]
616pub struct TextureUpdateList {
617    /// Indicates that there was some kind of cleanup clear operation. Used for
618    /// sanity checks.
619    pub clears_shared_cache: bool,
620    /// Commands to alloc/realloc/free the textures. Processed first.
621    pub allocations: Vec<TextureCacheAllocation>,
622    /// Commands to update the contents of the textures. Processed second.
623    pub updates: FastHashMap<CacheTextureId, Vec<TextureCacheUpdate>>,
624    /// Commands to move items within the cache, these are applied before everything
625    /// else in the update list.
626    pub copies: FastHashMap<(CacheTextureId, CacheTextureId), Vec<TextureCacheCopy>>,
627}
628
629impl TextureUpdateList {
630    /// Mints a new `TextureUpdateList`.
631    pub fn new() -> Self {
632        TextureUpdateList {
633            clears_shared_cache: false,
634            allocations: Vec::new(),
635            updates: FastHashMap::default(),
636            copies: FastHashMap::default(),
637        }
638    }
639
640    /// Returns true if this is a no-op (no updates to be applied).
641    pub fn is_nop(&self) -> bool {
642        self.allocations.is_empty() && self.updates.is_empty()
643    }
644
645    /// Sets the clears_shared_cache flag for renderer-side sanity checks.
646    #[inline]
647    pub fn note_clear(&mut self) {
648        self.clears_shared_cache = true;
649    }
650
651    /// Pushes an update operation onto the list.
652    #[inline]
653    pub fn push_update(&mut self, id: CacheTextureId, update: TextureCacheUpdate) {
654        self.updates
655            .entry(id)
656            .or_default()
657            .push(update);
658    }
659
660    /// Sends a command to the Renderer to clear the portion of the shared region
661    /// we just freed. Used when the texture cache debugger is enabled.
662    #[cold]
663    pub fn push_debug_clear(
664        &mut self,
665        id: CacheTextureId,
666        origin: DeviceIntPoint,
667        width: i32,
668        height: i32,
669    ) {
670        let size = DeviceIntSize::new(width, height);
671        let rect = DeviceIntRect::from_origin_and_size(origin, size);
672        self.push_update(id, TextureCacheUpdate {
673            rect,
674            stride: None,
675            offset: 0,
676            format_override: None,
677            source: TextureUpdateSource::DebugClear,
678        });
679    }
680
681
682    /// Pushes an allocation operation onto the list.
683    pub fn push_alloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
684        debug_assert!(!self.allocations.iter().any(|x| x.id == id));
685        self.allocations.push(TextureCacheAllocation {
686            id,
687            kind: TextureCacheAllocationKind::Alloc(info),
688        });
689    }
690
691    /// Pushes a reallocation operation onto the list, potentially coalescing
692    /// with previous operations.
693    pub fn push_reset(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
694        self.debug_assert_coalesced(id);
695
696        // Drop any unapplied updates to the to-be-freed texture.
697        self.updates.remove(&id);
698
699        // Coallesce this realloc into a previous alloc or realloc, if available.
700        if let Some(cur) = self.allocations.iter_mut().find(|x| x.id == id) {
701            match cur.kind {
702                TextureCacheAllocationKind::Alloc(ref mut i) => *i = info,
703                TextureCacheAllocationKind::Reset(ref mut i) => *i = info,
704                TextureCacheAllocationKind::Free => panic!("Resetting freed texture"),
705            }
706            return
707        }
708
709        self.allocations.push(TextureCacheAllocation {
710            id,
711            kind: TextureCacheAllocationKind::Reset(info),
712        });
713    }
714
715    /// Pushes a free operation onto the list, potentially coalescing with
716    /// previous operations.
717    pub fn push_free(&mut self, id: CacheTextureId) {
718        self.debug_assert_coalesced(id);
719
720        // Drop any unapplied updates to the to-be-freed texture.
721        self.updates.remove(&id);
722
723        // Drop any allocations for it as well. If we happen to be allocating and
724        // freeing in the same batch, we can collapse them to a no-op.
725        let idx = self.allocations.iter().position(|x| x.id == id);
726        let removed_kind = idx.map(|i| self.allocations.remove(i).kind);
727        match removed_kind {
728            Some(TextureCacheAllocationKind::Alloc(..)) => { /* no-op! */ },
729            Some(TextureCacheAllocationKind::Free) => panic!("Double free"),
730            Some(TextureCacheAllocationKind::Reset(..)) |
731            None => {
732                self.allocations.push(TextureCacheAllocation {
733                    id,
734                    kind: TextureCacheAllocationKind::Free,
735                });
736            }
737        };
738    }
739
740    /// Push a copy operation from a texture to another.
741    ///
742    /// The source and destination rectangles must have the same size.
743    /// The copies are applied before every other operations in the
744    /// texture update list.
745    pub fn push_copy(
746        &mut self,
747        src_id: CacheTextureId, src_rect: &DeviceIntRect,
748        dst_id: CacheTextureId, dst_rect: &DeviceIntRect,
749    ) {
750        debug_assert_eq!(src_rect.size(), dst_rect.size());
751        self.copies.entry((src_id, dst_id))
752            .or_insert_with(Vec::new)
753            .push(TextureCacheCopy {
754                src_rect: *src_rect,
755                dst_rect: *dst_rect,
756            });
757    }
758
759    fn debug_assert_coalesced(&self, id: CacheTextureId) {
760        debug_assert!(
761            self.allocations.iter().filter(|x| x.id == id).count() <= 1,
762            "Allocations should have been coalesced",
763        );
764    }
765}
766
767/// A list of updates built by the render backend that should be applied
768/// by the renderer thread.
769pub struct ResourceUpdateList {
770    /// List of OS native surface create / destroy operations to apply.
771    pub native_surface_updates: Vec<NativeSurfaceOperation>,
772
773    /// Atomic set of texture cache updates to apply.
774    pub texture_updates: TextureUpdateList,
775}
776
777impl ResourceUpdateList {
778    /// Returns true if this update list has no effect.
779    pub fn is_nop(&self) -> bool {
780        self.texture_updates.is_nop() && self.native_surface_updates.is_empty()
781    }
782}
783
784/// Wraps a frame_builder::Frame, but conceptually could hold more information
785pub struct RenderedDocument {
786    pub frame: Frame,
787    pub profile: TransactionProfile,
788    pub render_reasons: RenderReasons,
789    pub frame_stats: Option<FullFrameStats>
790}
791
792pub enum DebugOutput {
793    #[cfg(feature = "capture")]
794    SaveCapture(CaptureConfig, Vec<ExternalCaptureImage>),
795    #[cfg(feature = "replay")]
796    LoadCapture(CaptureConfig, Vec<PlainExternalImage>),
797}
798
799#[allow(dead_code)]
800pub enum ResultMsg {
801    DebugCommand(DebugCommand),
802    DebugOutput(DebugOutput),
803    RefreshShader(PathBuf),
804    UpdateResources {
805        resource_updates: ResourceUpdateList,
806        memory_pressure: bool,
807    },
808    PublishPipelineInfo(PipelineInfo),
809    PublishDocument(
810        FramePublishId,
811        DocumentId,
812        RenderedDocument,
813        ResourceUpdateList,
814    ),
815    RenderDocumentOffscreen(
816        DocumentId,
817        RenderedDocument,
818        ResourceUpdateList,
819    ),
820    AppendNotificationRequests(Vec<NotificationRequest>),
821    SetParameter(Parameter),
822    ForceRedraw,
823}
824
825/// Primitive metadata we pass around in a bunch of places
826#[derive(Copy, Clone, Debug)]
827pub struct LayoutPrimitiveInfo {
828    /// NOTE: this is *ideally* redundant with the clip_rect
829    /// but that's an ongoing project, so for now it exists and is used :(
830    pub rect: LayoutRect,
831    pub clip_rect: LayoutRect,
832    pub flags: PrimitiveFlags,
833    /// Which edges should get anti-aliasing if the primitive is axis-aligned.
834    ///
835    /// Typically none for CSS primitives and all for SVG primitives.
836    /// If a display item is split into multiple primitives, removing anti-aliasing
837    /// for the edges where the item is split ensures that there is no seam.
838    pub aligned_aa_edges: EdgeMask,
839    /// Which edges should get anti-aliasing if the primitive is not axis-aligned.
840    ///
841    /// Typically all edges, or at least a superset of aa_edges.
842    /// If a display item is split into multiple primitives, removing anti-aliasing
843    /// for the edges where the item is split ensures that there is no seam.
844    pub transformed_aa_edges: EdgeMask,
845}
846
847impl LayoutPrimitiveInfo {
848    pub fn with_clip_rect(rect: LayoutRect, clip_rect: LayoutRect) -> Self {
849        Self {
850            rect,
851            clip_rect,
852            flags: PrimitiveFlags::default(),
853            aligned_aa_edges: EdgeMask::empty(),
854            transformed_aa_edges: EdgeMask::all(),
855        }
856    }
857}
858