1use 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 pub fn first() -> Self {
62 FrameId(0)
63 }
64
65 pub fn as_u64(&self) -> u64 {
67 self.0
68 }
69
70 pub fn advance(&mut self) {
72 self.0 += 1;
73 }
74
75 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#[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 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 pub fn frame_id(&self) -> FrameId {
136 self.id
137 }
138
139 pub fn time(&self) -> SystemTime {
141 self.time
142 }
143
144 pub fn document_id(&self) -> DocumentId {
146 self.document_id
147 }
148
149 pub fn is_valid(&self) -> bool {
150 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 pub fn first(document_id: DocumentId) -> Self {
158 FrameStamp {
159 id: FrameId::first(),
160 time: SystemTime::now(),
161 document_id,
162 }
163 }
164
165 pub fn advance(&mut self) {
167 self.id.advance();
168 self.time = SystemTime::now();
169 }
170
171 pub const INVALID: FrameStamp = FrameStamp {
173 id: FrameId(0),
174 time: UNIX_EPOCH,
175 document_id: DocumentId::INVALID,
176 };
177}
178
179#[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
208pub type PlaneSplitter = BspSplitter<PlaneSplitAnchor>;
210
211#[derive(Debug, Copy, Clone)]
213#[cfg_attr(feature = "capture", derive(Serialize))]
214pub struct PlaneSplitterIndex(pub usize);
215
216const OPACITY_EPSILON: f32 = 0.001;
218
219#[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, 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 match *self {
318 Filter::Identity => 0, 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, linear: node.linear,
407 inflate: 0, 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#[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 pub bgra8_sampling_swizzle: Swizzle,
458}
459
460#[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#[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 Invalid,
498 TextureCache(CacheTextureId, Swizzle),
500 External(TextureSourceExternal),
502 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 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 DebugClear,
556}
557
558#[derive(Debug)]
560pub struct TextureCacheAllocation {
561 pub id: CacheTextureId,
563 pub kind: TextureCacheAllocationKind,
565}
566
567#[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 pub is_shared_cache: bool,
577 pub has_depth: bool,
579 pub category: TextureCacheCategory
580}
581
582#[derive(Debug)]
584pub enum TextureCacheAllocationKind {
585 Alloc(TextureCacheAllocInfo),
587 Reset(TextureCacheAllocInfo),
589 Free,
591}
592
593#[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#[derive(Debug)]
605pub struct TextureCacheCopy {
606 pub src_rect: DeviceIntRect,
607 pub dst_rect: DeviceIntRect,
608}
609
610#[derive(Default)]
616pub struct TextureUpdateList {
617 pub clears_shared_cache: bool,
620 pub allocations: Vec<TextureCacheAllocation>,
622 pub updates: FastHashMap<CacheTextureId, Vec<TextureCacheUpdate>>,
624 pub copies: FastHashMap<(CacheTextureId, CacheTextureId), Vec<TextureCacheCopy>>,
627}
628
629impl TextureUpdateList {
630 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 pub fn is_nop(&self) -> bool {
642 self.allocations.is_empty() && self.updates.is_empty()
643 }
644
645 #[inline]
647 pub fn note_clear(&mut self) {
648 self.clears_shared_cache = true;
649 }
650
651 #[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 #[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 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 pub fn push_reset(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
694 self.debug_assert_coalesced(id);
695
696 self.updates.remove(&id);
698
699 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 pub fn push_free(&mut self, id: CacheTextureId) {
718 self.debug_assert_coalesced(id);
719
720 self.updates.remove(&id);
722
723 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(..)) => { },
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 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
767pub struct ResourceUpdateList {
770 pub native_surface_updates: Vec<NativeSurfaceOperation>,
772
773 pub texture_updates: TextureUpdateList,
775}
776
777impl ResourceUpdateList {
778 pub fn is_nop(&self) -> bool {
780 self.texture_updates.is_nop() && self.native_surface_updates.is_empty()
781 }
782}
783
784pub 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#[derive(Copy, Clone, Debug)]
827pub struct LayoutPrimitiveInfo {
828 pub rect: LayoutRect,
831 pub clip_rect: LayoutRect,
832 pub flags: PrimitiveFlags,
833 pub aligned_aa_edges: EdgeMask,
839 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