surface.rs (38261B)
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 //! Contains functionality to help building the render task graph from a series of off-screen 6 //! surfaces that are created during the prepare pass, and other surface related types and 7 //! helpers. 8 9 use api::units::*; 10 use crate::box_shadow::BLUR_SAMPLE_SCALE; 11 use crate::command_buffer::{CommandBufferBuilderKind, CommandBufferList, CommandBufferBuilder, CommandBufferIndex}; 12 use crate::internal_types::{FastHashMap, Filter}; 13 use crate::picture::PictureCompositeMode; 14 use crate::tile_cache::{TileKey, SubSliceIndex, MAX_COMPOSITOR_SURFACES}; 15 use crate::prim_store::PictureIndex; 16 use crate::render_task_graph::{RenderTaskId, RenderTaskGraphBuilder}; 17 use crate::render_target::ResolveOp; 18 use crate::render_task::{RenderTask, RenderTaskKind, RenderTaskLocation}; 19 use crate::space::SpaceMapper; 20 use crate::spatial_tree::{SpatialTree, SpatialNodeIndex}; 21 use crate::util::MaxRect; 22 use crate::visibility::{VisibilityState, PrimitiveVisibility, FrameVisibilityContext}; 23 pub use crate::picture_composite_mode::{get_surface_rects, calculate_uv_rect_kind}; 24 25 26 /// Maximum blur radius for blur filter 27 const MAX_BLUR_RADIUS: f32 = 100.; 28 29 /// An index into the surface array 30 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 31 #[cfg_attr(feature = "capture", derive(Serialize))] 32 #[cfg_attr(feature = "replay", derive(Deserialize))] 33 pub struct SurfaceIndex(pub usize); 34 35 /// Specify whether a surface allows subpixel AA text rendering. 36 #[derive(Debug, Copy, Clone)] 37 pub enum SubpixelMode { 38 /// This surface allows subpixel AA text 39 Allow, 40 /// Subpixel AA text cannot be drawn on this surface 41 Deny, 42 /// Subpixel AA can be drawn on this surface, if not intersecting 43 /// with the excluded regions, and inside the allowed rect. 44 Conditional { 45 allowed_rect: PictureRect, 46 prohibited_rect: PictureRect, 47 }, 48 } 49 50 /// Information about an offscreen surface. For now, 51 /// it contains information about the size and coordinate 52 /// system of the surface. In the future, it will contain 53 /// information about the contents of the surface, which 54 /// will allow surfaces to be cached / retained between 55 /// frames and display lists. 56 pub struct SurfaceInfo { 57 /// A local rect defining the size of this surface, in the 58 /// coordinate system of the parent surface. This contains 59 /// the unclipped bounding rect of child primitives. 60 pub unclipped_local_rect: PictureRect, 61 /// The local space coverage of child primitives after they are 62 /// are clipped to their owning clip-chain. 63 pub clipped_local_rect: PictureRect, 64 /// The (conservative) valid part of this surface rect. Used 65 /// to reduce the size of render target allocation. 66 pub clipping_rect: PictureRect, 67 /// The rectangle to use for culling and clipping. 68 pub culling_rect: VisRect, 69 /// Helper structs for mapping local rects in different 70 /// coordinate systems into the picture coordinates. 71 pub map_local_to_picture: SpaceMapper<LayoutPixel, PicturePixel>, 72 /// The positioning node for the surface itself, 73 pub surface_spatial_node_index: SpatialNodeIndex, 74 /// The rasterization root for this surface. 75 pub raster_spatial_node_index: SpatialNodeIndex, 76 /// The spatial node for culling and clipping (anything using VisPixel). 77 /// TODO: Replace with the raster spatial node. 78 pub visibility_spatial_node_index: SpatialNodeIndex, 79 /// The device pixel ratio specific to this surface. 80 pub device_pixel_scale: DevicePixelScale, 81 /// The scale factors of the surface to world transform. 82 pub world_scale_factors: (f32, f32), 83 /// Local scale factors surface to raster transform 84 pub local_scale: (f32, f32), 85 /// If true, we know this surface is completely opaque. 86 pub is_opaque: bool, 87 /// If true, allow snapping on this and child surfaces 88 pub allow_snapping: bool, 89 /// If true, the scissor rect must be set when drawing this surface 90 pub force_scissor_rect: bool, 91 } 92 93 impl SurfaceInfo { 94 pub fn new( 95 surface_spatial_node_index: SpatialNodeIndex, 96 raster_spatial_node_index: SpatialNodeIndex, 97 world_rect: WorldRect, 98 spatial_tree: &SpatialTree, 99 device_pixel_scale: DevicePixelScale, 100 world_scale_factors: (f32, f32), 101 local_scale: (f32, f32), 102 allow_snapping: bool, 103 force_scissor_rect: bool, 104 ) -> Self { 105 let map_surface_to_world = SpaceMapper::new_with_target( 106 spatial_tree.root_reference_frame_index(), 107 surface_spatial_node_index, 108 world_rect, 109 spatial_tree, 110 ); 111 112 let pic_bounds = map_surface_to_world 113 .unmap(&map_surface_to_world.bounds) 114 .unwrap_or_else(PictureRect::max_rect); 115 116 let map_local_to_picture = SpaceMapper::new( 117 surface_spatial_node_index, 118 pic_bounds, 119 ); 120 121 // TODO: replace the root with raster space. 122 let visibility_spatial_node_index = spatial_tree.root_reference_frame_index(); 123 124 SurfaceInfo { 125 unclipped_local_rect: PictureRect::zero(), 126 clipped_local_rect: PictureRect::zero(), 127 is_opaque: false, 128 clipping_rect: PictureRect::zero(), 129 map_local_to_picture, 130 raster_spatial_node_index, 131 surface_spatial_node_index, 132 visibility_spatial_node_index, 133 device_pixel_scale, 134 world_scale_factors, 135 local_scale, 136 allow_snapping, 137 force_scissor_rect, 138 // TODO: At the moment all culling is done in world space but 139 // but the plan is to move it to raster space. 140 culling_rect: world_rect.cast_unit(), 141 } 142 } 143 144 /// Clamps the blur radius depending on scale factors. 145 pub fn clamp_blur_radius( 146 &self, 147 x_blur_radius: f32, 148 y_blur_radius: f32, 149 ) -> (f32, f32) { 150 // Clamping must occur after scale factors are applied, but scale factors are not applied 151 // until later on. To clamp the blur radius, we first apply the scale factors and then clamp 152 // and finally revert the scale factors. 153 154 let sx_blur_radius = x_blur_radius * self.local_scale.0; 155 let sy_blur_radius = y_blur_radius * self.local_scale.1; 156 157 let largest_scaled_blur_radius = f32::max( 158 sx_blur_radius * self.world_scale_factors.0, 159 sy_blur_radius * self.world_scale_factors.1, 160 ); 161 162 if largest_scaled_blur_radius > MAX_BLUR_RADIUS { 163 let sf = MAX_BLUR_RADIUS / largest_scaled_blur_radius; 164 (x_blur_radius * sf, y_blur_radius * sf) 165 } else { 166 // Return the original blur radius to avoid any rounding errors 167 (x_blur_radius, y_blur_radius) 168 } 169 } 170 171 pub fn update_culling_rect( 172 &mut self, 173 parent_culling_rect: VisRect, 174 composite_mode: &PictureCompositeMode, 175 frame_context: &FrameVisibilityContext, 176 ) { 177 // Set the default culling rect to be the parent, in case we fail 178 // any mappings below due to weird perspective or invalid transforms. 179 self.culling_rect = parent_culling_rect; 180 181 if let PictureCompositeMode::Filter(Filter::Blur { width, height, should_inflate, .. }) = composite_mode { 182 if *should_inflate { 183 // Space mapping vis <-> picture space 184 let map_surface_to_vis = SpaceMapper::new_with_target( 185 // TODO: switch from root to raster space. 186 frame_context.root_spatial_node_index, 187 self.surface_spatial_node_index, 188 parent_culling_rect, 189 frame_context.spatial_tree, 190 ); 191 192 // Unmap the parent culling rect to surface space. Note that this may be 193 // quite conservative in the case of a complex transform, especially perspective. 194 if let Some(local_parent_culling_rect) = map_surface_to_vis.unmap(&parent_culling_rect) { 195 let (width_factor, height_factor) = self.clamp_blur_radius(*width, *height); 196 197 // Inflate by the local-space amount this surface extends. 198 let expanded_rect: PictureBox2D = local_parent_culling_rect.inflate( 199 width_factor.ceil() * BLUR_SAMPLE_SCALE, 200 height_factor.ceil() * BLUR_SAMPLE_SCALE, 201 ); 202 203 // Map back to the expected vis-space culling rect 204 if let Some(rect) = map_surface_to_vis.map(&expanded_rect) { 205 self.culling_rect = rect; 206 } 207 } 208 } 209 } 210 } 211 212 pub fn map_to_device_rect( 213 &self, 214 picture_rect: &PictureRect, 215 spatial_tree: &SpatialTree, 216 ) -> DeviceRect { 217 let raster_rect = if self.raster_spatial_node_index != self.surface_spatial_node_index { 218 // Currently, the surface's spatial node can be different from its raster node only 219 // for surfaces in the root coordinate system for snapping reasons. 220 // See `PicturePrimitive::assign_surface`. 221 assert_eq!(self.device_pixel_scale.0, 1.0); 222 assert_eq!(self.raster_spatial_node_index, spatial_tree.root_reference_frame_index()); 223 224 let pic_to_raster = SpaceMapper::new_with_target( 225 self.raster_spatial_node_index, 226 self.surface_spatial_node_index, 227 WorldRect::max_rect(), 228 spatial_tree, 229 ); 230 231 pic_to_raster.map(&picture_rect).unwrap() 232 } else { 233 picture_rect.cast_unit() 234 }; 235 236 raster_rect * self.device_pixel_scale 237 } 238 239 /// Clip and transform a local rect to a device rect suitable for allocating 240 /// a child off-screen surface of this surface (e.g. for clip-masks) 241 pub fn get_surface_rect( 242 &self, 243 local_rect: &PictureRect, 244 spatial_tree: &SpatialTree, 245 ) -> Option<DeviceIntRect> { 246 let local_rect = match local_rect.intersection(&self.clipping_rect) { 247 Some(rect) => rect, 248 None => return None, 249 }; 250 251 let raster_rect = if self.raster_spatial_node_index != self.surface_spatial_node_index { 252 assert_eq!(self.device_pixel_scale.0, 1.0); 253 254 let local_to_world = SpaceMapper::new_with_target( 255 spatial_tree.root_reference_frame_index(), 256 self.surface_spatial_node_index, 257 WorldRect::max_rect(), 258 spatial_tree, 259 ); 260 261 local_to_world.map(&local_rect).unwrap() 262 } else { 263 // The content should have been culled out earlier. 264 assert!(self.device_pixel_scale.0 > 0.0); 265 266 local_rect.cast_unit() 267 }; 268 269 let surface_rect = (raster_rect * self.device_pixel_scale).round_out().to_i32(); 270 if surface_rect.is_empty() { 271 // The local_rect computed above may have non-empty size that is very 272 // close to zero. Due to limited arithmetic precision, the SpaceMapper 273 // might transform the near-zero-sized rect into a zero-sized one. 274 return None; 275 } 276 277 Some(surface_rect) 278 } 279 } 280 281 // Information about the render task(s) for a given tile 282 #[cfg_attr(feature = "capture", derive(Serialize))] 283 #[cfg_attr(feature = "replay", derive(Deserialize))] 284 pub struct SurfaceTileDescriptor { 285 /// Target render task for commands added to this tile. This is changed 286 /// each time a sub-graph is encountered on this tile 287 pub current_task_id: RenderTaskId, 288 /// The compositing task for this tile, if required. This is only needed 289 /// when a tile contains one or more sub-graphs. 290 pub composite_task_id: Option<RenderTaskId>, 291 /// Dirty rect for this tile 292 pub dirty_rect: PictureRect, 293 } 294 295 // Details of how a surface is rendered 296 pub enum SurfaceDescriptorKind { 297 // Picture cache tiles 298 Tiled { 299 tiles: FastHashMap<TileKey, SurfaceTileDescriptor>, 300 }, 301 // A single surface (e.g. for an opacity filter) 302 Simple { 303 render_task_id: RenderTaskId, 304 dirty_rect: PictureRect, 305 }, 306 // A surface with 1+ intermediate tasks (e.g. blur) 307 Chained { 308 render_task_id: RenderTaskId, 309 root_task_id: RenderTaskId, 310 dirty_rect: PictureRect, 311 }, 312 } 313 314 // Describes how a surface is rendered 315 pub struct SurfaceDescriptor { 316 kind: SurfaceDescriptorKind, 317 } 318 319 impl SurfaceDescriptor { 320 // Create a picture cache tiled surface 321 pub fn new_tiled( 322 tiles: FastHashMap<TileKey, SurfaceTileDescriptor>, 323 ) -> Self { 324 SurfaceDescriptor { 325 kind: SurfaceDescriptorKind::Tiled { 326 tiles, 327 }, 328 } 329 } 330 331 // Create a chained surface (e.g. blur) 332 pub fn new_chained( 333 render_task_id: RenderTaskId, 334 root_task_id: RenderTaskId, 335 dirty_rect: PictureRect, 336 ) -> Self { 337 SurfaceDescriptor { 338 kind: SurfaceDescriptorKind::Chained { 339 render_task_id, 340 root_task_id, 341 dirty_rect, 342 }, 343 } 344 } 345 346 // Create a simple surface (e.g. opacity) 347 pub fn new_simple( 348 render_task_id: RenderTaskId, 349 dirty_rect: PictureRect, 350 ) -> Self { 351 SurfaceDescriptor { 352 kind: SurfaceDescriptorKind::Simple { 353 render_task_id, 354 dirty_rect, 355 }, 356 } 357 } 358 } 359 360 // Describes a list of command buffers that we are adding primitives to 361 // for a given surface. These are created from a command buffer builder 362 // as an optimization - skipping the indirection pic_task -> cmd_buffer_index 363 struct CommandBufferTargets { 364 available_cmd_buffers: Vec<Vec<(PictureRect, CommandBufferIndex)>>, 365 } 366 367 impl CommandBufferTargets { 368 fn new() -> Self { 369 CommandBufferTargets { 370 available_cmd_buffers: vec![Vec::new(); MAX_COMPOSITOR_SURFACES+1], 371 } 372 } 373 374 fn init( 375 &mut self, 376 cb: &CommandBufferBuilder, 377 rg_builder: &RenderTaskGraphBuilder, 378 ) { 379 for available_cmd_buffers in &mut self.available_cmd_buffers { 380 available_cmd_buffers.clear(); 381 } 382 383 match cb.kind { 384 CommandBufferBuilderKind::Tiled { ref tiles, .. } => { 385 for (key, desc) in tiles { 386 let task = rg_builder.get_task(desc.current_task_id); 387 match task.kind { 388 RenderTaskKind::Picture(ref info) => { 389 let available_cmd_buffers = &mut self.available_cmd_buffers[key.sub_slice_index.as_usize()]; 390 available_cmd_buffers.push((desc.dirty_rect, info.cmd_buffer_index)); 391 } 392 _ => unreachable!("bug: not a picture"), 393 } 394 } 395 } 396 CommandBufferBuilderKind::Simple { render_task_id, dirty_rect, .. } => { 397 let task = rg_builder.get_task(render_task_id); 398 match task.kind { 399 RenderTaskKind::Picture(ref info) => { 400 for sub_slice_buffer in &mut self.available_cmd_buffers { 401 sub_slice_buffer.push((dirty_rect, info.cmd_buffer_index)); 402 } 403 } 404 _ => unreachable!("bug: not a picture"), 405 } 406 } 407 CommandBufferBuilderKind::Invalid => {} 408 }; 409 } 410 411 /// For a given rect and sub-slice, get a list of command buffers to write commands to 412 fn get_cmd_buffer_targets_for_rect( 413 &mut self, 414 rect: &PictureRect, 415 sub_slice_index: SubSliceIndex, 416 targets: &mut Vec<CommandBufferIndex>, 417 ) -> bool { 418 419 for (dirty_rect, cmd_buffer_index) in &self.available_cmd_buffers[sub_slice_index.as_usize()] { 420 if dirty_rect.intersects(rect) { 421 targets.push(*cmd_buffer_index); 422 } 423 } 424 425 !targets.is_empty() 426 } 427 } 428 429 // Main helper interface to build a graph of surfaces. In future patches this 430 // will support building sub-graphs. 431 pub struct SurfaceBuilder { 432 // The currently set cmd buffer targets (updated during push/pop) 433 current_cmd_buffers: CommandBufferTargets, 434 // Stack of surfaces that are parents to the current targets 435 builder_stack: Vec<CommandBufferBuilder>, 436 // A map of the output render tasks from any sub-graphs that haven't 437 // been consumed by BackdropRender prims yet 438 pub sub_graph_output_map: FastHashMap<PictureIndex, RenderTaskId>, 439 } 440 441 impl SurfaceBuilder { 442 pub fn new() -> Self { 443 SurfaceBuilder { 444 current_cmd_buffers: CommandBufferTargets::new(), 445 builder_stack: Vec::new(), 446 sub_graph_output_map: FastHashMap::default(), 447 } 448 } 449 450 /// Register the current surface as the source of a resolve for the task sub-graph that 451 /// is currently on the surface builder stack. 452 pub fn register_resolve_source( 453 &mut self, 454 ) { 455 let surface_task_id = match self.builder_stack.last().unwrap().kind { 456 CommandBufferBuilderKind::Tiled { .. } | CommandBufferBuilderKind::Invalid => { 457 panic!("bug: only supported for non-tiled surfaces"); 458 } 459 CommandBufferBuilderKind::Simple { render_task_id, .. } => render_task_id, 460 }; 461 462 for builder in self.builder_stack.iter_mut().rev() { 463 if builder.establishes_sub_graph { 464 assert_eq!(builder.resolve_source, None); 465 builder.resolve_source = Some(surface_task_id); 466 return; 467 } 468 } 469 470 unreachable!("bug: resolve source with no sub-graph"); 471 } 472 473 pub fn push_surface( 474 &mut self, 475 surface_index: SurfaceIndex, 476 is_sub_graph: bool, 477 clipping_rect: PictureRect, 478 descriptor: Option<SurfaceDescriptor>, 479 surfaces: &mut [SurfaceInfo], 480 rg_builder: &RenderTaskGraphBuilder, 481 ) { 482 // Init the surface 483 surfaces[surface_index.0].clipping_rect = clipping_rect; 484 485 let builder = if let Some(descriptor) = descriptor { 486 match descriptor.kind { 487 SurfaceDescriptorKind::Tiled { tiles } => { 488 CommandBufferBuilder::new_tiled( 489 tiles, 490 ) 491 } 492 SurfaceDescriptorKind::Simple { render_task_id, dirty_rect, .. } => { 493 CommandBufferBuilder::new_simple( 494 render_task_id, 495 is_sub_graph, 496 None, 497 dirty_rect, 498 ) 499 } 500 SurfaceDescriptorKind::Chained { render_task_id, root_task_id, dirty_rect, .. } => { 501 CommandBufferBuilder::new_simple( 502 render_task_id, 503 is_sub_graph, 504 Some(root_task_id), 505 dirty_rect, 506 ) 507 } 508 } 509 } else { 510 CommandBufferBuilder::empty() 511 }; 512 513 self.current_cmd_buffers.init(&builder, rg_builder); 514 self.builder_stack.push(builder); 515 } 516 517 // Add a child render task (e.g. a render task cache item, or a clip mask) as a 518 // dependency of the current surface 519 pub fn add_child_render_task( 520 &mut self, 521 child_task_id: RenderTaskId, 522 rg_builder: &mut RenderTaskGraphBuilder, 523 ) { 524 let builder = self.builder_stack.last().unwrap(); 525 526 match builder.kind { 527 CommandBufferBuilderKind::Tiled { ref tiles } => { 528 for (_, descriptor) in tiles { 529 rg_builder.add_dependency( 530 descriptor.current_task_id, 531 child_task_id, 532 ); 533 } 534 } 535 CommandBufferBuilderKind::Simple { render_task_id, .. } => { 536 rg_builder.add_dependency( 537 render_task_id, 538 child_task_id, 539 ); 540 } 541 CommandBufferBuilderKind::Invalid { .. } => {} 542 } 543 } 544 545 // Add a picture render task as a dependency of the parent surface. This is a 546 // special case with extra complexity as the root of the surface may change 547 // when inside a sub-graph. It's currently only needed for drop-shadow effects. 548 pub fn add_picture_render_task( 549 &mut self, 550 child_task_id: RenderTaskId, 551 ) { 552 self.builder_stack 553 .last_mut() 554 .unwrap() 555 .extra_dependencies 556 .push(child_task_id); 557 } 558 559 // Get a list of command buffer indices that primitives should be pushed 560 // to for a given current visbility / dirty state 561 pub fn get_cmd_buffer_targets_for_prim( 562 &mut self, 563 vis: &PrimitiveVisibility, 564 targets: &mut Vec<CommandBufferIndex>, 565 ) -> bool { 566 targets.clear(); 567 568 match vis.state { 569 VisibilityState::Unset => { 570 panic!("bug: invalid vis state"); 571 } 572 VisibilityState::Culled => { 573 false 574 } 575 VisibilityState::Visible { sub_slice_index, .. } => { 576 self.current_cmd_buffers.get_cmd_buffer_targets_for_rect( 577 &vis.clip_chain.pic_coverage_rect, 578 sub_slice_index, 579 targets, 580 ) 581 } 582 VisibilityState::PassThrough => { 583 true 584 } 585 } 586 } 587 588 pub fn pop_empty_surface(&mut self) { 589 let builder = self.builder_stack.pop().unwrap(); 590 assert!(!builder.establishes_sub_graph); 591 } 592 593 // Finish adding primitives and child tasks to a surface and pop it off the stack 594 pub fn pop_surface( 595 &mut self, 596 pic_index: PictureIndex, 597 rg_builder: &mut RenderTaskGraphBuilder, 598 cmd_buffers: &mut CommandBufferList, 599 ) { 600 let builder = self.builder_stack.pop().unwrap(); 601 602 if builder.establishes_sub_graph { 603 // If we are popping a sub-graph off the stack the dependency setup is rather more complex... 604 match builder.kind { 605 CommandBufferBuilderKind::Tiled { .. } | CommandBufferBuilderKind::Invalid => { 606 unreachable!("bug: sub-graphs can only be simple surfaces"); 607 } 608 CommandBufferBuilderKind::Simple { render_task_id: child_render_task_id, root_task_id: child_root_task_id, .. } => { 609 // Get info about the resolve operation to copy from parent surface or tiles to the picture cache task 610 if let Some(resolve_task_id) = builder.resolve_source { 611 let mut src_task_ids = Vec::new(); 612 613 // Make the output of the sub-graph a dependency of the new replacement tile task 614 let _old = self.sub_graph_output_map.insert( 615 pic_index, 616 child_root_task_id.unwrap_or(child_render_task_id), 617 ); 618 debug_assert!(_old.is_none()); 619 620 // Set up dependencies for the sub-graph. The basic concepts below are the same, but for 621 // tiled surfaces are a little more complex as there are multiple tasks to set up. 622 // (a) Set up new task(s) on parent surface that write to the same location 623 // (b) Set up a resolve target to copy from parent surface tasks(s) to the resolve target 624 // (c) Make the old parent surface tasks input dependencies of the resolve target 625 // (d) Make the sub-graph output an input dependency of the new task(s). 626 627 match self.builder_stack.last_mut().unwrap().kind { 628 CommandBufferBuilderKind::Tiled { ref mut tiles } => { 629 let keys: Vec<TileKey> = tiles.keys().cloned().collect(); 630 631 // For each tile in parent surface 632 for key in keys { 633 let descriptor = tiles.remove(&key).unwrap(); 634 let parent_task_id = descriptor.current_task_id; 635 let parent_task = rg_builder.get_task_mut(parent_task_id); 636 637 match parent_task.location { 638 RenderTaskLocation::Unallocated { .. } | RenderTaskLocation::Existing { .. } => { 639 // Get info about the parent tile task location and params 640 let location = RenderTaskLocation::Existing { 641 parent_task_id, 642 size: parent_task.location.size(), 643 }; 644 645 let pic_task = match parent_task.kind { 646 RenderTaskKind::Picture(ref mut pic_task) => { 647 let cmd_buffer_index = cmd_buffers.create_cmd_buffer(); 648 let new_pic_task = pic_task.duplicate(cmd_buffer_index); 649 650 // Add the resolve src to copy from tile -> picture input task 651 src_task_ids.push(parent_task_id); 652 653 new_pic_task 654 } 655 _ => panic!("bug: not a picture"), 656 }; 657 658 // Make the existing tile an input dependency of the resolve target 659 rg_builder.add_dependency( 660 resolve_task_id, 661 parent_task_id, 662 ); 663 664 // Create the new task to replace the tile task 665 let new_task_id = rg_builder.add().init( 666 RenderTask::new( 667 location, // draw to same place 668 RenderTaskKind::Picture(pic_task), 669 ), 670 ); 671 672 // Ensure that the parent task will get scheduled earlier during 673 // pass assignment since we are reusing the existing surface, 674 // even though it's not technically needed for rendering order. 675 rg_builder.add_dependency( 676 new_task_id, 677 parent_task_id, 678 ); 679 680 // Update the surface builder with the now current target for future primitives 681 tiles.insert( 682 key, 683 SurfaceTileDescriptor { 684 current_task_id: new_task_id, 685 ..descriptor 686 }, 687 ); 688 } 689 RenderTaskLocation::Static { .. } => { 690 // Update the surface builder with the now current target for future primitives 691 tiles.insert( 692 key, 693 descriptor, 694 ); 695 } 696 _ => { 697 panic!("bug: unexpected task location"); 698 } 699 } 700 } 701 } 702 CommandBufferBuilderKind::Simple { render_task_id: ref mut parent_task_id, .. } => { 703 let parent_task = rg_builder.get_task_mut(*parent_task_id); 704 705 // Get info about the parent tile task location and params 706 let location = RenderTaskLocation::Existing { 707 parent_task_id: *parent_task_id, 708 size: parent_task.location.size(), 709 }; 710 let pic_task = match parent_task.kind { 711 RenderTaskKind::Picture(ref mut pic_task) => { 712 let cmd_buffer_index = cmd_buffers.create_cmd_buffer(); 713 714 let new_pic_task = pic_task.duplicate(cmd_buffer_index); 715 716 // Add the resolve src to copy from tile -> picture input task 717 src_task_ids.push(*parent_task_id); 718 719 new_pic_task 720 } 721 _ => panic!("bug: not a picture"), 722 }; 723 724 // Make the existing surface an input dependency of the resolve target 725 rg_builder.add_dependency( 726 resolve_task_id, 727 *parent_task_id, 728 ); 729 730 // Create the new task to replace the parent surface task 731 let new_task_id = rg_builder.add().init( 732 RenderTask::new( 733 location, // draw to same place 734 RenderTaskKind::Picture(pic_task), 735 ), 736 ); 737 738 // Ensure that the parent task will get scheduled earlier during 739 // pass assignment since we are reusing the existing surface, 740 // even though it's not technically needed for rendering order. 741 rg_builder.add_dependency( 742 new_task_id, 743 *parent_task_id, 744 ); 745 746 // Update the surface builder with the now current target for future primitives 747 *parent_task_id = new_task_id; 748 } 749 CommandBufferBuilderKind::Invalid => { 750 unreachable!(); 751 } 752 } 753 754 let dest_task = rg_builder.get_task_mut(resolve_task_id); 755 756 match dest_task.kind { 757 RenderTaskKind::Picture(ref mut dest_task_info) => { 758 assert!(dest_task_info.resolve_op.is_none()); 759 dest_task_info.resolve_op = Some(ResolveOp { 760 src_task_ids, 761 dest_task_id: resolve_task_id, 762 }) 763 } 764 _ => { 765 unreachable!("bug: not a picture"); 766 } 767 } 768 } 769 770 // This can occur if there is an edge case where the resolve target is found 771 // not visible even though the filter chain was (for example, in the case of 772 // an extreme scale causing floating point inaccuracies). Adding a dependency 773 // here is also a safety in case for some reason the backdrop render primitive 774 // doesn't pick up the dependency, ensuring that it gets scheduled and freed 775 // as early as possible. 776 match self.builder_stack.last().unwrap().kind { 777 CommandBufferBuilderKind::Tiled { ref tiles } => { 778 // For a tiled render task, add as a dependency to every tile. 779 for (_, descriptor) in tiles { 780 rg_builder.add_dependency( 781 descriptor.current_task_id, 782 child_root_task_id.unwrap_or(child_render_task_id), 783 ); 784 } 785 } 786 CommandBufferBuilderKind::Simple { render_task_id: parent_task_id, .. } => { 787 rg_builder.add_dependency( 788 parent_task_id, 789 child_root_task_id.unwrap_or(child_render_task_id), 790 ); 791 } 792 CommandBufferBuilderKind::Invalid => { 793 unreachable!(); 794 } 795 } 796 } 797 } 798 } else { 799 match builder.kind { 800 CommandBufferBuilderKind::Tiled { ref tiles } => { 801 for (_, descriptor) in tiles { 802 if let Some(composite_task_id) = descriptor.composite_task_id { 803 rg_builder.add_dependency( 804 composite_task_id, 805 descriptor.current_task_id, 806 ); 807 808 let composite_task = rg_builder.get_task_mut(composite_task_id); 809 match composite_task.kind { 810 RenderTaskKind::TileComposite(ref mut info) => { 811 info.task_id = Some(descriptor.current_task_id); 812 } 813 _ => unreachable!("bug: not a tile composite"), 814 } 815 } 816 } 817 } 818 CommandBufferBuilderKind::Simple { render_task_id: child_task_id, root_task_id: child_root_task_id, .. } => { 819 match self.builder_stack.last().unwrap().kind { 820 CommandBufferBuilderKind::Tiled { ref tiles } => { 821 // For a tiled render task, add as a dependency to every tile. 822 for (_, descriptor) in tiles { 823 rg_builder.add_dependency( 824 descriptor.current_task_id, 825 child_root_task_id.unwrap_or(child_task_id), 826 ); 827 } 828 } 829 CommandBufferBuilderKind::Simple { render_task_id: parent_task_id, .. } => { 830 rg_builder.add_dependency( 831 parent_task_id, 832 child_root_task_id.unwrap_or(child_task_id), 833 ); 834 } 835 CommandBufferBuilderKind::Invalid => { 836 } 837 } 838 } 839 CommandBufferBuilderKind::Invalid => { 840 } 841 } 842 } 843 844 // Step through the dependencies for this builder and add them to the finalized 845 // render task root(s) for this surface 846 match builder.kind { 847 CommandBufferBuilderKind::Tiled { ref tiles } => { 848 for (_, descriptor) in tiles { 849 for task_id in &builder.extra_dependencies { 850 rg_builder.add_dependency( 851 descriptor.current_task_id, 852 *task_id, 853 ); 854 } 855 } 856 } 857 CommandBufferBuilderKind::Simple { render_task_id, .. } => { 858 for task_id in &builder.extra_dependencies { 859 rg_builder.add_dependency( 860 render_task_id, 861 *task_id, 862 ); 863 } 864 } 865 CommandBufferBuilderKind::Invalid { .. } => {} 866 } 867 868 // Set up the cmd-buffer targets to write prims into the popped surface 869 self.current_cmd_buffers.init( 870 self.builder_stack.last().unwrap_or(&CommandBufferBuilder::empty()), rg_builder 871 ); 872 } 873 874 pub fn finalize(self) { 875 assert!(self.builder_stack.is_empty()); 876 } 877 } 878 879 880 pub fn calculate_screen_uv( 881 p: DevicePoint, 882 clipped: DeviceRect, 883 ) -> DeviceHomogeneousVector { 884 // TODO(gw): Switch to a simple mix, no bilerp / homogeneous vec needed anymore 885 DeviceHomogeneousVector::new( 886 (p.x - clipped.min.x) / (clipped.max.x - clipped.min.x), 887 (p.y - clipped.min.y) / (clipped.max.y - clipped.min.y), 888 0.0, 889 1.0, 890 ) 891 }