1use api::{ColorF, ColorU, PremultipliedColorF, PropertyBinding, PropertyBindingId, SnapshotInfo};
6use api::units::*;
7use crate::prim_store::image::AdjustedImageSource;
8use crate::{render_task_graph::RenderTaskGraphBuilder, renderer::GpuBufferBuilderF};
9use crate::box_shadow::BLUR_SAMPLE_SCALE;
10use crate::frame_builder::{FrameBuildingContext, FrameBuildingState};
11use crate::gpu_types::{BlurEdgeMode, BrushSegmentGpuData, ImageBrushPrimitiveData, UvRectKind};
12use crate::intern::ItemUid;
13use crate::render_backend::DataStores;
14use crate::render_task_graph::RenderTaskId;
15use crate::render_target::RenderTargetKind;
16use crate::render_task::{BlurTask, RenderTask, BlurTaskCache};
17use crate::render_task::RenderTaskKind;
18use crate::renderer::{BlendMode, GpuBufferAddress, GpuBufferBuilder};
19use crate::space::SpaceMapper;
20use crate::spatial_tree::SpatialTree;
21use crate::surface::{SurfaceDescriptor, SurfaceInfo, calculate_screen_uv};
22use crate::surface::SurfaceIndex;
23use crate::svg_filter::{get_coverage_source_svgfe, FilterGraphNodeKey, FilterGraphOpKey};
24use crate::util::MaxRect;
25use smallvec::SmallVec;
26use crate::internal_types::Filter;
27use crate::profiler;
28use core::time::Duration;
29use euclid::Scale;
30use api::MixBlendMode;
31use crate::filterdata::FilterDataHandle;
32use crate::tile_cache::SliceId;
33use crate::svg_filter::{FilterGraphNode, FilterGraphOp, get_coverage_target_svgfe};
34use crate::picture::BlitReason;
35use crate::prim_store::VectorKey;
36#[cfg(feature = "capture")]
37use serde::Serialize;
38
39#[allow(dead_code)]
42#[derive(Debug, Clone)]
43#[cfg_attr(feature = "capture", derive(Serialize))]
44pub enum PictureCompositeMode {
45 MixBlend(MixBlendMode),
47 Filter(Filter),
49 ComponentTransferFilter(FilterDataHandle),
51 Blit(BlitReason),
54 TileCache {
56 slice_id: SliceId,
57 },
58 SVGFEGraph(Vec<(FilterGraphNode, FilterGraphOp)>),
60 IntermediateSurface,
62}
63
64impl PictureCompositeMode {
65 pub fn get_rect(
66 &self,
67 surface: &SurfaceInfo,
68 sub_rect: Option<LayoutRect>,
69 ) -> LayoutRect {
70 let surface_rect = match sub_rect {
71 Some(sub_rect) => sub_rect,
72 None => surface.clipped_local_rect.cast_unit(),
73 };
74
75 match self {
76 PictureCompositeMode::Filter(Filter::Blur { width, height, should_inflate, .. }) => {
77 if *should_inflate {
78 let (width_factor, height_factor) = surface.clamp_blur_radius(*width, *height);
79
80 surface_rect.inflate(
81 width_factor.ceil() * BLUR_SAMPLE_SCALE,
82 height_factor.ceil() * BLUR_SAMPLE_SCALE,
83 )
84 } else {
85 surface_rect
86 }
87 }
88 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
89 let mut max_blur_radius = 0.0;
90 for shadow in shadows {
91 max_blur_radius = f32::max(max_blur_radius, shadow.blur_radius);
92 }
93
94 let (max_blur_radius_x, max_blur_radius_y) = surface.clamp_blur_radius(
95 max_blur_radius,
96 max_blur_radius,
97 );
98 let blur_inflation_x = max_blur_radius_x * BLUR_SAMPLE_SCALE;
99 let blur_inflation_y = max_blur_radius_y * BLUR_SAMPLE_SCALE;
100
101 surface_rect.inflate(blur_inflation_x, blur_inflation_y)
102 }
103 PictureCompositeMode::SVGFEGraph(ref filters) => {
104 get_coverage_target_svgfe(filters, surface_rect.cast_unit())
108 }
109 _ => {
110 surface_rect
111 }
112 }
113 }
114
115 pub fn get_coverage(
116 &self,
117 surface: &SurfaceInfo,
118 sub_rect: Option<LayoutRect>,
119 ) -> LayoutRect {
120 let surface_rect = match sub_rect {
121 Some(sub_rect) => sub_rect,
122 None => surface.clipped_local_rect.cast_unit(),
123 };
124
125 match self {
126 PictureCompositeMode::Filter(Filter::Blur { width, height, should_inflate, .. }) => {
127 if *should_inflate {
128 let (width_factor, height_factor) = surface.clamp_blur_radius(*width, *height);
129
130 surface_rect.inflate(
131 width_factor.ceil() * BLUR_SAMPLE_SCALE,
132 height_factor.ceil() * BLUR_SAMPLE_SCALE,
133 )
134 } else {
135 surface_rect
136 }
137 }
138 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
139 let mut rect = surface_rect;
140
141 for shadow in shadows {
142 let (blur_radius_x, blur_radius_y) = surface.clamp_blur_radius(
143 shadow.blur_radius,
144 shadow.blur_radius,
145 );
146 let blur_inflation_x = blur_radius_x * BLUR_SAMPLE_SCALE;
147 let blur_inflation_y = blur_radius_y * BLUR_SAMPLE_SCALE;
148
149 let shadow_rect = surface_rect
150 .translate(shadow.offset)
151 .inflate(blur_inflation_x, blur_inflation_y);
152 rect = rect.union(&shadow_rect);
153 }
154
155 rect
156 }
157 PictureCompositeMode::SVGFEGraph(ref filters) => {
158 let target_subregion = get_coverage_source_svgfe(filters, surface_rect.cast());
161 let source_subregion = get_coverage_target_svgfe(filters, surface_rect.cast());
162 target_subregion.union(&source_subregion)
163 }
164 _ => {
165 surface_rect
166 }
167 }
168 }
169
170 pub fn write_gpu_blocks(
171 &self,
172 surface: &SurfaceInfo,
173 gpu_buffers: &mut GpuBufferBuilder,
174 data_stores: &mut DataStores,
175 extra_gpu_data: &mut SmallVec<[GpuBufferAddress; 1]>,
176 ) {
177 match *self {
185 PictureCompositeMode::TileCache { .. } => {}
186 PictureCompositeMode::Filter(Filter::Blur { .. }) => {}
187 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
188 extra_gpu_data.resize(shadows.len(), GpuBufferAddress::INVALID);
189 for (shadow, extra_handle) in shadows.iter().zip(extra_gpu_data.iter_mut()) {
190 let mut writer = gpu_buffers.f32.write_blocks(5);
191 let prim_rect = surface.clipped_local_rect.cast_unit();
192
193 let (blur_inflation_x, blur_inflation_y) = surface.clamp_blur_radius(
197 shadow.blur_radius,
198 shadow.blur_radius,
199 );
200
201 let shadow_rect = prim_rect.inflate(
202 blur_inflation_x * BLUR_SAMPLE_SCALE,
203 blur_inflation_y * BLUR_SAMPLE_SCALE,
204 ).translate(shadow.offset);
205
206 writer.push(&ImageBrushPrimitiveData {
208 color: shadow.color.premultiplied(),
209 background_color: PremultipliedColorF::WHITE,
210 stretch_size: shadow_rect.size(),
211 });
212
213 writer.push(&BrushSegmentGpuData {
214 local_rect: shadow_rect,
215 extra_data: [0.0; 4],
216 });
217
218 *extra_handle = writer.finish();
219 }
220 }
221 PictureCompositeMode::Filter(ref filter) => {
222 match *filter {
223 Filter::ColorMatrix(ref m) => {
224 if extra_gpu_data.is_empty() {
225 extra_gpu_data.push(GpuBufferAddress::INVALID);
226 }
227 let mut writer = gpu_buffers.f32.write_blocks(5);
228 for i in 0..5 {
229 writer.push_one([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
230 }
231 extra_gpu_data[0] = writer.finish();
232 }
233 Filter::Flood(ref color) => {
234 if extra_gpu_data.is_empty() {
235 extra_gpu_data.push(GpuBufferAddress::INVALID);
236 }
237 let mut writer = gpu_buffers.f32.write_blocks(1);
238 writer.push_one(color.to_array());
239 extra_gpu_data[0] = writer.finish();
240 }
241 _ => {}
242 }
243 }
244 PictureCompositeMode::ComponentTransferFilter(handle) => {
245 let filter_data = &mut data_stores.filter_data[handle];
246 filter_data.write_gpu_blocks(&mut gpu_buffers.f32);
247 }
248 PictureCompositeMode::MixBlend(..) |
249 PictureCompositeMode::Blit(_) |
250 PictureCompositeMode::IntermediateSurface => {}
251 PictureCompositeMode::SVGFEGraph(ref filters) => {
252 for (_node, op) in filters {
254 match op {
255 FilterGraphOp::SVGFEComponentTransferInterned { handle, creates_pixels: _ } => {
256 let filter_data = &mut data_stores.filter_data[*handle];
257 filter_data.write_gpu_blocks(&mut gpu_buffers.f32);
258 }
259 _ => {}
260 }
261 }
262 }
263 }
264 }
265
266 pub fn kind(&self) -> &'static str {
269 match *self {
270 PictureCompositeMode::Blit(..) => "Blit",
271 PictureCompositeMode::ComponentTransferFilter(..) => "ComponentTransferFilter",
272 PictureCompositeMode::IntermediateSurface => "IntermediateSurface",
273 PictureCompositeMode::MixBlend(..) => "MixBlend",
274 PictureCompositeMode::SVGFEGraph(..) => "SVGFEGraph",
275 PictureCompositeMode::TileCache{..} => "TileCache",
276 PictureCompositeMode::Filter(Filter::Blur{..}) => "Filter::Blur",
277 PictureCompositeMode::Filter(Filter::Brightness(..)) => "Filter::Brightness",
278 PictureCompositeMode::Filter(Filter::ColorMatrix(..)) => "Filter::ColorMatrix",
279 PictureCompositeMode::Filter(Filter::ComponentTransfer) => "Filter::ComponentTransfer",
280 PictureCompositeMode::Filter(Filter::Contrast(..)) => "Filter::Contrast",
281 PictureCompositeMode::Filter(Filter::DropShadows(..)) => "Filter::DropShadows",
282 PictureCompositeMode::Filter(Filter::Flood(..)) => "Filter::Flood",
283 PictureCompositeMode::Filter(Filter::Grayscale(..)) => "Filter::Grayscale",
284 PictureCompositeMode::Filter(Filter::HueRotate(..)) => "Filter::HueRotate",
285 PictureCompositeMode::Filter(Filter::Identity) => "Filter::Identity",
286 PictureCompositeMode::Filter(Filter::Invert(..)) => "Filter::Invert",
287 PictureCompositeMode::Filter(Filter::LinearToSrgb) => "Filter::LinearToSrgb",
288 PictureCompositeMode::Filter(Filter::Opacity(..)) => "Filter::Opacity",
289 PictureCompositeMode::Filter(Filter::Saturate(..)) => "Filter::Saturate",
290 PictureCompositeMode::Filter(Filter::Sepia(..)) => "Filter::Sepia",
291 PictureCompositeMode::Filter(Filter::SrgbToLinear) => "Filter::SrgbToLinear",
292 PictureCompositeMode::Filter(Filter::SVGGraphNode(..)) => "Filter::SVGGraphNode",
293 }
294 }
295}
296
297pub fn prepare_composite_mode(
298 composite_mode: &PictureCompositeMode,
299 surface_index: SurfaceIndex,
300 parent_surface_index: SurfaceIndex,
301 surface_rects: &SurfaceAllocInfo,
302 snapshot: &Option<SnapshotInfo>,
303 can_use_shared_surface: bool,
304 frame_context: &FrameBuildingContext,
305 frame_state: &mut FrameBuildingState,
306 data_stores: &mut DataStores,
307 extra_gpu_data: &mut SmallVec<[GpuBufferAddress; 1]>,
308) -> (SurfaceDescriptor, [Option<RenderTaskId>; 2]) {
309 let surface = &frame_state.surfaces[surface_index.0];
310 let surface_spatial_node_index = surface.surface_spatial_node_index;
311 let raster_spatial_node_index = surface.raster_spatial_node_index;
312 let device_pixel_scale = surface.device_pixel_scale;
313
314 let primary_render_task_id;
315 let surface_descriptor;
316 let mut secondary_render_task_id = None;
317 match *composite_mode {
318 PictureCompositeMode::TileCache { .. } => {
319 unreachable!("handled above");
320 }
321 PictureCompositeMode::Filter(Filter::Blur { width, height, edge_mode, .. }) => {
322 let (width, height) = surface.clamp_blur_radius(width, height);
323
324 let width_std_deviation = width * surface.local_scale.0 * device_pixel_scale.0;
325 let height_std_deviation = height * surface.local_scale.1 * device_pixel_scale.0;
326 let blur_std_deviation = DeviceSize::new(
327 width_std_deviation,
328 height_std_deviation,
329 );
330
331 let original_size = surface_rects.clipped.size();
332
333 let adjusted_size = BlurTask::adjusted_blur_source_size(
334 original_size,
335 blur_std_deviation,
336 );
337
338 let clear_color = if adjusted_size == original_size {
339 None
340 } else {
341 Some(ColorF::TRANSPARENT)
342 };
343
344 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
345 let adjusted_size = adjusted_size.to_i32();
346
347 let uv_rect_kind = calculate_uv_rect_kind(
348 DeviceRect::from_origin_and_size(surface_rects.clipped.min, adjusted_size.to_f32()),
349 surface_rects.unclipped,
350 );
351
352 let picture_task_id = frame_state.rg_builder.add().init(
353 RenderTask::new_dynamic(
354 adjusted_size,
355 RenderTaskKind::new_picture(
356 adjusted_size,
357 surface_rects.needs_scissor_rect,
358 surface_rects.clipped.min,
359 surface_spatial_node_index,
360 raster_spatial_node_index,
361 device_pixel_scale,
362 None,
363 None,
364 clear_color,
365 cmd_buffer_index,
366 can_use_shared_surface,
367 Some(original_size.round().to_i32()),
368 )
369 ).with_uv_rect_kind(uv_rect_kind)
370 );
371
372
373 let blur_render_task_id = request_render_task(
374 frame_state,
375 snapshot,
376 &surface_rects,
377 false,
378 &mut|rg_builder, _| {
379 RenderTask::new_blur(
380 blur_std_deviation,
381 picture_task_id,
382 rg_builder,
383 RenderTargetKind::Color,
384 None,
385 original_size.to_i32(),
386 edge_mode,
387 )
388 }
389 );
390 primary_render_task_id = blur_render_task_id;
391
392 surface_descriptor = SurfaceDescriptor::new_chained(
393 picture_task_id,
394 blur_render_task_id,
395 surface_rects.clipped_local,
396 );
397 }
398 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
399 let surface = &frame_state.surfaces[surface_index.0];
400
401 let device_rect = surface_rects.clipped;
402
403 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
404
405 let picture_task_id = frame_state.rg_builder.add().init(
406 RenderTask::new_dynamic(
407 surface_rects.task_size,
408 RenderTaskKind::new_picture(
409 surface_rects.task_size,
410 surface_rects.needs_scissor_rect,
411 device_rect.min,
412 surface_spatial_node_index,
413 raster_spatial_node_index,
414 device_pixel_scale,
415 None,
416 None,
417 None,
418 cmd_buffer_index,
419 can_use_shared_surface,
420 None,
421 ),
422 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
423 );
424
425 let mut blur_tasks = BlurTaskCache::default();
426
427 extra_gpu_data.resize(shadows.len(), GpuBufferAddress::INVALID);
428
429 let mut blur_render_task_id = picture_task_id;
430 for shadow in shadows {
431 let (blur_radius_x, blur_radius_y) = surface.clamp_blur_radius(
432 shadow.blur_radius,
433 shadow.blur_radius,
434 );
435
436 blur_render_task_id = RenderTask::new_blur(
437 DeviceSize::new(
438 blur_radius_x * surface.local_scale.0 * device_pixel_scale.0,
439 blur_radius_y * surface.local_scale.1 * device_pixel_scale.0,
440 ),
441 picture_task_id,
442 frame_state.rg_builder,
443 RenderTargetKind::Color,
444 Some(&mut blur_tasks),
445 device_rect.size().to_i32(),
446 BlurEdgeMode::Duplicate,
447 );
448 }
449
450 frame_state.surface_builder.add_picture_render_task(picture_task_id);
451
452 primary_render_task_id = blur_render_task_id;
453 secondary_render_task_id = Some(picture_task_id);
454
455 surface_descriptor = SurfaceDescriptor::new_chained(
456 picture_task_id,
457 blur_render_task_id,
458 surface_rects.clipped_local,
459 );
460 }
461 PictureCompositeMode::MixBlend(mode) if BlendMode::from_mix_blend_mode(
462 mode,
463 frame_context.fb_config.gpu_supports_advanced_blend,
464 frame_context.fb_config.advanced_blend_is_coherent,
465 frame_context.fb_config.dual_source_blending_is_supported,
466 ).is_none() => {
467 let parent_surface = &frame_state.surfaces[parent_surface_index.0];
468
469 let map_pic_to_parent = SpaceMapper::new_with_target(
470 parent_surface.surface_spatial_node_index,
471 surface_spatial_node_index,
472 parent_surface.clipping_rect,
473 frame_context.spatial_tree,
474 );
475 let pic_rect = surface.clipped_local_rect;
476 let pic_in_raster_space = map_pic_to_parent
477 .map(&pic_rect)
478 .expect("bug: unable to map mix-blend content into parent");
479
480 let backdrop_rect = pic_in_raster_space;
481 let parent_surface_rect = parent_surface.clipping_rect;
482
483 let readback_task_id = match backdrop_rect.intersection(&parent_surface_rect) {
484 Some(available_rect) => {
485 let backdrop_rect = parent_surface.map_to_device_rect(
486 &backdrop_rect,
487 frame_context.spatial_tree,
488 );
489
490 let available_rect = parent_surface.map_to_device_rect(
491 &available_rect,
492 frame_context.spatial_tree,
493 ).round_out();
494
495 let backdrop_uv = calculate_uv_rect_kind(
496 available_rect,
497 backdrop_rect,
498 );
499
500 frame_state.rg_builder.add().init(
501 RenderTask::new_dynamic(
502 available_rect.size().to_i32(),
503 RenderTaskKind::new_readback(Some(available_rect.min)),
504 ).with_uv_rect_kind(backdrop_uv)
505 )
506 }
507 None => {
508 frame_state.rg_builder.add().init(
509 RenderTask::new_dynamic(
510 DeviceIntSize::new(16, 16),
511 RenderTaskKind::new_readback(None),
512 )
513 )
514 }
515 };
516
517 frame_state.surface_builder.add_child_render_task(
518 readback_task_id,
519 frame_state.rg_builder,
520 );
521
522 secondary_render_task_id = Some(readback_task_id);
523
524 let task_size = surface_rects.clipped.size().to_i32();
525
526 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
527
528 let is_opaque = false;
529 let render_task_id = request_render_task(
530 frame_state,
531 &snapshot,
532 &surface_rects,
533 is_opaque,
534 &mut|rg_builder, _| {
535 rg_builder.add().init(
536 RenderTask::new_dynamic(
537 task_size,
538 RenderTaskKind::new_picture(
539 task_size,
540 surface_rects.needs_scissor_rect,
541 surface_rects.clipped.min,
542 surface_spatial_node_index,
543 raster_spatial_node_index,
544 device_pixel_scale,
545 None,
546 None,
547 None,
548 cmd_buffer_index,
549 can_use_shared_surface,
550 None,
551 )
552 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
553 )
554 }
555 );
556
557 primary_render_task_id = render_task_id;
558
559 surface_descriptor = SurfaceDescriptor::new_simple(
560 render_task_id,
561 surface_rects.clipped_local,
562 );
563 }
564 PictureCompositeMode::Filter(..) => {
565 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
566
567 let is_opaque = false;
568 let render_task_id = request_render_task(
569 frame_state,
570 snapshot,
571 &surface_rects,
572 is_opaque,
573 &mut|rg_builder, _| {
574 rg_builder.add().init(
575 RenderTask::new_dynamic(
576 surface_rects.task_size,
577 RenderTaskKind::new_picture(
578 surface_rects.task_size,
579 surface_rects.needs_scissor_rect,
580 surface_rects.clipped.min,
581 surface_spatial_node_index,
582 raster_spatial_node_index,
583 device_pixel_scale,
584 None,
585 None,
586 None,
587 cmd_buffer_index,
588 can_use_shared_surface,
589 None,
590 )
591 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
592 )
593 },
594 );
595
596 primary_render_task_id = render_task_id;
597
598 surface_descriptor = SurfaceDescriptor::new_simple(
599 render_task_id,
600 surface_rects.clipped_local,
601 );
602 }
603 PictureCompositeMode::ComponentTransferFilter(..) => {
604 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
605
606 let is_opaque = false;
607 let render_task_id = request_render_task(
608 frame_state,
609 snapshot,
610 &surface_rects,
611 is_opaque,
612 &mut|rg_builder, _| {
613 rg_builder.add().init(
614 RenderTask::new_dynamic(
615 surface_rects.task_size,
616 RenderTaskKind::new_picture(
617 surface_rects.task_size,
618 surface_rects.needs_scissor_rect,
619 surface_rects.clipped.min,
620 surface_spatial_node_index,
621 raster_spatial_node_index,
622 device_pixel_scale,
623 None,
624 None,
625 None,
626 cmd_buffer_index,
627 can_use_shared_surface,
628 None,
629 )
630 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
631 )
632 }
633 );
634
635 primary_render_task_id = render_task_id;
636
637 surface_descriptor = SurfaceDescriptor::new_simple(
638 render_task_id,
639 surface_rects.clipped_local,
640 );
641 }
642 PictureCompositeMode::MixBlend(..) |
643 PictureCompositeMode::Blit(_) => {
644 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
645
646 let is_opaque = false;
647 let render_task_id = request_render_task(
648 frame_state,
649 snapshot,
650 &surface_rects,
651 is_opaque,
652 &mut|rg_builder, _| {
653 rg_builder.add().init(
654 RenderTask::new_dynamic(
655 surface_rects.task_size,
656 RenderTaskKind::new_picture(
657 surface_rects.task_size,
658 surface_rects.needs_scissor_rect,
659 surface_rects.clipped.min,
660 surface_spatial_node_index,
661 raster_spatial_node_index,
662 device_pixel_scale,
663 None,
664 None,
665 None,
666 cmd_buffer_index,
667 can_use_shared_surface,
668 None,
669 )
670 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
671 )
672 }
673 );
674
675 primary_render_task_id = render_task_id;
676
677 surface_descriptor = SurfaceDescriptor::new_simple(
678 render_task_id,
679 surface_rects.clipped_local,
680 );
681 }
682 PictureCompositeMode::IntermediateSurface => {
683 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
684
685 let is_opaque = false;
686 let render_task_id = request_render_task(
687 frame_state,
688 snapshot,
689 &surface_rects,
690 is_opaque,
691 &mut|rg_builder, _| {
692 rg_builder.add().init(
693 RenderTask::new_dynamic(
694 surface_rects.task_size,
695 RenderTaskKind::new_picture(
696 surface_rects.task_size,
697 surface_rects.needs_scissor_rect,
698 surface_rects.clipped.min,
699 surface_spatial_node_index,
700 raster_spatial_node_index,
701 device_pixel_scale,
702 None,
703 None,
704 None,
705 cmd_buffer_index,
706 can_use_shared_surface,
707 None,
708 )
709 ).with_uv_rect_kind(surface_rects.uv_rect_kind)
710 )
711 }
712 );
713
714 primary_render_task_id = render_task_id;
715
716 surface_descriptor = SurfaceDescriptor::new_simple(
717 render_task_id,
718 surface_rects.clipped_local,
719 );
720 }
721 PictureCompositeMode::SVGFEGraph(ref filters) => {
722 let cmd_buffer_index = frame_state.cmd_buffers.create_cmd_buffer();
723
724 let prim_subregion = surface_rects.unclipped;
725 let target_subregion = surface_rects.clipped;
726 let source_subregion = surface_rects.source;
727
728 let source_task_size = source_subregion.round_out().size().to_i32();
729 let source_task_size = if source_task_size.width > 0 && source_task_size.height > 0 {
730 source_task_size
731 } else {
732 DeviceIntSize::new(1,1)
733 };
734 let picture_task_id = frame_state.rg_builder.add().init(
735 RenderTask::new_dynamic(
736 source_task_size,
737 RenderTaskKind::new_picture(
738 source_task_size,
739 surface_rects.needs_scissor_rect,
740 source_subregion.min,
741 surface_spatial_node_index,
742 raster_spatial_node_index,
743 device_pixel_scale,
744 None,
745 None,
746 None,
747 cmd_buffer_index,
748 can_use_shared_surface,
749 None,
750 )
751 )
752 );
753
754 let subregion_to_device_scale_x = surface_rects.clipped_notsnapped.width() / surface_rects.clipped_local.width();
755 let subregion_to_device_scale_y = surface_rects.clipped_notsnapped.height() / surface_rects.clipped_local.height();
756 let subregion_to_device_offset_x = surface_rects.clipped_notsnapped.min.x - (surface_rects.clipped_local.min.x * subregion_to_device_scale_x).floor();
757 let subregion_to_device_offset_y = surface_rects.clipped_notsnapped.min.y - (surface_rects.clipped_local.min.y * subregion_to_device_scale_y).floor();
758
759 let filter_task_id = request_render_task(
760 frame_state,
761 snapshot,
762 &surface_rects,
763 false,
764 &mut|rg_builder, gpu_buffer| {
765 RenderTask::new_svg_filter_graph(
766 filters,
767 rg_builder,
768 gpu_buffer,
769 data_stores,
770 surface_rects.uv_rect_kind,
771 picture_task_id,
772 source_subregion.cast_unit(),
773 target_subregion.cast_unit(),
774 prim_subregion.cast_unit(),
775 subregion_to_device_scale_x,
776 subregion_to_device_scale_y,
777 subregion_to_device_offset_x,
778 subregion_to_device_offset_y,
779 )
780 }
781 );
782
783 primary_render_task_id = filter_task_id;
784
785 surface_descriptor = SurfaceDescriptor::new_chained(
786 picture_task_id,
787 filter_task_id,
788 surface_rects.clipped_local,
789 );
790 }
791 }
792
793 (
794 surface_descriptor,
795 [
796 Some(primary_render_task_id),
797 secondary_render_task_id,
798 ]
799 )
800}
801
802fn request_render_task(
803 frame_state: &mut FrameBuildingState,
804 snapshot: &Option<SnapshotInfo>,
805 surface_rects: &SurfaceAllocInfo,
806 is_opaque: bool,
807 f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
808) -> RenderTaskId {
809
810 let task_id = match snapshot {
811 Some(info) => {
812 let adjustment = AdjustedImageSource::from_rects(
813 &info.area,
814 &surface_rects.clipped_local.cast_unit()
815 );
816 let task_id = frame_state.resource_cache.render_as_image(
817 info.key.as_image(),
818 surface_rects.task_size,
819 frame_state.rg_builder,
820 &mut frame_state.frame_gpu_data.f32,
821 is_opaque,
822 &adjustment,
823 f
824 );
825
826 frame_state.surface_builder.add_child_render_task(
831 task_id,
832 frame_state.rg_builder,
833 );
834
835 frame_state.image_dependencies.insert(info.key.as_image(), task_id);
836
837 task_id
838 }
839 None => {
840 f(
841 frame_state.rg_builder,
842 &mut frame_state.frame_gpu_data.f32,
843 )
844 }
845 };
846
847 task_id
848}
849
850#[derive(Debug)]
853pub struct SurfaceAllocInfo {
854 pub task_size: DeviceIntSize,
855 pub needs_scissor_rect: bool,
856 pub clipped: DeviceRect,
857 pub unclipped: DeviceRect,
858 pub source: DeviceRect,
861 pub clipped_notsnapped: DeviceRect,
863 pub clipped_local: PictureRect,
864 pub uv_rect_kind: UvRectKind,
865}
866
867pub fn get_surface_rects(
868 surface_index: SurfaceIndex,
869 composite_mode: &PictureCompositeMode,
870 parent_surface_index: SurfaceIndex,
871 surfaces: &mut [SurfaceInfo],
872 spatial_tree: &SpatialTree,
873 max_surface_size: f32,
874 force_scissor_rect: bool,
875) -> Option<SurfaceAllocInfo> {
876 let parent_surface = &surfaces[parent_surface_index.0];
877
878 let local_to_parent = SpaceMapper::new_with_target(
879 parent_surface.surface_spatial_node_index,
880 surfaces[surface_index.0].surface_spatial_node_index,
881 parent_surface.clipping_rect,
882 spatial_tree,
883 );
884
885 let local_clip_rect = local_to_parent
886 .unmap(&parent_surface.clipping_rect)
887 .unwrap_or(PictureRect::max_rect())
888 .cast_unit();
889
890 let surface = &mut surfaces[surface_index.0];
891
892 let (clipped_local, unclipped_local, source_local) = match composite_mode {
893 PictureCompositeMode::SVGFEGraph(ref filters) => {
894 let prim_subregion = composite_mode.get_rect(surface, None);
895
896 let visible_subregion: LayoutRect =
897 prim_subregion.cast_unit()
898 .intersection(&local_clip_rect)
899 .unwrap_or(PictureRect::zero())
900 .cast_unit();
901
902 if visible_subregion.is_empty() {
903 return None;
904 }
905
906 let source_potential_subregion = get_coverage_source_svgfe(
907 filters, visible_subregion.cast_unit());
908 let source_subregion =
909 source_potential_subregion
910 .intersection(&surface.unclipped_local_rect.cast_unit())
911 .unwrap_or(LayoutRect::zero());
912
913 let coverage_subregion = source_subregion.union(&visible_subregion);
914
915 (coverage_subregion.cast_unit(), prim_subregion.cast_unit(), source_subregion.cast_unit())
916 }
917 PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
918 let local_prim_rect = surface.clipped_local_rect;
919
920 let mut max_blur_inflation_x: f32 = 0.0;
926 let mut max_blur_inflation_y: f32 = 0.0;
927 for shadow in shadows {
928 let (blur_radius_x, blur_radius_y) = surface.clamp_blur_radius(
929 shadow.blur_radius,
930 shadow.blur_radius,
931 );
932 max_blur_inflation_x = max_blur_inflation_x.max(blur_radius_x * BLUR_SAMPLE_SCALE);
933 max_blur_inflation_y = max_blur_inflation_y.max(blur_radius_y * BLUR_SAMPLE_SCALE);
934 }
935
936 let mut required_local_rect = local_prim_rect
937 .intersection(&local_clip_rect)
938 .map(|r| r.inflate(max_blur_inflation_x, max_blur_inflation_y))
939 .unwrap_or(PictureRect::zero());
940
941 for shadow in shadows {
942 let (blur_radius_x, blur_radius_y) = surface.clamp_blur_radius(
943 shadow.blur_radius,
944 shadow.blur_radius,
945 );
946 let blur_inflation_x = blur_radius_x * BLUR_SAMPLE_SCALE;
947 let blur_inflation_y = blur_radius_y * BLUR_SAMPLE_SCALE;
948
949 let local_shadow_rect = local_prim_rect
950 .translate(shadow.offset.cast_unit())
951 .inflate(blur_inflation_x, blur_inflation_y);
952
953 if let Some(clipped_shadow_rect) = local_clip_rect.intersection(&local_shadow_rect) {
954 let required_shadow_rect = clipped_shadow_rect.inflate(blur_inflation_x, blur_inflation_y);
955
956 let local_clipped_shadow_rect = required_shadow_rect.translate(-shadow.offset.cast_unit());
957
958 required_local_rect = required_local_rect.union(&local_clipped_shadow_rect);
959 }
960 }
961
962 let unclipped = composite_mode.get_rect(surface, None);
963 let clipped = required_local_rect;
964
965 let clipped = match clipped.intersection(&unclipped.cast_unit()) {
966 Some(rect) => rect,
967 None => return None,
968 };
969
970 (clipped, unclipped, clipped)
971 }
972 _ => {
973 let surface_origin = surface.clipped_local_rect.min.to_vector().cast_unit();
974
975 let normalized_prim_rect = composite_mode
976 .get_rect(surface, None)
977 .translate(-surface_origin);
978
979 let normalized_clip_rect = local_clip_rect
980 .cast_unit()
981 .translate(-surface_origin);
982
983 let norm_clipped_rect = match normalized_prim_rect.intersection(&normalized_clip_rect) {
984 Some(rect) => rect,
985 None => return None,
986 };
987
988 let norm_clipped_rect = composite_mode.get_rect(surface, Some(norm_clipped_rect));
989
990 let norm_clipped_rect = match norm_clipped_rect.intersection(&normalized_prim_rect) {
991 Some(rect) => rect,
992 None => return None,
993 };
994
995 let unclipped = normalized_prim_rect.translate(surface_origin);
996 let clipped = norm_clipped_rect.translate(surface_origin);
997
998 (clipped.cast_unit(), unclipped.cast_unit(), clipped.cast_unit())
999 }
1000 };
1001
1002 let (mut clipped, mut unclipped, mut source) = if surface.raster_spatial_node_index != surface.surface_spatial_node_index {
1003 assert_eq!(surface.device_pixel_scale.0, 1.0);
1004
1005 let local_to_world = SpaceMapper::new_with_target(
1006 spatial_tree.root_reference_frame_index(),
1007 surface.surface_spatial_node_index,
1008 WorldRect::max_rect(),
1009 spatial_tree,
1010 );
1011
1012 let clipped = local_to_world.map(&clipped_local.cast_unit()).unwrap() * surface.device_pixel_scale;
1013 let unclipped = local_to_world.map(&unclipped_local).unwrap() * surface.device_pixel_scale;
1014 let source = local_to_world.map(&source_local.cast_unit()).unwrap() * surface.device_pixel_scale;
1015
1016 (clipped, unclipped, source)
1017 } else {
1018 let clipped = clipped_local.cast_unit() * surface.device_pixel_scale;
1019 let unclipped = unclipped_local.cast_unit() * surface.device_pixel_scale;
1020 let source = source_local.cast_unit() * surface.device_pixel_scale;
1021
1022 (clipped, unclipped, source)
1023 };
1024 let mut clipped_snapped = clipped.round_out();
1025 let mut source_snapped = source.round_out();
1026
1027 let max_dimension =
1028 clipped_snapped.width().max(
1029 clipped_snapped.height().max(
1030 source_snapped.width().max(
1031 source_snapped.height()
1032 ))).ceil();
1033 if max_dimension > max_surface_size {
1034 let max_dimension =
1035 clipped_local.width().max(
1036 clipped_local.height().max(
1037 source_local.width().max(
1038 source_local.height()
1039 ))).ceil();
1040 surface.raster_spatial_node_index = surface.surface_spatial_node_index;
1041 surface.device_pixel_scale = Scale::new(max_surface_size / max_dimension);
1042 surface.local_scale = (1.0, 1.0);
1043
1044 let add_markers = profiler::thread_is_being_profiled();
1045 if add_markers {
1046 let new_clipped = (clipped_local.cast_unit() * surface.device_pixel_scale).round();
1047 let new_source = (source_local.cast_unit() * surface.device_pixel_scale).round();
1048 profiler::add_text_marker("SurfaceSizeLimited",
1049 format!("Surface for {:?} reduced from raster {:?} (source {:?}) to local {:?} (source {:?})",
1050 composite_mode.kind(),
1051 clipped.size(), source.size(),
1052 new_clipped, new_source).as_str(),
1053 Duration::from_secs_f32(new_clipped.width() * new_clipped.height() / 1000000000.0));
1054 }
1055
1056 clipped = clipped_local.cast_unit() * surface.device_pixel_scale;
1057 unclipped = unclipped_local.cast_unit() * surface.device_pixel_scale;
1058 source = source_local.cast_unit() * surface.device_pixel_scale;
1059 clipped_snapped = clipped.round();
1060 source_snapped = source.round();
1061 }
1062
1063 let task_size = clipped_snapped.size().to_i32();
1064 let task_size = task_size.min(DeviceIntSize::new(max_surface_size as i32, max_surface_size as i32));
1065 debug_assert!(
1066 task_size.width <= max_surface_size as i32 &&
1067 task_size.height <= max_surface_size as i32,
1068 "task_size {:?} for {:?} must be within max_surface_size {}",
1069 task_size,
1070 composite_mode.kind(),
1071 max_surface_size);
1072
1073 let uv_rect_kind = calculate_uv_rect_kind(
1074 clipped_snapped,
1075 unclipped,
1076 );
1077
1078 if task_size.width == 0 || task_size.height == 0 {
1079 return None;
1080 }
1081
1082 let needs_scissor_rect = force_scissor_rect || !clipped_local.contains_box(&surface.unclipped_local_rect);
1083
1084 Some(SurfaceAllocInfo {
1085 task_size,
1086 needs_scissor_rect,
1087 clipped: clipped_snapped,
1088 unclipped,
1089 source: source_snapped,
1090 clipped_notsnapped: clipped,
1091 clipped_local,
1092 uv_rect_kind,
1093 })
1094}
1095
1096pub fn calculate_uv_rect_kind(
1097 clipped: DeviceRect,
1098 unclipped: DeviceRect,
1099) -> UvRectKind {
1100 let top_left = calculate_screen_uv(
1101 unclipped.top_left().cast_unit(),
1102 clipped,
1103 );
1104
1105 let top_right = calculate_screen_uv(
1106 unclipped.top_right().cast_unit(),
1107 clipped,
1108 );
1109
1110 let bottom_left = calculate_screen_uv(
1111 unclipped.bottom_left().cast_unit(),
1112 clipped,
1113 );
1114
1115 let bottom_right = calculate_screen_uv(
1116 unclipped.bottom_right().cast_unit(),
1117 clipped,
1118 );
1119
1120 UvRectKind::Quad {
1121 top_left,
1122 top_right,
1123 bottom_left,
1124 bottom_right,
1125 }
1126}
1127
1128#[cfg_attr(feature = "capture", derive(Serialize))]
1131#[cfg_attr(feature = "replay", derive(Deserialize))]
1132#[derive(Debug, Clone, MallocSizeOf, PartialEq, Hash, Eq)]
1133pub enum PictureCompositeKey {
1134 Identity,
1136
1137 Blur(Au, Au, bool, BlurEdgeMode),
1139 Brightness(Au),
1140 Contrast(Au),
1141 Grayscale(Au),
1142 HueRotate(Au),
1143 Invert(Au),
1144 Opacity(Au),
1145 OpacityBinding(PropertyBindingId, Au),
1146 Saturate(Au),
1147 Sepia(Au),
1148 DropShadows(Vec<(VectorKey, Au, ColorU)>),
1149 ColorMatrix([Au; 20]),
1150 SrgbToLinear,
1151 LinearToSrgb,
1152 ComponentTransfer(ItemUid),
1153 Flood(ColorU),
1154 SVGFEGraph(Vec<(FilterGraphNodeKey, FilterGraphOpKey)>),
1155
1156 Multiply,
1158 Screen,
1159 Overlay,
1160 Darken,
1161 Lighten,
1162 ColorDodge,
1163 ColorBurn,
1164 HardLight,
1165 SoftLight,
1166 Difference,
1167 Exclusion,
1168 Hue,
1169 Saturation,
1170 Color,
1171 Luminosity,
1172 PlusLighter,
1173}
1174
1175impl From<Option<PictureCompositeMode>> for PictureCompositeKey {
1176 fn from(mode: Option<PictureCompositeMode>) -> Self {
1177 match mode {
1178 Some(PictureCompositeMode::MixBlend(mode)) => {
1179 match mode {
1180 MixBlendMode::Normal => PictureCompositeKey::Identity,
1181 MixBlendMode::Multiply => PictureCompositeKey::Multiply,
1182 MixBlendMode::Screen => PictureCompositeKey::Screen,
1183 MixBlendMode::Overlay => PictureCompositeKey::Overlay,
1184 MixBlendMode::Darken => PictureCompositeKey::Darken,
1185 MixBlendMode::Lighten => PictureCompositeKey::Lighten,
1186 MixBlendMode::ColorDodge => PictureCompositeKey::ColorDodge,
1187 MixBlendMode::ColorBurn => PictureCompositeKey::ColorBurn,
1188 MixBlendMode::HardLight => PictureCompositeKey::HardLight,
1189 MixBlendMode::SoftLight => PictureCompositeKey::SoftLight,
1190 MixBlendMode::Difference => PictureCompositeKey::Difference,
1191 MixBlendMode::Exclusion => PictureCompositeKey::Exclusion,
1192 MixBlendMode::Hue => PictureCompositeKey::Hue,
1193 MixBlendMode::Saturation => PictureCompositeKey::Saturation,
1194 MixBlendMode::Color => PictureCompositeKey::Color,
1195 MixBlendMode::Luminosity => PictureCompositeKey::Luminosity,
1196 MixBlendMode::PlusLighter => PictureCompositeKey::PlusLighter,
1197 }
1198 }
1199 Some(PictureCompositeMode::Filter(op)) => {
1200 match op {
1201 Filter::Blur { width, height, should_inflate, edge_mode } => {
1202 PictureCompositeKey::Blur(
1203 Au::from_f32_px(width),
1204 Au::from_f32_px(height),
1205 should_inflate,
1206 edge_mode,
1207 )
1208 }
1209 Filter::Brightness(value) => PictureCompositeKey::Brightness(Au::from_f32_px(value)),
1210 Filter::Contrast(value) => PictureCompositeKey::Contrast(Au::from_f32_px(value)),
1211 Filter::Grayscale(value) => PictureCompositeKey::Grayscale(Au::from_f32_px(value)),
1212 Filter::HueRotate(value) => PictureCompositeKey::HueRotate(Au::from_f32_px(value)),
1213 Filter::Invert(value) => PictureCompositeKey::Invert(Au::from_f32_px(value)),
1214 Filter::Saturate(value) => PictureCompositeKey::Saturate(Au::from_f32_px(value)),
1215 Filter::Sepia(value) => PictureCompositeKey::Sepia(Au::from_f32_px(value)),
1216 Filter::SrgbToLinear => PictureCompositeKey::SrgbToLinear,
1217 Filter::LinearToSrgb => PictureCompositeKey::LinearToSrgb,
1218 Filter::Identity => PictureCompositeKey::Identity,
1219 Filter::DropShadows(ref shadows) => {
1220 PictureCompositeKey::DropShadows(
1221 shadows.iter().map(|shadow| {
1222 (shadow.offset.into(), Au::from_f32_px(shadow.blur_radius), shadow.color.into())
1223 }).collect()
1224 )
1225 }
1226 Filter::Opacity(binding, _) => {
1227 match binding {
1228 PropertyBinding::Value(value) => {
1229 PictureCompositeKey::Opacity(Au::from_f32_px(value))
1230 }
1231 PropertyBinding::Binding(key, default) => {
1232 PictureCompositeKey::OpacityBinding(key.id, Au::from_f32_px(default))
1233 }
1234 }
1235 }
1236 Filter::ColorMatrix(values) => {
1237 let mut quantized_values: [Au; 20] = [Au(0); 20];
1238 for (value, result) in values.iter().zip(quantized_values.iter_mut()) {
1239 *result = Au::from_f32_px(*value);
1240 }
1241 PictureCompositeKey::ColorMatrix(quantized_values)
1242 }
1243 Filter::ComponentTransfer => unreachable!(),
1244 Filter::Flood(color) => PictureCompositeKey::Flood(color.into()),
1245 Filter::SVGGraphNode(_node, _op) => unreachable!(),
1246 }
1247 }
1248 Some(PictureCompositeMode::ComponentTransferFilter(handle)) => {
1249 PictureCompositeKey::ComponentTransfer(handle.uid())
1250 }
1251 Some(PictureCompositeMode::SVGFEGraph(filter_nodes)) => {
1252 PictureCompositeKey::SVGFEGraph(
1253 filter_nodes.into_iter().map(|(node, op)| {
1254 (node.into(), op.into())
1255 }).collect())
1256 }
1257 Some(PictureCompositeMode::Blit(_)) |
1258 Some(PictureCompositeMode::TileCache { .. }) |
1259 Some(PictureCompositeMode::IntermediateSurface) |
1260 None => {
1261 PictureCompositeKey::Identity
1262 }
1263 }
1264 }
1265}