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 
5 use api::{BorderRadius, ClipMode, ColorF, ColorU, RasterSpace};
6 use api::{ImageRendering, RepeatMode, PrimitiveFlags};
7 use api::{PremultipliedColorF, PropertyBinding, Shadow};
8 use api::{PrimitiveKeyKind, FillRule, POLYGON_CLIP_VERTEX_MAX};
9 use api::units::*;
10 use euclid::{SideOffsets2D, Size2D};
11 use malloc_size_of::MallocSizeOf;
12 use crate::segment::EdgeAaSegmentMask;
13 use crate::border::BorderSegmentCacheKey;
14 use crate::clip::{ClipChainId, ClipSet};
15 use crate::debug_item::{DebugItem, DebugMessage};
16 use crate::debug_colors;
17 use crate::scene_building::{CreateShadow, IsVisible};
18 use crate::frame_builder::FrameBuildingState;
19 use crate::glyph_rasterizer::GlyphKey;
20 use crate::gpu_cache::{GpuCacheAddress, GpuCacheHandle, GpuDataRequest};
21 use crate::gpu_types::{BrushFlags};
22 use crate::intern;
23 use crate::picture::PicturePrimitive;
24 use crate::render_task_graph::RenderTaskId;
25 use crate::resource_cache::ImageProperties;
26 use crate::scene::SceneProperties;
27 use std::{hash, ops, u32, usize};
28 #[cfg(debug_assertions)]
29 use std::sync::atomic::{AtomicUsize, Ordering};
30 use crate::util::Recycler;
31 use crate::internal_types::LayoutPrimitiveInfo;
32 #[cfg(debug_assertions)]
33 use crate::internal_types::FrameId;
34 use crate::visibility::PrimitiveVisibility;
35 
36 pub mod backdrop;
37 pub mod borders;
38 pub mod gradient;
39 pub mod image;
40 pub mod line_dec;
41 pub mod picture;
42 pub mod text_run;
43 pub mod interned;
44 
45 mod storage;
46 
47 use backdrop::BackdropDataHandle;
48 use borders::{ImageBorderDataHandle, NormalBorderDataHandle};
49 use gradient::{LinearGradientPrimitive, LinearGradientDataHandle, RadialGradientDataHandle, ConicGradientDataHandle};
50 use image::{ImageDataHandle, ImageInstance, YuvImageDataHandle};
51 use line_dec::LineDecorationDataHandle;
52 use picture::PictureDataHandle;
53 use text_run::{TextRunDataHandle, TextRunPrimitive};
54 
55 pub const VECS_PER_SEGMENT: usize = 2;
56 
57 /// Counter for unique primitive IDs for debug tracing.
58 #[cfg(debug_assertions)]
59 static NEXT_PRIM_ID: AtomicUsize = AtomicUsize::new(0);
60 
61 #[cfg(debug_assertions)]
62 static PRIM_CHASE_ID: AtomicUsize = AtomicUsize::new(usize::MAX);
63 
64 #[cfg(debug_assertions)]
register_prim_chase_id(id: PrimitiveDebugId)65 pub fn register_prim_chase_id(id: PrimitiveDebugId) {
66     PRIM_CHASE_ID.store(id.0, Ordering::SeqCst);
67 }
68 
69 #[cfg(not(debug_assertions))]
register_prim_chase_id(_: PrimitiveDebugId)70 pub fn register_prim_chase_id(_: PrimitiveDebugId) {
71 }
72 
73 #[cfg_attr(feature = "capture", derive(Serialize))]
74 #[cfg_attr(feature = "replay", derive(Deserialize))]
75 #[derive(Debug, Copy, Clone, MallocSizeOf)]
76 pub struct PrimitiveOpacity {
77     pub is_opaque: bool,
78 }
79 
80 impl PrimitiveOpacity {
opaque() -> PrimitiveOpacity81     pub fn opaque() -> PrimitiveOpacity {
82         PrimitiveOpacity { is_opaque: true }
83     }
84 
translucent() -> PrimitiveOpacity85     pub fn translucent() -> PrimitiveOpacity {
86         PrimitiveOpacity { is_opaque: false }
87     }
88 
from_alpha(alpha: f32) -> PrimitiveOpacity89     pub fn from_alpha(alpha: f32) -> PrimitiveOpacity {
90         PrimitiveOpacity {
91             is_opaque: alpha >= 1.0,
92         }
93     }
94 }
95 
96 /// For external images, it's not possible to know the
97 /// UV coords of the image (or the image data itself)
98 /// until the render thread receives the frame and issues
99 /// callbacks to the client application. For external
100 /// images that are visible, a DeferredResolve is created
101 /// that is stored in the frame. This allows the render
102 /// thread to iterate this list and update any changed
103 /// texture data and update the UV rect. Any filtering
104 /// is handled externally for NativeTexture external
105 /// images.
106 #[cfg_attr(feature = "capture", derive(Serialize))]
107 #[cfg_attr(feature = "replay", derive(Deserialize))]
108 pub struct DeferredResolve {
109     pub address: GpuCacheAddress,
110     pub image_properties: ImageProperties,
111     pub rendering: ImageRendering,
112 }
113 
114 #[derive(Debug, Copy, Clone, PartialEq)]
115 #[cfg_attr(feature = "capture", derive(Serialize))]
116 pub struct ClipTaskIndex(pub u32);
117 
118 impl ClipTaskIndex {
119     pub const INVALID: ClipTaskIndex = ClipTaskIndex(0);
120 }
121 
122 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, MallocSizeOf, Ord, PartialOrd)]
123 #[cfg_attr(feature = "capture", derive(Serialize))]
124 #[cfg_attr(feature = "replay", derive(Deserialize))]
125 pub struct PictureIndex(pub usize);
126 
127 #[cfg_attr(feature = "capture", derive(Serialize))]
128 #[cfg_attr(feature = "replay", derive(Deserialize))]
129 #[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
130 pub struct RectangleKey {
131     pub x0: f32,
132     pub y0: f32,
133     pub x1: f32,
134     pub y1: f32,
135 }
136 
137 impl RectangleKey {
intersects(&self, other: &Self) -> bool138     pub fn intersects(&self, other: &Self) -> bool {
139         self.x0 < other.x1
140             && other.x0 < self.x1
141             && self.y0 < other.y1
142             && other.y0 < self.y1
143     }
144 }
145 
146 impl Eq for RectangleKey {}
147 
148 impl hash::Hash for RectangleKey {
hash<H: hash::Hasher>(&self, state: &mut H)149     fn hash<H: hash::Hasher>(&self, state: &mut H) {
150         self.x0.to_bits().hash(state);
151         self.y0.to_bits().hash(state);
152         self.x1.to_bits().hash(state);
153         self.y1.to_bits().hash(state);
154     }
155 }
156 
157 impl From<RectangleKey> for LayoutRect {
from(key: RectangleKey) -> LayoutRect158     fn from(key: RectangleKey) -> LayoutRect {
159         LayoutRect {
160             min: LayoutPoint::new(key.x0, key.y0),
161             max: LayoutPoint::new(key.x1, key.y1),
162         }
163     }
164 }
165 
166 impl From<RectangleKey> for WorldRect {
from(key: RectangleKey) -> WorldRect167     fn from(key: RectangleKey) -> WorldRect {
168         WorldRect {
169             min: WorldPoint::new(key.x0, key.y0),
170             max: WorldPoint::new(key.x1, key.y1),
171         }
172     }
173 }
174 
175 impl From<LayoutRect> for RectangleKey {
from(rect: LayoutRect) -> RectangleKey176     fn from(rect: LayoutRect) -> RectangleKey {
177         RectangleKey {
178             x0: rect.min.x,
179             y0: rect.min.y,
180             x1: rect.max.x,
181             y1: rect.max.y,
182         }
183     }
184 }
185 
186 impl From<PictureRect> for RectangleKey {
from(rect: PictureRect) -> RectangleKey187     fn from(rect: PictureRect) -> RectangleKey {
188         RectangleKey {
189             x0: rect.min.x,
190             y0: rect.min.y,
191             x1: rect.max.x,
192             y1: rect.max.y,
193         }
194     }
195 }
196 
197 impl From<WorldRect> for RectangleKey {
from(rect: WorldRect) -> RectangleKey198     fn from(rect: WorldRect) -> RectangleKey {
199         RectangleKey {
200             x0: rect.min.x,
201             y0: rect.min.y,
202             x1: rect.max.x,
203             y1: rect.max.y,
204         }
205     }
206 }
207 
208 /// To create a fixed-size representation of a polygon, we use a fixed
209 /// number of points. Our initialization method restricts us to values
210 /// <= 32. If our constant POLYGON_CLIP_VERTEX_MAX is > 32, the Rust
211 /// compiler will complain.
212 #[cfg_attr(feature = "capture", derive(Serialize))]
213 #[cfg_attr(feature = "replay", derive(Deserialize))]
214 #[derive(Copy, Debug, Clone, Hash, MallocSizeOf, PartialEq)]
215 pub struct PolygonKey {
216     pub point_count: u8,
217     pub points: [PointKey; POLYGON_CLIP_VERTEX_MAX],
218     pub fill_rule: FillRule,
219 }
220 
221 impl PolygonKey {
new( points_layout: &Vec<LayoutPoint>, fill_rule: FillRule, ) -> Self222     pub fn new(
223         points_layout: &Vec<LayoutPoint>,
224         fill_rule: FillRule,
225     ) -> Self {
226         // We have to fill fixed-size arrays with data from a Vec.
227         // We'll do this by initializing the arrays to known-good
228         // values then overwriting those values as long as our
229         // iterator provides values.
230         let mut points: [PointKey; POLYGON_CLIP_VERTEX_MAX] = [PointKey { x: 0.0, y: 0.0}; POLYGON_CLIP_VERTEX_MAX];
231 
232         let mut point_count: u8 = 0;
233         for (src, dest) in points_layout.iter().zip(points.iter_mut()) {
234             *dest = (*src as LayoutPoint).into();
235             point_count = point_count + 1;
236         }
237 
238         PolygonKey {
239             point_count,
240             points,
241             fill_rule,
242         }
243     }
244 }
245 
246 impl Eq for PolygonKey {}
247 
248 /// A hashable SideOffset2D that can be used in primitive keys.
249 #[cfg_attr(feature = "capture", derive(Serialize))]
250 #[cfg_attr(feature = "replay", derive(Deserialize))]
251 #[derive(Debug, Clone, MallocSizeOf, PartialEq)]
252 pub struct SideOffsetsKey {
253     pub top: f32,
254     pub right: f32,
255     pub bottom: f32,
256     pub left: f32,
257 }
258 
259 impl Eq for SideOffsetsKey {}
260 
261 impl hash::Hash for SideOffsetsKey {
hash<H: hash::Hasher>(&self, state: &mut H)262     fn hash<H: hash::Hasher>(&self, state: &mut H) {
263         self.top.to_bits().hash(state);
264         self.right.to_bits().hash(state);
265         self.bottom.to_bits().hash(state);
266         self.left.to_bits().hash(state);
267     }
268 }
269 
270 impl From<SideOffsetsKey> for LayoutSideOffsets {
from(key: SideOffsetsKey) -> LayoutSideOffsets271     fn from(key: SideOffsetsKey) -> LayoutSideOffsets {
272         LayoutSideOffsets::new(
273             key.top,
274             key.right,
275             key.bottom,
276             key.left,
277         )
278     }
279 }
280 
281 impl<U> From<SideOffsets2D<f32, U>> for SideOffsetsKey {
from(offsets: SideOffsets2D<f32, U>) -> SideOffsetsKey282     fn from(offsets: SideOffsets2D<f32, U>) -> SideOffsetsKey {
283         SideOffsetsKey {
284             top: offsets.top,
285             right: offsets.right,
286             bottom: offsets.bottom,
287             left: offsets.left,
288         }
289     }
290 }
291 
292 /// A hashable size for using as a key during primitive interning.
293 #[cfg_attr(feature = "capture", derive(Serialize))]
294 #[cfg_attr(feature = "replay", derive(Deserialize))]
295 #[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
296 pub struct SizeKey {
297     w: f32,
298     h: f32,
299 }
300 
301 impl Eq for SizeKey {}
302 
303 impl hash::Hash for SizeKey {
hash<H: hash::Hasher>(&self, state: &mut H)304     fn hash<H: hash::Hasher>(&self, state: &mut H) {
305         self.w.to_bits().hash(state);
306         self.h.to_bits().hash(state);
307     }
308 }
309 
310 impl From<SizeKey> for LayoutSize {
from(key: SizeKey) -> LayoutSize311     fn from(key: SizeKey) -> LayoutSize {
312         LayoutSize::new(key.w, key.h)
313     }
314 }
315 
316 impl<U> From<Size2D<f32, U>> for SizeKey {
from(size: Size2D<f32, U>) -> SizeKey317     fn from(size: Size2D<f32, U>) -> SizeKey {
318         SizeKey {
319             w: size.width,
320             h: size.height,
321         }
322     }
323 }
324 
325 /// A hashable vec for using as a key during primitive interning.
326 #[cfg_attr(feature = "capture", derive(Serialize))]
327 #[cfg_attr(feature = "replay", derive(Deserialize))]
328 #[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
329 pub struct VectorKey {
330     pub x: f32,
331     pub y: f32,
332 }
333 
334 impl Eq for VectorKey {}
335 
336 impl hash::Hash for VectorKey {
hash<H: hash::Hasher>(&self, state: &mut H)337     fn hash<H: hash::Hasher>(&self, state: &mut H) {
338         self.x.to_bits().hash(state);
339         self.y.to_bits().hash(state);
340     }
341 }
342 
343 impl From<VectorKey> for LayoutVector2D {
from(key: VectorKey) -> LayoutVector2D344     fn from(key: VectorKey) -> LayoutVector2D {
345         LayoutVector2D::new(key.x, key.y)
346     }
347 }
348 
349 impl From<VectorKey> for WorldVector2D {
from(key: VectorKey) -> WorldVector2D350     fn from(key: VectorKey) -> WorldVector2D {
351         WorldVector2D::new(key.x, key.y)
352     }
353 }
354 
355 impl From<LayoutVector2D> for VectorKey {
from(vec: LayoutVector2D) -> VectorKey356     fn from(vec: LayoutVector2D) -> VectorKey {
357         VectorKey {
358             x: vec.x,
359             y: vec.y,
360         }
361     }
362 }
363 
364 impl From<WorldVector2D> for VectorKey {
from(vec: WorldVector2D) -> VectorKey365     fn from(vec: WorldVector2D) -> VectorKey {
366         VectorKey {
367             x: vec.x,
368             y: vec.y,
369         }
370     }
371 }
372 
373 /// A hashable point for using as a key during primitive interning.
374 #[cfg_attr(feature = "capture", derive(Serialize))]
375 #[cfg_attr(feature = "replay", derive(Deserialize))]
376 #[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
377 pub struct PointKey {
378     pub x: f32,
379     pub y: f32,
380 }
381 
382 impl Eq for PointKey {}
383 
384 impl hash::Hash for PointKey {
hash<H: hash::Hasher>(&self, state: &mut H)385     fn hash<H: hash::Hasher>(&self, state: &mut H) {
386         self.x.to_bits().hash(state);
387         self.y.to_bits().hash(state);
388     }
389 }
390 
391 impl From<PointKey> for LayoutPoint {
from(key: PointKey) -> LayoutPoint392     fn from(key: PointKey) -> LayoutPoint {
393         LayoutPoint::new(key.x, key.y)
394     }
395 }
396 
397 impl From<LayoutPoint> for PointKey {
from(p: LayoutPoint) -> PointKey398     fn from(p: LayoutPoint) -> PointKey {
399         PointKey {
400             x: p.x,
401             y: p.y,
402         }
403     }
404 }
405 
406 impl From<PicturePoint> for PointKey {
from(p: PicturePoint) -> PointKey407     fn from(p: PicturePoint) -> PointKey {
408         PointKey {
409             x: p.x,
410             y: p.y,
411         }
412     }
413 }
414 
415 impl From<WorldPoint> for PointKey {
from(p: WorldPoint) -> PointKey416     fn from(p: WorldPoint) -> PointKey {
417         PointKey {
418             x: p.x,
419             y: p.y,
420         }
421     }
422 }
423 
424 /// A hashable float for using as a key during primitive interning.
425 #[cfg_attr(feature = "capture", derive(Serialize))]
426 #[cfg_attr(feature = "replay", derive(Deserialize))]
427 #[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
428 pub struct FloatKey(f32);
429 
430 impl Eq for FloatKey {}
431 
432 impl hash::Hash for FloatKey {
hash<H: hash::Hasher>(&self, state: &mut H)433     fn hash<H: hash::Hasher>(&self, state: &mut H) {
434         self.0.to_bits().hash(state);
435     }
436 }
437 
438 
439 #[cfg_attr(feature = "capture", derive(Serialize))]
440 #[cfg_attr(feature = "replay", derive(Deserialize))]
441 #[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
442 pub struct PrimKeyCommonData {
443     pub flags: PrimitiveFlags,
444     pub prim_rect: RectangleKey,
445 }
446 
447 impl From<&LayoutPrimitiveInfo> for PrimKeyCommonData {
from(info: &LayoutPrimitiveInfo) -> Self448     fn from(info: &LayoutPrimitiveInfo) -> Self {
449         PrimKeyCommonData {
450             flags: info.flags,
451             prim_rect: info.rect.into(),
452         }
453     }
454 }
455 
456 #[cfg_attr(feature = "capture", derive(Serialize))]
457 #[cfg_attr(feature = "replay", derive(Deserialize))]
458 #[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
459 pub struct PrimKey<T: MallocSizeOf> {
460     pub common: PrimKeyCommonData,
461     pub kind: T,
462 }
463 
464 #[cfg_attr(feature = "capture", derive(Serialize))]
465 #[cfg_attr(feature = "replay", derive(Deserialize))]
466 #[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
467 pub struct PrimitiveKey {
468     pub common: PrimKeyCommonData,
469     pub kind: PrimitiveKeyKind,
470 }
471 
472 impl PrimitiveKey {
new( info: &LayoutPrimitiveInfo, kind: PrimitiveKeyKind, ) -> Self473     pub fn new(
474         info: &LayoutPrimitiveInfo,
475         kind: PrimitiveKeyKind,
476     ) -> Self {
477         PrimitiveKey {
478             common: info.into(),
479             kind,
480         }
481     }
482 }
483 
484 impl intern::InternDebug for PrimitiveKey {}
485 
486 /// The shared information for a given primitive. This is interned and retained
487 /// both across frames and display lists, by comparing the matching PrimitiveKey.
488 #[cfg_attr(feature = "capture", derive(Serialize))]
489 #[cfg_attr(feature = "replay", derive(Deserialize))]
490 #[derive(MallocSizeOf)]
491 pub enum PrimitiveTemplateKind {
492     Rectangle {
493         color: PropertyBinding<ColorF>,
494     },
495     Clear,
496 }
497 
498 impl PrimitiveTemplateKind {
499     /// Write any GPU blocks for the primitive template to the given request object.
write_prim_gpu_blocks( &self, request: &mut GpuDataRequest, scene_properties: &SceneProperties, )500     pub fn write_prim_gpu_blocks(
501         &self,
502         request: &mut GpuDataRequest,
503         scene_properties: &SceneProperties,
504     ) {
505         match *self {
506             PrimitiveTemplateKind::Clear => {
507                 // Opaque black with operator dest out
508                 request.push(PremultipliedColorF::BLACK);
509             }
510             PrimitiveTemplateKind::Rectangle { ref color, .. } => {
511                 request.push(scene_properties.resolve_color(color).premultiplied())
512             }
513         }
514     }
515 }
516 
517 /// Construct the primitive template data from a primitive key. This
518 /// is invoked when a primitive key is created and the interner
519 /// doesn't currently contain a primitive with this key.
520 impl From<PrimitiveKeyKind> for PrimitiveTemplateKind {
from(kind: PrimitiveKeyKind) -> Self521     fn from(kind: PrimitiveKeyKind) -> Self {
522         match kind {
523             PrimitiveKeyKind::Clear => {
524                 PrimitiveTemplateKind::Clear
525             }
526             PrimitiveKeyKind::Rectangle { color, .. } => {
527                 PrimitiveTemplateKind::Rectangle {
528                     color: color.into(),
529                 }
530             }
531         }
532     }
533 }
534 
535 #[cfg_attr(feature = "capture", derive(Serialize))]
536 #[cfg_attr(feature = "replay", derive(Deserialize))]
537 #[derive(MallocSizeOf)]
538 #[derive(Debug)]
539 pub struct PrimTemplateCommonData {
540     pub flags: PrimitiveFlags,
541     pub may_need_repetition: bool,
542     pub prim_rect: LayoutRect,
543     pub opacity: PrimitiveOpacity,
544     /// The GPU cache handle for a primitive template. Since this structure
545     /// is retained across display lists by interning, this GPU cache handle
546     /// also remains valid, which reduces the number of updates to the GPU
547     /// cache when a new display list is processed.
548     pub gpu_cache_handle: GpuCacheHandle,
549 }
550 
551 impl PrimTemplateCommonData {
with_key_common(common: PrimKeyCommonData) -> Self552     pub fn with_key_common(common: PrimKeyCommonData) -> Self {
553         PrimTemplateCommonData {
554             flags: common.flags,
555             may_need_repetition: true,
556             prim_rect: common.prim_rect.into(),
557             gpu_cache_handle: GpuCacheHandle::new(),
558             opacity: PrimitiveOpacity::translucent(),
559         }
560     }
561 }
562 
563 #[cfg_attr(feature = "capture", derive(Serialize))]
564 #[cfg_attr(feature = "replay", derive(Deserialize))]
565 #[derive(MallocSizeOf)]
566 pub struct PrimTemplate<T> {
567     pub common: PrimTemplateCommonData,
568     pub kind: T,
569 }
570 
571 #[cfg_attr(feature = "capture", derive(Serialize))]
572 #[cfg_attr(feature = "replay", derive(Deserialize))]
573 #[derive(MallocSizeOf)]
574 pub struct PrimitiveTemplate {
575     pub common: PrimTemplateCommonData,
576     pub kind: PrimitiveTemplateKind,
577 }
578 
579 impl ops::Deref for PrimitiveTemplate {
580     type Target = PrimTemplateCommonData;
deref(&self) -> &Self::Target581     fn deref(&self) -> &Self::Target {
582         &self.common
583     }
584 }
585 
586 impl ops::DerefMut for PrimitiveTemplate {
deref_mut(&mut self) -> &mut Self::Target587     fn deref_mut(&mut self) -> &mut Self::Target {
588         &mut self.common
589     }
590 }
591 
592 impl From<PrimitiveKey> for PrimitiveTemplate {
from(item: PrimitiveKey) -> Self593     fn from(item: PrimitiveKey) -> Self {
594         PrimitiveTemplate {
595             common: PrimTemplateCommonData::with_key_common(item.common),
596             kind: item.kind.into(),
597         }
598     }
599 }
600 
601 impl PrimitiveTemplate {
602     /// Update the GPU cache for a given primitive template. This may be called multiple
603     /// times per frame, by each primitive reference that refers to this interned
604     /// template. The initial request call to the GPU cache ensures that work is only
605     /// done if the cache entry is invalid (due to first use or eviction).
update( &mut self, frame_state: &mut FrameBuildingState, scene_properties: &SceneProperties, )606     pub fn update(
607         &mut self,
608         frame_state: &mut FrameBuildingState,
609         scene_properties: &SceneProperties,
610     ) {
611         if let Some(mut request) = frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) {
612             self.kind.write_prim_gpu_blocks(&mut request, scene_properties);
613         }
614 
615         self.opacity = match self.kind {
616             PrimitiveTemplateKind::Clear => {
617                 PrimitiveOpacity::translucent()
618             }
619             PrimitiveTemplateKind::Rectangle { ref color, .. } => {
620                 PrimitiveOpacity::from_alpha(scene_properties.resolve_color(color).a)
621             }
622         };
623     }
624 }
625 
626 type PrimitiveDataHandle = intern::Handle<PrimitiveKeyKind>;
627 
628 impl intern::Internable for PrimitiveKeyKind {
629     type Key = PrimitiveKey;
630     type StoreData = PrimitiveTemplate;
631     type InternData = ();
632     const PROFILE_COUNTER: usize = crate::profiler::INTERNED_PRIMITIVES;
633 }
634 
635 impl InternablePrimitive for PrimitiveKeyKind {
into_key( self, info: &LayoutPrimitiveInfo, ) -> PrimitiveKey636     fn into_key(
637         self,
638         info: &LayoutPrimitiveInfo,
639     ) -> PrimitiveKey {
640         PrimitiveKey::new(info, self)
641     }
642 
make_instance_kind( key: PrimitiveKey, data_handle: PrimitiveDataHandle, prim_store: &mut PrimitiveStore, _reference_frame_relative_offset: LayoutVector2D, ) -> PrimitiveInstanceKind643     fn make_instance_kind(
644         key: PrimitiveKey,
645         data_handle: PrimitiveDataHandle,
646         prim_store: &mut PrimitiveStore,
647         _reference_frame_relative_offset: LayoutVector2D,
648     ) -> PrimitiveInstanceKind {
649         match key.kind {
650             PrimitiveKeyKind::Clear => {
651                 PrimitiveInstanceKind::Clear {
652                     data_handle
653                 }
654             }
655             PrimitiveKeyKind::Rectangle { color, .. } => {
656                 let color_binding_index = match color {
657                     PropertyBinding::Binding(..) => {
658                         prim_store.color_bindings.push(color)
659                     }
660                     PropertyBinding::Value(..) => ColorBindingIndex::INVALID,
661                 };
662                 PrimitiveInstanceKind::Rectangle {
663                     data_handle,
664                     segment_instance_index: SegmentInstanceIndex::INVALID,
665                     color_binding_index,
666                 }
667             }
668         }
669     }
670 }
671 
672 #[derive(Debug, MallocSizeOf)]
673 #[cfg_attr(feature = "capture", derive(Serialize))]
674 #[cfg_attr(feature = "replay", derive(Deserialize))]
675 pub struct VisibleMaskImageTile {
676     pub tile_offset: TileOffset,
677     pub tile_rect: LayoutRect,
678 }
679 
680 #[derive(Debug)]
681 #[cfg_attr(feature = "capture", derive(Serialize))]
682 pub struct VisibleGradientTile {
683     pub handle: GpuCacheHandle,
684     pub local_rect: LayoutRect,
685     pub local_clip_rect: LayoutRect,
686 }
687 
688 /// Information about how to cache a border segment,
689 /// along with the current render task cache entry.
690 #[cfg_attr(feature = "capture", derive(Serialize))]
691 #[cfg_attr(feature = "replay", derive(Deserialize))]
692 #[derive(Debug, MallocSizeOf)]
693 pub struct BorderSegmentInfo {
694     pub local_task_size: LayoutSize,
695     pub cache_key: BorderSegmentCacheKey,
696 }
697 
698 /// Represents the visibility state of a segment (wrt clip masks).
699 #[cfg_attr(feature = "capture", derive(Serialize))]
700 #[derive(Debug, Clone)]
701 pub enum ClipMaskKind {
702     /// The segment has a clip mask, specified by the render task.
703     Mask(RenderTaskId),
704     /// The segment has no clip mask.
705     None,
706     /// The segment is made invisible / clipped completely.
707     Clipped,
708 }
709 
710 #[cfg_attr(feature = "capture", derive(Serialize))]
711 #[cfg_attr(feature = "replay", derive(Deserialize))]
712 #[derive(Debug, Clone, MallocSizeOf)]
713 pub struct BrushSegment {
714     pub local_rect: LayoutRect,
715     pub may_need_clip_mask: bool,
716     pub edge_flags: EdgeAaSegmentMask,
717     pub extra_data: [f32; 4],
718     pub brush_flags: BrushFlags,
719 }
720 
721 impl BrushSegment {
new( local_rect: LayoutRect, may_need_clip_mask: bool, edge_flags: EdgeAaSegmentMask, extra_data: [f32; 4], brush_flags: BrushFlags, ) -> Self722     pub fn new(
723         local_rect: LayoutRect,
724         may_need_clip_mask: bool,
725         edge_flags: EdgeAaSegmentMask,
726         extra_data: [f32; 4],
727         brush_flags: BrushFlags,
728     ) -> Self {
729         Self {
730             local_rect,
731             may_need_clip_mask,
732             edge_flags,
733             extra_data,
734             brush_flags,
735         }
736     }
737 }
738 
739 #[derive(Debug, Clone)]
740 #[repr(C)]
741 #[cfg_attr(feature = "capture", derive(Serialize))]
742 #[cfg_attr(feature = "replay", derive(Deserialize))]
743 struct ClipRect {
744     rect: LayoutRect,
745     mode: f32,
746 }
747 
748 #[derive(Debug, Clone)]
749 #[repr(C)]
750 #[cfg_attr(feature = "capture", derive(Serialize))]
751 #[cfg_attr(feature = "replay", derive(Deserialize))]
752 struct ClipCorner {
753     rect: LayoutRect,
754     outer_radius_x: f32,
755     outer_radius_y: f32,
756     inner_radius_x: f32,
757     inner_radius_y: f32,
758 }
759 
760 impl ClipCorner {
uniform(rect: LayoutRect, outer_radius: f32, inner_radius: f32) -> ClipCorner761     fn uniform(rect: LayoutRect, outer_radius: f32, inner_radius: f32) -> ClipCorner {
762         ClipCorner {
763             rect,
764             outer_radius_x: outer_radius,
765             outer_radius_y: outer_radius,
766             inner_radius_x: inner_radius,
767             inner_radius_y: inner_radius,
768         }
769     }
770 }
771 
772 #[derive(Debug, Clone)]
773 #[repr(C)]
774 #[cfg_attr(feature = "capture", derive(Serialize))]
775 #[cfg_attr(feature = "replay", derive(Deserialize))]
776 pub struct ClipData {
777     rect: ClipRect,
778     top_left: ClipCorner,
779     top_right: ClipCorner,
780     bottom_left: ClipCorner,
781     bottom_right: ClipCorner,
782 }
783 
784 impl ClipData {
rounded_rect(size: LayoutSize, radii: &BorderRadius, mode: ClipMode) -> ClipData785     pub fn rounded_rect(size: LayoutSize, radii: &BorderRadius, mode: ClipMode) -> ClipData {
786         // TODO(gw): For simplicity, keep most of the clip GPU structs the
787         //           same as they were, even though the origin is now always
788         //           zero, since they are in the clip's local space. In future,
789         //           we could reduce the GPU cache size of ClipData.
790         let rect = LayoutRect::from_size(size);
791 
792         ClipData {
793             rect: ClipRect {
794                 rect,
795                 mode: mode as u32 as f32,
796             },
797             top_left: ClipCorner {
798                 rect: LayoutRect::from_origin_and_size(
799                     LayoutPoint::new(rect.min.x, rect.min.y),
800                     LayoutSize::new(radii.top_left.width, radii.top_left.height),
801                 ),
802                 outer_radius_x: radii.top_left.width,
803                 outer_radius_y: radii.top_left.height,
804                 inner_radius_x: 0.0,
805                 inner_radius_y: 0.0,
806             },
807             top_right: ClipCorner {
808                 rect: LayoutRect::from_origin_and_size(
809                     LayoutPoint::new(
810                         rect.max.x - radii.top_right.width,
811                         rect.min.y,
812                     ),
813                     LayoutSize::new(radii.top_right.width, radii.top_right.height),
814                 ),
815                 outer_radius_x: radii.top_right.width,
816                 outer_radius_y: radii.top_right.height,
817                 inner_radius_x: 0.0,
818                 inner_radius_y: 0.0,
819             },
820             bottom_left: ClipCorner {
821                 rect: LayoutRect::from_origin_and_size(
822                     LayoutPoint::new(
823                         rect.min.x,
824                         rect.max.y - radii.bottom_left.height,
825                     ),
826                     LayoutSize::new(radii.bottom_left.width, radii.bottom_left.height),
827                 ),
828                 outer_radius_x: radii.bottom_left.width,
829                 outer_radius_y: radii.bottom_left.height,
830                 inner_radius_x: 0.0,
831                 inner_radius_y: 0.0,
832             },
833             bottom_right: ClipCorner {
834                 rect: LayoutRect::from_origin_and_size(
835                     LayoutPoint::new(
836                         rect.max.x - radii.bottom_right.width,
837                         rect.max.y - radii.bottom_right.height,
838                     ),
839                     LayoutSize::new(radii.bottom_right.width, radii.bottom_right.height),
840                 ),
841                 outer_radius_x: radii.bottom_right.width,
842                 outer_radius_y: radii.bottom_right.height,
843                 inner_radius_x: 0.0,
844                 inner_radius_y: 0.0,
845             },
846         }
847     }
848 
uniform(size: LayoutSize, radius: f32, mode: ClipMode) -> ClipData849     pub fn uniform(size: LayoutSize, radius: f32, mode: ClipMode) -> ClipData {
850         // TODO(gw): For simplicity, keep most of the clip GPU structs the
851         //           same as they were, even though the origin is now always
852         //           zero, since they are in the clip's local space. In future,
853         //           we could reduce the GPU cache size of ClipData.
854         let rect = LayoutRect::from_size(size);
855 
856         ClipData {
857             rect: ClipRect {
858                 rect,
859                 mode: mode as u32 as f32,
860             },
861             top_left: ClipCorner::uniform(
862                 LayoutRect::from_origin_and_size(
863                     LayoutPoint::new(rect.min.x, rect.min.y),
864                     LayoutSize::new(radius, radius),
865                 ),
866                 radius,
867                 0.0,
868             ),
869             top_right: ClipCorner::uniform(
870                 LayoutRect::from_origin_and_size(
871                     LayoutPoint::new(rect.max.x - radius, rect.min.y),
872                     LayoutSize::new(radius, radius),
873                 ),
874                 radius,
875                 0.0,
876             ),
877             bottom_left: ClipCorner::uniform(
878                 LayoutRect::from_origin_and_size(
879                     LayoutPoint::new(rect.min.x, rect.max.y - radius),
880                     LayoutSize::new(radius, radius),
881                 ),
882                 radius,
883                 0.0,
884             ),
885             bottom_right: ClipCorner::uniform(
886                 LayoutRect::from_origin_and_size(
887                     LayoutPoint::new(
888                         rect.max.x - radius,
889                         rect.max.y - radius,
890                     ),
891                     LayoutSize::new(radius, radius),
892                 ),
893                 radius,
894                 0.0,
895             ),
896         }
897     }
898 }
899 
900 /// A hashable descriptor for nine-patches, used by image and
901 /// gradient borders.
902 #[derive(Debug, Clone, PartialEq, Eq, Hash, MallocSizeOf)]
903 #[cfg_attr(feature = "capture", derive(Serialize))]
904 #[cfg_attr(feature = "replay", derive(Deserialize))]
905 pub struct NinePatchDescriptor {
906     pub width: i32,
907     pub height: i32,
908     pub slice: DeviceIntSideOffsets,
909     pub fill: bool,
910     pub repeat_horizontal: RepeatMode,
911     pub repeat_vertical: RepeatMode,
912     pub outset: SideOffsetsKey,
913     pub widths: SideOffsetsKey,
914 }
915 
916 impl IsVisible for PrimitiveKeyKind {
917     // Return true if the primary primitive is visible.
918     // Used to trivially reject non-visible primitives.
919     // TODO(gw): Currently, primitives other than those
920     //           listed here are handled before the
921     //           add_primitive() call. In the future
922     //           we should move the logic for all other
923     //           primitive types to use this.
is_visible(&self) -> bool924     fn is_visible(&self) -> bool {
925         match *self {
926             PrimitiveKeyKind::Clear => {
927                 true
928             }
929             PrimitiveKeyKind::Rectangle { ref color, .. } => {
930                 match *color {
931                     PropertyBinding::Value(value) => value.a > 0,
932                     PropertyBinding::Binding(..) => true,
933                 }
934             }
935         }
936     }
937 }
938 
939 impl CreateShadow for PrimitiveKeyKind {
940     // Create a clone of this PrimitiveContainer, applying whatever
941     // changes are necessary to the primitive to support rendering
942     // it as part of the supplied shadow.
create_shadow( &self, shadow: &Shadow, _: bool, _: RasterSpace, ) -> PrimitiveKeyKind943     fn create_shadow(
944         &self,
945         shadow: &Shadow,
946         _: bool,
947         _: RasterSpace,
948     ) -> PrimitiveKeyKind {
949         match *self {
950             PrimitiveKeyKind::Rectangle { .. } => {
951                 PrimitiveKeyKind::Rectangle {
952                     color: PropertyBinding::Value(shadow.color.into()),
953                 }
954             }
955             PrimitiveKeyKind::Clear => {
956                 panic!("bug: this prim is not supported in shadow contexts");
957             }
958         }
959     }
960 }
961 
962 #[derive(Clone, Copy, Debug, PartialEq)]
963 #[cfg_attr(feature = "capture", derive(Serialize))]
964 #[cfg_attr(feature = "replay", derive(Deserialize))]
965 pub struct PrimitiveDebugId(pub usize);
966 
967 #[derive(Debug)]
968 #[cfg_attr(feature = "capture", derive(Serialize))]
969 pub enum PrimitiveInstanceKind {
970     /// Direct reference to a Picture
971     Picture {
972         /// Handle to the common interned data for this primitive.
973         data_handle: PictureDataHandle,
974         pic_index: PictureIndex,
975         segment_instance_index: SegmentInstanceIndex,
976     },
977     /// A run of glyphs, with associated font parameters.
978     TextRun {
979         /// Handle to the common interned data for this primitive.
980         data_handle: TextRunDataHandle,
981         /// Index to the per instance scratch data for this primitive.
982         run_index: TextRunIndex,
983     },
984     /// A line decoration. cache_handle refers to a cached render
985     /// task handle, if this line decoration is not a simple solid.
986     LineDecoration {
987         /// Handle to the common interned data for this primitive.
988         data_handle: LineDecorationDataHandle,
989         // TODO(gw): For now, we need to store some information in
990         //           the primitive instance that is created during
991         //           prepare_prims and read during the batching pass.
992         //           Once we unify the prepare_prims and batching to
993         //           occur at the same time, we can remove most of
994         //           the things we store here in the instance, and
995         //           use them directly. This will remove cache_handle,
996         //           but also the opacity, clip_task_id etc below.
997         render_task: Option<RenderTaskId>,
998     },
999     NormalBorder {
1000         /// Handle to the common interned data for this primitive.
1001         data_handle: NormalBorderDataHandle,
1002         render_task_ids: storage::Range<RenderTaskId>,
1003     },
1004     ImageBorder {
1005         /// Handle to the common interned data for this primitive.
1006         data_handle: ImageBorderDataHandle,
1007     },
1008     Rectangle {
1009         /// Handle to the common interned data for this primitive.
1010         data_handle: PrimitiveDataHandle,
1011         segment_instance_index: SegmentInstanceIndex,
1012         color_binding_index: ColorBindingIndex,
1013     },
1014     YuvImage {
1015         /// Handle to the common interned data for this primitive.
1016         data_handle: YuvImageDataHandle,
1017         segment_instance_index: SegmentInstanceIndex,
1018         is_compositor_surface: bool,
1019     },
1020     Image {
1021         /// Handle to the common interned data for this primitive.
1022         data_handle: ImageDataHandle,
1023         image_instance_index: ImageInstanceIndex,
1024         is_compositor_surface: bool,
1025     },
1026     /// Always rendered directly into the picture. This tends to be
1027     /// faster with SWGL.
1028     LinearGradient {
1029         /// Handle to the common interned data for this primitive.
1030         data_handle: LinearGradientDataHandle,
1031         visible_tiles_range: GradientTileRange,
1032     },
1033     /// Always rendered via a cached render task. Usually faster with
1034     /// a GPU.
1035     CachedLinearGradient {
1036         /// Handle to the common interned data for this primitive.
1037         data_handle: LinearGradientDataHandle,
1038         visible_tiles_range: GradientTileRange,
1039     },
1040     RadialGradient {
1041         /// Handle to the common interned data for this primitive.
1042         data_handle: RadialGradientDataHandle,
1043         visible_tiles_range: GradientTileRange,
1044     },
1045     ConicGradient {
1046         /// Handle to the common interned data for this primitive.
1047         data_handle: ConicGradientDataHandle,
1048         visible_tiles_range: GradientTileRange,
1049     },
1050     /// Clear out a rect, used for special effects.
1051     Clear {
1052         /// Handle to the common interned data for this primitive.
1053         data_handle: PrimitiveDataHandle,
1054     },
1055     /// Render a portion of a specified backdrop.
1056     Backdrop {
1057         data_handle: BackdropDataHandle,
1058     },
1059 }
1060 
1061 #[derive(Debug)]
1062 #[cfg_attr(feature = "capture", derive(Serialize))]
1063 pub struct PrimitiveInstance {
1064     /// Identifies the kind of primitive this
1065     /// instance is, and references to where
1066     /// the relevant information for the primitive
1067     /// can be found.
1068     pub kind: PrimitiveInstanceKind,
1069 
1070     #[cfg(debug_assertions)]
1071     pub id: PrimitiveDebugId,
1072 
1073     /// The last frame ID (of the `RenderTaskGraph`) this primitive
1074     /// was prepared for rendering in.
1075     #[cfg(debug_assertions)]
1076     pub prepared_frame_id: FrameId,
1077 
1078     /// All information and state related to clip(s) for this primitive
1079     pub clip_set: ClipSet,
1080 
1081     /// Information related to the current visibility state of this
1082     /// primitive.
1083     // TODO(gw): Currently built each frame, but can be retained.
1084     // TODO(gw): Remove clipped_world_rect (use tile bounds to determine vis flags)
1085     pub vis: PrimitiveVisibility,
1086     pub anti_aliased: bool,
1087 }
1088 
1089 impl PrimitiveInstance {
new( local_clip_rect: LayoutRect, kind: PrimitiveInstanceKind, clip_chain_id: ClipChainId, ) -> Self1090     pub fn new(
1091         local_clip_rect: LayoutRect,
1092         kind: PrimitiveInstanceKind,
1093         clip_chain_id: ClipChainId,
1094     ) -> Self {
1095         PrimitiveInstance {
1096             kind,
1097             #[cfg(debug_assertions)]
1098             prepared_frame_id: FrameId::INVALID,
1099             #[cfg(debug_assertions)]
1100             id: PrimitiveDebugId(NEXT_PRIM_ID.fetch_add(1, Ordering::Relaxed)),
1101             vis: PrimitiveVisibility::new(),
1102             clip_set: ClipSet {
1103                 local_clip_rect,
1104                 clip_chain_id,
1105             },
1106             anti_aliased: false,
1107         }
1108     }
1109 
1110     // Reset any pre-frame state for this primitive.
reset(&mut self)1111     pub fn reset(&mut self) {
1112         self.vis.reset();
1113 
1114         if self.is_chased() {
1115             #[cfg(debug_assertions)] // needed for ".id" part
1116             info!("\tpreparing {:?}", self.id);
1117             info!("\t{:?}", self.kind);
1118         }
1119     }
1120 
clear_visibility(&mut self)1121     pub fn clear_visibility(&mut self) {
1122         self.vis.reset();
1123     }
1124 
1125     #[cfg(debug_assertions)]
is_chased(&self) -> bool1126     pub fn is_chased(&self) -> bool {
1127         PRIM_CHASE_ID.load(Ordering::SeqCst) == self.id.0
1128     }
1129 
1130     #[cfg(not(debug_assertions))]
is_chased(&self) -> bool1131     pub fn is_chased(&self) -> bool {
1132         false
1133     }
1134 
uid(&self) -> intern::ItemUid1135     pub fn uid(&self) -> intern::ItemUid {
1136         match &self.kind {
1137             PrimitiveInstanceKind::Clear { data_handle, .. } |
1138             PrimitiveInstanceKind::Rectangle { data_handle, .. } => {
1139                 data_handle.uid()
1140             }
1141             PrimitiveInstanceKind::Image { data_handle, .. } => {
1142                 data_handle.uid()
1143             }
1144             PrimitiveInstanceKind::ImageBorder { data_handle, .. } => {
1145                 data_handle.uid()
1146             }
1147             PrimitiveInstanceKind::LineDecoration { data_handle, .. } => {
1148                 data_handle.uid()
1149             }
1150             PrimitiveInstanceKind::LinearGradient { data_handle, .. } => {
1151                 data_handle.uid()
1152             }
1153             PrimitiveInstanceKind::CachedLinearGradient { data_handle, .. } => {
1154                 data_handle.uid()
1155             }
1156             PrimitiveInstanceKind::NormalBorder { data_handle, .. } => {
1157                 data_handle.uid()
1158             }
1159             PrimitiveInstanceKind::Picture { data_handle, .. } => {
1160                 data_handle.uid()
1161             }
1162             PrimitiveInstanceKind::RadialGradient { data_handle, .. } => {
1163                 data_handle.uid()
1164             }
1165             PrimitiveInstanceKind::ConicGradient { data_handle, .. } => {
1166                 data_handle.uid()
1167             }
1168             PrimitiveInstanceKind::TextRun { data_handle, .. } => {
1169                 data_handle.uid()
1170             }
1171             PrimitiveInstanceKind::YuvImage { data_handle, .. } => {
1172                 data_handle.uid()
1173             }
1174             PrimitiveInstanceKind::Backdrop { data_handle, .. } => {
1175                 data_handle.uid()
1176             }
1177         }
1178     }
1179 }
1180 
1181 #[cfg_attr(feature = "capture", derive(Serialize))]
1182 #[derive(Debug)]
1183 pub struct SegmentedInstance {
1184     pub gpu_cache_handle: GpuCacheHandle,
1185     pub segments_range: SegmentsRange,
1186 }
1187 
1188 pub type GlyphKeyStorage = storage::Storage<GlyphKey>;
1189 pub type TextRunIndex = storage::Index<TextRunPrimitive>;
1190 pub type TextRunStorage = storage::Storage<TextRunPrimitive>;
1191 pub type ColorBindingIndex = storage::Index<PropertyBinding<ColorU>>;
1192 pub type ColorBindingStorage = storage::Storage<PropertyBinding<ColorU>>;
1193 pub type BorderHandleStorage = storage::Storage<RenderTaskId>;
1194 pub type SegmentStorage = storage::Storage<BrushSegment>;
1195 pub type SegmentsRange = storage::Range<BrushSegment>;
1196 pub type SegmentInstanceStorage = storage::Storage<SegmentedInstance>;
1197 pub type SegmentInstanceIndex = storage::Index<SegmentedInstance>;
1198 pub type ImageInstanceStorage = storage::Storage<ImageInstance>;
1199 pub type ImageInstanceIndex = storage::Index<ImageInstance>;
1200 pub type GradientTileStorage = storage::Storage<VisibleGradientTile>;
1201 pub type GradientTileRange = storage::Range<VisibleGradientTile>;
1202 pub type LinearGradientStorage = storage::Storage<LinearGradientPrimitive>;
1203 
1204 /// Contains various vecs of data that is used only during frame building,
1205 /// where we want to recycle the memory each new display list, to avoid constantly
1206 /// re-allocating and moving memory around. Written during primitive preparation,
1207 /// and read during batching.
1208 #[cfg_attr(feature = "capture", derive(Serialize))]
1209 pub struct PrimitiveScratchBuffer {
1210     /// Contains a list of clip mask instance parameters
1211     /// per segment generated.
1212     pub clip_mask_instances: Vec<ClipMaskKind>,
1213 
1214     /// List of glyphs keys that are allocated by each
1215     /// text run instance.
1216     pub glyph_keys: GlyphKeyStorage,
1217 
1218     /// List of render task handles for border segment instances
1219     /// that have been added this frame.
1220     pub border_cache_handles: BorderHandleStorage,
1221 
1222     /// A list of brush segments that have been built for this scene.
1223     pub segments: SegmentStorage,
1224 
1225     /// A list of segment ranges and GPU cache handles for prim instances
1226     /// that have opted into segment building. In future, this should be
1227     /// removed in favor of segment building during primitive interning.
1228     pub segment_instances: SegmentInstanceStorage,
1229 
1230     /// A list of visible tiles that tiled gradients use to store
1231     /// per-tile information.
1232     pub gradient_tiles: GradientTileStorage,
1233 
1234     /// List of debug display items for rendering.
1235     pub debug_items: Vec<DebugItem>,
1236 
1237     /// List of current debug messages to log on screen
1238     messages: Vec<DebugMessage>,
1239 }
1240 
1241 impl Default for PrimitiveScratchBuffer {
default() -> Self1242     fn default() -> Self {
1243         PrimitiveScratchBuffer {
1244             clip_mask_instances: Vec::new(),
1245             glyph_keys: GlyphKeyStorage::new(0),
1246             border_cache_handles: BorderHandleStorage::new(0),
1247             segments: SegmentStorage::new(0),
1248             segment_instances: SegmentInstanceStorage::new(0),
1249             gradient_tiles: GradientTileStorage::new(0),
1250             debug_items: Vec::new(),
1251             messages: Vec::new(),
1252         }
1253     }
1254 }
1255 
1256 impl PrimitiveScratchBuffer {
recycle(&mut self, recycler: &mut Recycler)1257     pub fn recycle(&mut self, recycler: &mut Recycler) {
1258         recycler.recycle_vec(&mut self.clip_mask_instances);
1259         self.glyph_keys.recycle(recycler);
1260         self.border_cache_handles.recycle(recycler);
1261         self.segments.recycle(recycler);
1262         self.segment_instances.recycle(recycler);
1263         self.gradient_tiles.recycle(recycler);
1264         recycler.recycle_vec(&mut self.debug_items);
1265     }
1266 
begin_frame(&mut self)1267     pub fn begin_frame(&mut self) {
1268         // Clear the clip mask tasks for the beginning of the frame. Append
1269         // a single kind representing no clip mask, at the ClipTaskIndex::INVALID
1270         // location.
1271         self.clip_mask_instances.clear();
1272         self.clip_mask_instances.push(ClipMaskKind::None);
1273 
1274         self.border_cache_handles.clear();
1275 
1276         // TODO(gw): As in the previous code, the gradient tiles store GPU cache
1277         //           handles that are cleared (and thus invalidated + re-uploaded)
1278         //           every frame. This maintains the existing behavior, but we
1279         //           should fix this in the future to retain handles.
1280         self.gradient_tiles.clear();
1281 
1282         self.debug_items.clear();
1283     }
1284 
end_frame(&mut self)1285     pub fn end_frame(&mut self) {
1286         const MSGS_TO_RETAIN: usize = 32;
1287         const TIME_TO_RETAIN: u64 = 2000000000;
1288         const LINE_HEIGHT: f32 = 20.0;
1289         const X0: f32 = 32.0;
1290         const Y0: f32 = 32.0;
1291         let now = time::precise_time_ns();
1292 
1293         let msgs_to_remove = self.messages.len().max(MSGS_TO_RETAIN) - MSGS_TO_RETAIN;
1294         let mut msgs_removed = 0;
1295 
1296         self.messages.retain(|msg| {
1297             if msgs_removed < msgs_to_remove {
1298                 msgs_removed += 1;
1299                 return false;
1300             }
1301 
1302             if msg.timestamp + TIME_TO_RETAIN < now {
1303                 return false;
1304             }
1305 
1306             true
1307         });
1308 
1309         let mut y = Y0 + self.messages.len() as f32 * LINE_HEIGHT;
1310         let shadow_offset = 1.0;
1311 
1312         for msg in &self.messages {
1313             self.debug_items.push(DebugItem::Text {
1314                 position: DevicePoint::new(X0 + shadow_offset, y + shadow_offset),
1315                 color: debug_colors::BLACK,
1316                 msg: msg.msg.clone(),
1317             });
1318 
1319             self.debug_items.push(DebugItem::Text {
1320                 position: DevicePoint::new(X0, y),
1321                 color: debug_colors::RED,
1322                 msg: msg.msg.clone(),
1323             });
1324 
1325             y -= LINE_HEIGHT;
1326         }
1327     }
1328 
1329     #[allow(dead_code)]
push_debug_rect( &mut self, rect: DeviceRect, outer_color: ColorF, inner_color: ColorF, )1330     pub fn push_debug_rect(
1331         &mut self,
1332         rect: DeviceRect,
1333         outer_color: ColorF,
1334         inner_color: ColorF,
1335     ) {
1336         self.debug_items.push(DebugItem::Rect {
1337             rect,
1338             outer_color,
1339             inner_color,
1340         });
1341     }
1342 
1343     #[allow(dead_code)]
push_debug_string( &mut self, position: DevicePoint, color: ColorF, msg: String, )1344     pub fn push_debug_string(
1345         &mut self,
1346         position: DevicePoint,
1347         color: ColorF,
1348         msg: String,
1349     ) {
1350         self.debug_items.push(DebugItem::Text {
1351             position,
1352             color,
1353             msg,
1354         });
1355     }
1356 
1357     #[allow(dead_code)]
log( &mut self, msg: String, )1358     pub fn log(
1359         &mut self,
1360         msg: String,
1361     ) {
1362         self.messages.push(DebugMessage {
1363             msg,
1364             timestamp: time::precise_time_ns(),
1365         })
1366     }
1367 }
1368 
1369 #[cfg_attr(feature = "capture", derive(Serialize))]
1370 #[cfg_attr(feature = "replay", derive(Deserialize))]
1371 #[derive(Clone, Debug)]
1372 pub struct PrimitiveStoreStats {
1373     picture_count: usize,
1374     text_run_count: usize,
1375     image_count: usize,
1376     linear_gradient_count: usize,
1377     color_binding_count: usize,
1378 }
1379 
1380 impl PrimitiveStoreStats {
empty() -> Self1381     pub fn empty() -> Self {
1382         PrimitiveStoreStats {
1383             picture_count: 0,
1384             text_run_count: 0,
1385             image_count: 0,
1386             linear_gradient_count: 0,
1387             color_binding_count: 0,
1388         }
1389     }
1390 }
1391 
1392 #[cfg_attr(feature = "capture", derive(Serialize))]
1393 pub struct PrimitiveStore {
1394     pub pictures: Vec<PicturePrimitive>,
1395     pub text_runs: TextRunStorage,
1396     pub linear_gradients: LinearGradientStorage,
1397 
1398     /// A list of image instances. These are stored separately as
1399     /// storing them inline in the instance makes the structure bigger
1400     /// for other types.
1401     pub images: ImageInstanceStorage,
1402 
1403     /// animated color bindings for this primitive.
1404     pub color_bindings: ColorBindingStorage,
1405 }
1406 
1407 impl PrimitiveStore {
new(stats: &PrimitiveStoreStats) -> PrimitiveStore1408     pub fn new(stats: &PrimitiveStoreStats) -> PrimitiveStore {
1409         PrimitiveStore {
1410             pictures: Vec::with_capacity(stats.picture_count),
1411             text_runs: TextRunStorage::new(stats.text_run_count),
1412             images: ImageInstanceStorage::new(stats.image_count),
1413             color_bindings: ColorBindingStorage::new(stats.color_binding_count),
1414             linear_gradients: LinearGradientStorage::new(stats.linear_gradient_count),
1415         }
1416     }
1417 
get_stats(&self) -> PrimitiveStoreStats1418     pub fn get_stats(&self) -> PrimitiveStoreStats {
1419         PrimitiveStoreStats {
1420             picture_count: self.pictures.len(),
1421             text_run_count: self.text_runs.len(),
1422             image_count: self.images.len(),
1423             linear_gradient_count: self.linear_gradients.len(),
1424             color_binding_count: self.color_bindings.len(),
1425         }
1426     }
1427 
1428     #[allow(unused)]
print_picture_tree(&self, root: PictureIndex)1429     pub fn print_picture_tree(&self, root: PictureIndex) {
1430         use crate::print_tree::PrintTree;
1431         let mut pt = PrintTree::new("picture tree");
1432         self.pictures[root.0].print(&self.pictures, root, &mut pt);
1433     }
1434 }
1435 
1436 /// Trait for primitives that are directly internable.
1437 /// see SceneBuilder::add_primitive<P>
1438 pub trait InternablePrimitive: intern::Internable<InternData = ()> + Sized {
1439     /// Build a new key from self with `info`.
into_key( self, info: &LayoutPrimitiveInfo, ) -> Self::Key1440     fn into_key(
1441         self,
1442         info: &LayoutPrimitiveInfo,
1443     ) -> Self::Key;
1444 
make_instance_kind( key: Self::Key, data_handle: intern::Handle<Self>, prim_store: &mut PrimitiveStore, reference_frame_relative_offset: LayoutVector2D, ) -> PrimitiveInstanceKind1445     fn make_instance_kind(
1446         key: Self::Key,
1447         data_handle: intern::Handle<Self>,
1448         prim_store: &mut PrimitiveStore,
1449         reference_frame_relative_offset: LayoutVector2D,
1450     ) -> PrimitiveInstanceKind;
1451 }
1452 
1453 
1454 #[test]
1455 #[cfg(target_pointer_width = "64")]
test_struct_sizes()1456 fn test_struct_sizes() {
1457     use std::mem;
1458     // The sizes of these structures are critical for performance on a number of
1459     // talos stress tests. If you get a failure here on CI, there's two possibilities:
1460     // (a) You made a structure smaller than it currently is. Great work! Update the
1461     //     test expectations and move on.
1462     // (b) You made a structure larger. This is not necessarily a problem, but should only
1463     //     be done with care, and after checking if talos performance regresses badly.
1464     assert_eq!(mem::size_of::<PrimitiveInstance>(), 160, "PrimitiveInstance size changed");
1465     assert_eq!(mem::size_of::<PrimitiveInstanceKind>(), 24, "PrimitiveInstanceKind size changed");
1466     assert_eq!(mem::size_of::<PrimitiveTemplate>(), 56, "PrimitiveTemplate size changed");
1467     assert_eq!(mem::size_of::<PrimitiveTemplateKind>(), 28, "PrimitiveTemplateKind size changed");
1468     assert_eq!(mem::size_of::<PrimitiveKey>(), 36, "PrimitiveKey size changed");
1469     assert_eq!(mem::size_of::<PrimitiveKeyKind>(), 16, "PrimitiveKeyKind size changed");
1470 }
1471