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