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