1use api::{LineStyle, LineOrientation, ColorF, FilterOpGraphPictureBufferId};
6use api::{MAX_RENDER_TASK_SIZE, SVGFE_GRAPH_MAX};
7use api::units::*;
8use std::time::Duration;
9use crate::box_shadow::BLUR_SAMPLE_SCALE;
10use crate::render_task_graph::SubTaskRange;
11use crate::clip::ClipNodeRange;
12use crate::command_buffer::{CommandBufferIndex, QuadFlags};
13use crate::pattern::{PatternKind, PatternShaderInput};
14use crate::profiler::{add_text_marker};
15use crate::spatial_tree::SpatialNodeIndex;
16use crate::frame_builder::FrameBuilderConfig;
17use crate::gpu_types::{BorderInstance, UvRectKind, BlurEdgeMode, ClipSpace};
18use crate::internal_types::{CacheTextureId, FastHashMap, TextureSource, Swizzle};
19use crate::svg_filter::{FilterGraphNode, FilterGraphOp, FilterGraphPictureReference, SVGFE_CONVOLVE_VALUES_LIMIT};
20use crate::picture::ResolvedSurfaceTexture;
21use crate::tile_cache::MAX_SURFACE_SIZE;
22use crate::transform::GpuTransformId;
23use crate::prim_store::ClipData;
24use crate::resource_cache::ImageRequest;
25use std::{usize, f32, i32, u32};
26use crate::renderer::{GpuBufferAddress, GpuBufferBuilder, GpuBufferBuilderF};
27use crate::render_backend::DataStores;
28use crate::render_target::{ResolveOp, RenderTargetKind};
29use crate::render_task_graph::{PassId, RenderTaskId, RenderTaskGraphBuilder};
30use crate::render_task_cache::RenderTaskCacheEntryHandle;
31use crate::segment::EdgeMask;
32use smallvec::SmallVec;
33
34const FLOATS_PER_RENDER_TASK_INFO: usize = 8;
35pub const MAX_BLUR_STD_DEVIATION: f32 = 4.0;
36pub const MIN_DOWNSCALING_RT_SIZE: i32 = 8;
37
38fn render_task_sanity_check(size: &DeviceIntSize) {
39 if size.width > MAX_RENDER_TASK_SIZE ||
40 size.height > MAX_RENDER_TASK_SIZE {
41 error!("Attempting to create a render task of size {}x{}", size.width, size.height);
42 panic!();
43 }
44}
45
46#[derive(Copy, Clone, PartialEq)]
47#[repr(C)]
48#[cfg_attr(feature = "capture", derive(Serialize))]
49#[cfg_attr(feature = "replay", derive(Deserialize))]
50pub struct RenderTaskAddress(pub i32);
51
52impl std::fmt::Debug for RenderTaskAddress {
53 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
54 write!(f, "#{}", self.0)
55 }
56}
57
58impl Into<RenderTaskAddress> for RenderTaskId {
59 fn into(self) -> RenderTaskAddress {
60 RenderTaskAddress(self.index as i32)
61 }
62}
63
64#[derive(Clone, Debug, Eq, PartialEq, Hash)]
67#[cfg_attr(feature = "capture", derive(Serialize))]
68#[cfg_attr(feature = "replay", derive(Deserialize))]
69pub enum StaticRenderTaskSurface {
70 TextureCache {
73 texture: CacheTextureId,
75 target_kind: RenderTargetKind,
77 },
78 ReadOnly {
81 source: TextureSource,
82 },
83 PictureCache {
86 surface: ResolvedSurfaceTexture,
88 },
89}
90
91#[derive(Clone, Debug)]
93#[cfg_attr(feature = "capture", derive(Serialize))]
94#[cfg_attr(feature = "replay", derive(Deserialize))]
95pub enum RenderTaskLocation {
96 Unallocated {
101 size: DeviceIntSize,
103 },
104 CacheRequest {
106 size: DeviceIntSize,
107 },
108 Existing {
110 parent_task_id: RenderTaskId,
111 size: DeviceIntSize,
113 },
114
115 Dynamic {
121 texture_id: CacheTextureId,
123 rect: DeviceIntRect,
125 },
126 Static {
128 surface: StaticRenderTaskSurface,
130 rect: DeviceIntRect,
132 },
133}
134
135impl RenderTaskLocation {
136 pub fn is_dynamic(&self) -> bool {
138 match *self {
139 RenderTaskLocation::Dynamic { .. } => true,
140 _ => false,
141 }
142 }
143
144 pub fn size(&self) -> DeviceIntSize {
145 match self {
146 RenderTaskLocation::Unallocated { size } => *size,
147 RenderTaskLocation::Dynamic { rect, .. } => rect.size(),
148 RenderTaskLocation::Static { rect, .. } => rect.size(),
149 RenderTaskLocation::CacheRequest { size } => *size,
150 RenderTaskLocation::Existing { size, .. } => *size,
151 }
152 }
153}
154
155#[derive(Debug)]
156#[cfg_attr(feature = "capture", derive(Serialize))]
157#[cfg_attr(feature = "replay", derive(Deserialize))]
158pub struct CachedTask {
159 pub target_kind: RenderTargetKind,
160}
161
162#[derive(Debug)]
163#[cfg_attr(feature = "capture", derive(Serialize))]
164#[cfg_attr(feature = "replay", derive(Deserialize))]
165pub struct ImageRequestTask {
166 pub request: ImageRequest,
167 pub is_composited: bool,
168}
169
170#[derive(Debug)]
171#[cfg_attr(feature = "capture", derive(Serialize))]
172#[cfg_attr(feature = "replay", derive(Deserialize))]
173pub struct CacheMaskTask {
174 pub actual_rect: DeviceRect,
175 pub root_spatial_node_index: SpatialNodeIndex,
176 pub clip_node_range: ClipNodeRange,
177 pub device_pixel_scale: DevicePixelScale,
178 pub clear_to_one: bool,
179}
180
181#[derive(Debug)]
182#[cfg_attr(feature = "capture", derive(Serialize))]
183#[cfg_attr(feature = "replay", derive(Deserialize))]
184pub struct ClipRegionTask {
185 pub local_pos: LayoutPoint,
186 pub device_pixel_scale: DevicePixelScale,
187 pub clip_data: ClipData,
188 pub clear_to_one: bool,
189}
190
191#[cfg_attr(feature = "capture", derive(Serialize))]
192#[cfg_attr(feature = "replay", derive(Deserialize))]
193pub struct EmptyTask {
194 pub content_origin: DevicePoint,
195 pub device_pixel_scale: DevicePixelScale,
196 pub raster_spatial_node_index: SpatialNodeIndex,
197}
198
199#[cfg_attr(feature = "capture", derive(Serialize))]
200#[cfg_attr(feature = "replay", derive(Deserialize))]
201pub struct PrimTask {
202 pub pattern: PatternKind,
203 pub pattern_input: PatternShaderInput,
204 pub content_origin: DevicePoint,
205 pub prim_address_f: GpuBufferAddress,
206 pub transform_id: GpuTransformId,
207 pub edge_flags: EdgeMask,
208 pub quad_flags: QuadFlags,
209 pub prim_needs_scissor_rect: bool,
210 pub texture_input: RenderTaskId,
211}
212
213#[cfg_attr(feature = "capture", derive(Serialize))]
214#[cfg_attr(feature = "replay", derive(Deserialize))]
215pub struct TileCompositeTask {
216 pub clear_color: ColorF,
217 pub scissor_rect: DeviceIntRect,
218 pub valid_rect: DeviceIntRect,
219 pub task_id: Option<RenderTaskId>,
220 pub sub_rect_offset: DeviceIntVector2D,
221}
222
223#[cfg_attr(feature = "capture", derive(Serialize))]
224#[cfg_attr(feature = "replay", derive(Deserialize))]
225pub struct PictureTask {
226 pub can_merge: bool,
227 pub content_origin: DevicePoint,
228 pub surface_spatial_node_index: SpatialNodeIndex,
229 pub raster_spatial_node_index: SpatialNodeIndex,
230 pub device_pixel_scale: DevicePixelScale,
231 pub clear_color: Option<ColorF>,
232 pub scissor_rect: Option<DeviceIntRect>,
233 pub valid_rect: Option<DeviceIntRect>,
234 pub cmd_buffer_index: CommandBufferIndex,
235 pub resolve_op: Option<ResolveOp>,
236 pub content_size: DeviceIntSize,
237 pub can_use_shared_surface: bool,
238}
239
240impl PictureTask {
241 pub fn duplicate(
246 &self,
247 cmd_buffer_index: CommandBufferIndex,
248 ) -> Self {
249 assert_eq!(self.resolve_op, None);
250
251 PictureTask {
252 clear_color: None,
253 cmd_buffer_index,
254 resolve_op: None,
255 can_use_shared_surface: false,
256 ..*self
257 }
258 }
259}
260
261#[derive(Debug)]
262#[cfg_attr(feature = "capture", derive(Serialize))]
263#[cfg_attr(feature = "replay", derive(Deserialize))]
264pub struct BlurTask {
265 pub blur_std_deviation: f32,
266 pub target_kind: RenderTargetKind,
267 pub blur_region: DeviceIntSize,
268 pub edge_mode: BlurEdgeMode,
269}
270
271impl BlurTask {
272 pub fn adjusted_blur_source_size(original_size: DeviceSize, mut std_dev: DeviceSize) -> DeviceSize {
276 let mut adjusted_size = original_size;
277 let mut scale_factor = 1.0;
278 while std_dev.width > MAX_BLUR_STD_DEVIATION && std_dev.height > MAX_BLUR_STD_DEVIATION {
279 if adjusted_size.width < MIN_DOWNSCALING_RT_SIZE as f32 ||
280 adjusted_size.height < MIN_DOWNSCALING_RT_SIZE as f32 {
281 break;
282 }
283 std_dev = std_dev * 0.5;
284 scale_factor *= 2.0;
285 adjusted_size = (original_size.to_f32() / scale_factor).ceil();
286 }
287
288 (adjusted_size * scale_factor).round()
289 }
290}
291
292#[derive(Debug)]
293#[cfg_attr(feature = "capture", derive(Serialize))]
294#[cfg_attr(feature = "replay", derive(Deserialize))]
295pub struct ScalingTask {
296 pub target_kind: RenderTargetKind,
297 pub padding: DeviceIntSideOffsets,
298}
299
300#[derive(Debug)]
301#[cfg_attr(feature = "capture", derive(Serialize))]
302#[cfg_attr(feature = "replay", derive(Deserialize))]
303pub struct BorderTask {
304 pub instances: Vec<BorderInstance>,
305}
306
307#[derive(Debug)]
308#[cfg_attr(feature = "capture", derive(Serialize))]
309#[cfg_attr(feature = "replay", derive(Deserialize))]
310pub struct BlitTask {
311 pub source: RenderTaskId,
312 pub source_rect: DeviceIntRect,
314}
315
316#[derive(Debug)]
317#[cfg_attr(feature = "capture", derive(Serialize))]
318#[cfg_attr(feature = "replay", derive(Deserialize))]
319pub struct LineDecorationTask {
320 pub wavy_line_thickness: f32,
321 pub style: LineStyle,
322 pub orientation: LineOrientation,
323 pub local_size: LayoutSize,
324}
325
326#[derive(Debug)]
327#[cfg_attr(feature = "capture", derive(Serialize))]
328#[cfg_attr(feature = "replay", derive(Deserialize))]
329pub struct SVGFEFilterTask {
330 pub node: FilterGraphNode,
331 pub op: FilterGraphOp,
332 pub content_origin: DevicePoint,
333 pub extra_gpu_data: Option<GpuBufferAddress>,
334}
335
336#[cfg_attr(feature = "capture", derive(Serialize))]
337#[cfg_attr(feature = "replay", derive(Deserialize))]
338pub struct ReadbackTask {
339 pub readback_origin: Option<DevicePoint>,
344}
345
346#[derive(Debug)]
347#[cfg_attr(feature = "capture", derive(Serialize))]
348#[cfg_attr(feature = "replay", derive(Deserialize))]
349pub struct RenderTaskData {
350 pub data: [f32; FLOATS_PER_RENDER_TASK_INFO],
351}
352
353#[cfg_attr(feature = "capture", derive(Serialize))]
354#[cfg_attr(feature = "replay", derive(Deserialize))]
355pub enum RenderTaskKind {
356 Image(ImageRequestTask),
357 Cached(CachedTask),
358 Picture(PictureTask),
359 CacheMask(CacheMaskTask),
360 ClipRegion(ClipRegionTask),
361 VerticalBlur(BlurTask),
362 HorizontalBlur(BlurTask),
363 Readback(ReadbackTask),
364 Scaling(ScalingTask),
365 Blit(BlitTask),
366 Border(BorderTask),
367 LineDecoration(LineDecorationTask),
368 SVGFENode(SVGFEFilterTask),
369 TileComposite(TileCompositeTask),
370 Prim(PrimTask),
371 Empty(EmptyTask),
372 #[cfg(test)]
373 Test(RenderTargetKind),
374}
375
376impl RenderTaskKind {
377 pub fn is_a_rendering_operation(&self) -> bool {
378 match self {
379 &RenderTaskKind::Image(..) => false,
380 &RenderTaskKind::Cached(..) => false,
381 _ => true,
382 }
383 }
384
385 pub fn can_use_shared_surface(&self) -> bool {
387 match self {
388 &RenderTaskKind::Picture(ref info) => info.can_use_shared_surface,
389 _ => true,
390 }
391 }
392
393 pub fn should_advance_pass(&self) -> bool {
394 match self {
395 &RenderTaskKind::Image(..) => false,
396 &RenderTaskKind::Cached(..) => false,
397 _ => true,
398 }
399 }
400
401 pub fn as_str(&self) -> &'static str {
402 match *self {
403 RenderTaskKind::Image(..) => "Image",
404 RenderTaskKind::Cached(..) => "Cached",
405 RenderTaskKind::Picture(..) => "Picture",
406 RenderTaskKind::CacheMask(..) => "CacheMask",
407 RenderTaskKind::ClipRegion(..) => "ClipRegion",
408 RenderTaskKind::VerticalBlur(..) => "VerticalBlur",
409 RenderTaskKind::HorizontalBlur(..) => "HorizontalBlur",
410 RenderTaskKind::Readback(..) => "Readback",
411 RenderTaskKind::Scaling(..) => "Scaling",
412 RenderTaskKind::Blit(..) => "Blit",
413 RenderTaskKind::Border(..) => "Border",
414 RenderTaskKind::LineDecoration(..) => "LineDecoration",
415 RenderTaskKind::SVGFENode(..) => "SVGFENode",
416 RenderTaskKind::TileComposite(..) => "TileComposite",
417 RenderTaskKind::Prim(..) => "Prim",
418 RenderTaskKind::Empty(..) => "Empty",
419 #[cfg(test)]
420 RenderTaskKind::Test(..) => "Test",
421 }
422 }
423
424 pub fn target_kind(&self) -> RenderTargetKind {
425 match *self {
426 RenderTaskKind::Image(..) |
427 RenderTaskKind::LineDecoration(..) |
428 RenderTaskKind::Readback(..) |
429 RenderTaskKind::Border(..) |
430 RenderTaskKind::Picture(..) |
431 RenderTaskKind::Blit(..) |
432 RenderTaskKind::TileComposite(..) |
433 RenderTaskKind::Prim(..) => {
434 RenderTargetKind::Color
435 }
436 RenderTaskKind::SVGFENode(..) => {
437 RenderTargetKind::Color
438 }
439
440 RenderTaskKind::ClipRegion(..) |
441 RenderTaskKind::CacheMask(..) |
442 RenderTaskKind::Empty(..) => {
443 RenderTargetKind::Alpha
444 }
445
446 RenderTaskKind::VerticalBlur(ref task_info) |
447 RenderTaskKind::HorizontalBlur(ref task_info) => {
448 task_info.target_kind
449 }
450
451 RenderTaskKind::Scaling(ref task_info) => {
452 task_info.target_kind
453 }
454
455 RenderTaskKind::Cached(ref task_info) => {
456 task_info.target_kind
457 }
458
459 #[cfg(test)]
460 RenderTaskKind::Test(kind) => kind,
461 }
462 }
463
464 pub fn new_tile_composite(
465 sub_rect_offset: DeviceIntVector2D,
466 scissor_rect: DeviceIntRect,
467 valid_rect: DeviceIntRect,
468 clear_color: ColorF,
469 ) -> Self {
470 RenderTaskKind::TileComposite(TileCompositeTask {
471 task_id: None,
472 sub_rect_offset,
473 scissor_rect,
474 valid_rect,
475 clear_color,
476 })
477 }
478
479 pub fn new_picture(
480 size: DeviceIntSize,
481 needs_scissor_rect: bool,
482 content_origin: DevicePoint,
483 surface_spatial_node_index: SpatialNodeIndex,
484 raster_spatial_node_index: SpatialNodeIndex,
485 device_pixel_scale: DevicePixelScale,
486 scissor_rect: Option<DeviceIntRect>,
487 valid_rect: Option<DeviceIntRect>,
488 clear_color: Option<ColorF>,
489 cmd_buffer_index: CommandBufferIndex,
490 can_use_shared_surface: bool,
491 content_size: Option<DeviceIntSize>,
492 ) -> Self {
493 render_task_sanity_check(&size);
494
495 RenderTaskKind::Picture(PictureTask {
496 content_origin,
497 can_merge: !needs_scissor_rect,
498 surface_spatial_node_index,
499 raster_spatial_node_index,
500 device_pixel_scale,
501 scissor_rect,
502 valid_rect,
503 clear_color,
504 cmd_buffer_index,
505 resolve_op: None,
506 can_use_shared_surface,
507 content_size: content_size.unwrap_or(size),
508 })
509 }
510
511 pub fn new_prim(
512 pattern: PatternKind,
513 pattern_input: PatternShaderInput,
514 content_origin: DevicePoint,
515 prim_address_f: GpuBufferAddress,
516 transform_id: GpuTransformId,
517 edge_flags: EdgeMask,
518 quad_flags: QuadFlags,
519 prim_needs_scissor_rect: bool,
520 texture_input: RenderTaskId,
521 ) -> Self {
522 RenderTaskKind::Prim(PrimTask {
523 pattern,
524 pattern_input,
525 content_origin,
526 prim_address_f,
527 transform_id,
528 edge_flags,
529 quad_flags,
530 prim_needs_scissor_rect,
531 texture_input,
532 })
533 }
534
535 pub fn new_readback(
536 readback_origin: Option<DevicePoint>,
537 ) -> Self {
538 RenderTaskKind::Readback(
539 ReadbackTask {
540 readback_origin,
541 }
542 )
543 }
544
545 pub fn new_line_decoration(
546 style: LineStyle,
547 orientation: LineOrientation,
548 wavy_line_thickness: f32,
549 local_size: LayoutSize,
550 ) -> Self {
551 RenderTaskKind::LineDecoration(LineDecorationTask {
552 style,
553 orientation,
554 wavy_line_thickness,
555 local_size,
556 })
557 }
558
559 pub fn new_border_segment(
560 instances: Vec<BorderInstance>,
561 ) -> Self {
562 RenderTaskKind::Border(BorderTask {
563 instances,
564 })
565 }
566
567 pub fn new_rounded_rect_mask(
568 local_pos: LayoutPoint,
569 clip_data: ClipData,
570 device_pixel_scale: DevicePixelScale,
571 fb_config: &FrameBuilderConfig,
572 ) -> Self {
573 RenderTaskKind::ClipRegion(ClipRegionTask {
574 local_pos,
575 device_pixel_scale,
576 clip_data,
577 clear_to_one: fb_config.gpu_supports_fast_clears,
578 })
579 }
580
581 pub fn new_mask(
582 outer_rect: DeviceIntRect,
583 clip_node_range: ClipNodeRange,
584 root_spatial_node_index: SpatialNodeIndex,
585 rg_builder: &mut RenderTaskGraphBuilder,
586 device_pixel_scale: DevicePixelScale,
587 fb_config: &FrameBuilderConfig,
588 ) -> RenderTaskId {
589 let task_size = outer_rect.size();
590
591 rg_builder.add().init(
592 RenderTask::new_dynamic(
593 task_size,
594 RenderTaskKind::CacheMask(CacheMaskTask {
595 actual_rect: outer_rect.to_f32(),
596 clip_node_range,
597 root_spatial_node_index,
598 device_pixel_scale,
599 clear_to_one: fb_config.gpu_supports_fast_clears,
600 }),
601 )
602 )
603 }
604
605 pub fn write_task_data(
609 &self,
610 target_rect: DeviceIntRect,
611 ) -> RenderTaskData {
612 let data = match self {
621 RenderTaskKind::Picture(ref task) => {
622 [
624 task.device_pixel_scale.0,
625 task.content_origin.x,
626 task.content_origin.y,
627 0.0,
628 ]
629 }
630 RenderTaskKind::Prim(ref task) => {
631 [
632 DevicePixelScale::identity().0,
634 task.content_origin.x,
635 task.content_origin.y,
636 0.0,
637 ]
638 }
639 RenderTaskKind::Empty(ref task) => {
640 [
641 task.device_pixel_scale.0,
643 task.content_origin.x,
644 task.content_origin.y,
645 0.0,
646 ]
647 }
648 RenderTaskKind::CacheMask(ref task) => {
649 [
650 task.device_pixel_scale.0,
651 task.actual_rect.min.x,
652 task.actual_rect.min.y,
653 0.0,
654 ]
655 }
656 RenderTaskKind::ClipRegion(ref task) => {
657 [
658 task.device_pixel_scale.0,
659 0.0,
660 0.0,
661 0.0,
662 ]
663 }
664 RenderTaskKind::VerticalBlur(_) |
665 RenderTaskKind::HorizontalBlur(_) => {
666 [
669 0.0,
670 0.0,
671 0.0,
672 0.0,
673 ]
674 }
675 RenderTaskKind::Image(..) |
676 RenderTaskKind::Cached(..) |
677 RenderTaskKind::Readback(..) |
678 RenderTaskKind::Scaling(..) |
679 RenderTaskKind::Border(..) |
680 RenderTaskKind::LineDecoration(..) |
681 RenderTaskKind::TileComposite(..) |
682 RenderTaskKind::Blit(..) => {
683 [0.0; 4]
684 }
685
686 RenderTaskKind::SVGFENode(_task) => {
687 [0.0; 4]
690 }
691
692 #[cfg(test)]
693 RenderTaskKind::Test(..) => {
694 [0.0; 4]
695 }
696 };
697
698 RenderTaskData {
699 data: [
700 target_rect.min.x as f32,
701 target_rect.min.y as f32,
702 target_rect.max.x as f32,
703 target_rect.max.y as f32,
704 data[0],
705 data[1],
706 data[2],
707 data[3],
708 ]
709 }
710 }
711
712 pub fn write_gpu_blocks(
713 &mut self,
714 gpu_buffer: &mut GpuBufferBuilder,
715 ) {
716 match self {
717 RenderTaskKind::SVGFENode(ref mut filter_task) => {
718 match filter_task.op {
719 FilterGraphOp::SVGFEBlendDarken => {}
720 FilterGraphOp::SVGFEBlendLighten => {}
721 FilterGraphOp::SVGFEBlendMultiply => {}
722 FilterGraphOp::SVGFEBlendNormal => {}
723 FilterGraphOp::SVGFEBlendScreen => {}
724 FilterGraphOp::SVGFEBlendOverlay => {}
725 FilterGraphOp::SVGFEBlendColorDodge => {}
726 FilterGraphOp::SVGFEBlendColorBurn => {}
727 FilterGraphOp::SVGFEBlendHardLight => {}
728 FilterGraphOp::SVGFEBlendSoftLight => {}
729 FilterGraphOp::SVGFEBlendDifference => {}
730 FilterGraphOp::SVGFEBlendExclusion => {}
731 FilterGraphOp::SVGFEBlendHue => {}
732 FilterGraphOp::SVGFEBlendSaturation => {}
733 FilterGraphOp::SVGFEBlendColor => {}
734 FilterGraphOp::SVGFEBlendLuminosity => {}
735 FilterGraphOp::SVGFEColorMatrix { values: matrix } => {
736 let mut writer = gpu_buffer.f32.write_blocks(5);
737 for i in 0..5 {
738 writer.push_one([matrix[i*4], matrix[i*4+1], matrix[i*4+2], matrix[i*4+3]]);
739 }
740 filter_task.extra_gpu_data = Some(writer.finish());
741 }
742 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
743 FilterGraphOp::SVGFEComponentTransferInterned{..} => {}
744 FilterGraphOp::SVGFECompositeArithmetic{k1, k2, k3, k4} => {
745 let mut writer = gpu_buffer.f32.write_blocks(1);
746 writer.push_one([k1, k2, k3, k4]);
747 filter_task.extra_gpu_data = Some(writer.finish());
748 }
749 FilterGraphOp::SVGFECompositeATop => {}
750 FilterGraphOp::SVGFECompositeIn => {}
751 FilterGraphOp::SVGFECompositeLighter => {}
752 FilterGraphOp::SVGFECompositeOut => {}
753 FilterGraphOp::SVGFECompositeOver => {}
754 FilterGraphOp::SVGFECompositeXOR => {}
755 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} |
756 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} |
757 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} => {
758 let mut writer = gpu_buffer.f32.write_blocks(8);
759 assert!(SVGFE_CONVOLVE_VALUES_LIMIT == 25);
760 writer.push_one([-target_x as f32, -target_y as f32, order_x as f32, order_y as f32]);
761 writer.push_one([kernel_unit_length_x as f32, kernel_unit_length_y as f32, 1.0 / divisor, bias]);
762 writer.push_one([kernel[0], kernel[1], kernel[2], kernel[3]]);
763 writer.push_one([kernel[4], kernel[5], kernel[6], kernel[7]]);
764 writer.push_one([kernel[8], kernel[9], kernel[10], kernel[11]]);
765 writer.push_one([kernel[12], kernel[13], kernel[14], kernel[15]]);
766 writer.push_one([kernel[16], kernel[17], kernel[18], kernel[19]]);
767 writer.push_one([kernel[20], 0.0, 0.0, preserve_alpha as f32]);
768 filter_task.extra_gpu_data = Some(writer.finish());
769 }
770 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {}
771 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {}
772 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {}
773 FilterGraphOp::SVGFEDisplacementMap{scale, x_channel_selector, y_channel_selector} => {
774 let mut writer = gpu_buffer.f32.write_blocks(1);
775 writer.push_one([x_channel_selector as f32, y_channel_selector as f32, scale, 0.0]);
776 filter_task.extra_gpu_data = Some(writer.finish());
777 }
778 FilterGraphOp::SVGFEDropShadow { color, .. } |
779 FilterGraphOp::SVGFEFlood { color } => {
780 let mut writer = gpu_buffer.f32.write_blocks(1);
781 writer.push_one(color.to_array());
782 filter_task.extra_gpu_data = Some(writer.finish());
783 }
784 FilterGraphOp::SVGFEGaussianBlur{..} => {}
785 FilterGraphOp::SVGFEIdentity => {}
786 FilterGraphOp::SVGFEImage {..} => {}
787 FilterGraphOp::SVGFEMorphologyDilate { radius_x, radius_y } |
788 FilterGraphOp::SVGFEMorphologyErode { radius_x, radius_y } => {
789 let mut writer = gpu_buffer.f32.write_blocks(1);
790 writer.push_one([radius_x, radius_y, 0.0, 0.0]);
791 filter_task.extra_gpu_data = Some(writer.finish());
792 }
793 FilterGraphOp::SVGFEOpacity{..} => {}
794 FilterGraphOp::SVGFESourceAlpha => {}
795 FilterGraphOp::SVGFESourceGraphic => {}
796 FilterGraphOp::SVGFESpecularLightingDistant{..} => {}
797 FilterGraphOp::SVGFESpecularLightingPoint{..} => {}
798 FilterGraphOp::SVGFESpecularLightingSpot{..} => {}
799 FilterGraphOp::SVGFETile => {}
800 FilterGraphOp::SVGFEToAlpha{..} => {}
801 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} => {}
802 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} => {}
803 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} => {}
804 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {}
805 }
806 }
807 _ => {}
808 }
809 }
810}
811
812pub type BlurTaskCache = FastHashMap<BlurTaskKey, RenderTaskId>;
816
817#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
820pub enum BlurTaskKey {
821 DownScale(u32),
822 Blur { downscale_level: u32, stddev_x: u32, stddev_y: u32 },
823}
824
825impl BlurTaskKey {
826 fn downscale_and_blur(downscale_level: u32, blur_stddev: DeviceSize) -> Self {
827 const QUANTIZATION_FACTOR: f32 = 1024.0;
832 let stddev_x = (blur_stddev.width * QUANTIZATION_FACTOR) as u32;
833 let stddev_y = (blur_stddev.height * QUANTIZATION_FACTOR) as u32;
834 BlurTaskKey::Blur { downscale_level, stddev_x, stddev_y }
835 }
836}
837
838pub type TaskDependencies = SmallVec<[RenderTaskId;2]>;
843
844#[cfg_attr(feature = "capture", derive(Serialize))]
845#[cfg_attr(feature = "replay", derive(Deserialize))]
846pub struct RenderTask {
847 pub location: RenderTaskLocation,
848 pub children: TaskDependencies,
849 pub kind: RenderTaskKind,
850 pub sub_tasks: SubTaskRange,
851
852 pub free_after: PassId,
855 pub render_on: PassId,
856
857 pub uv_rect_handle: GpuBufferAddress,
862 pub cache_handle: Option<RenderTaskCacheEntryHandle>,
863 pub uv_rect_kind: UvRectKind,
864}
865
866impl RenderTask {
867 pub fn new(
868 location: RenderTaskLocation,
869 kind: RenderTaskKind,
870 ) -> Self {
871 render_task_sanity_check(&location.size());
872
873 RenderTask {
874 location,
875 children: TaskDependencies::new(),
876 kind,
877 free_after: PassId::MAX,
878 render_on: PassId::MIN,
879 uv_rect_handle: GpuBufferAddress::INVALID,
880 uv_rect_kind: UvRectKind::Rect,
881 cache_handle: None,
882 sub_tasks: SubTaskRange::empty(),
883 }
884 }
885
886 pub fn new_dynamic(
887 size: DeviceIntSize,
888 kind: RenderTaskKind,
889 ) -> Self {
890 assert!(!size.is_empty(), "Bad {} render task size: {:?}", kind.as_str(), size);
891 RenderTask::new(
892 RenderTaskLocation::Unallocated { size },
893 kind,
894 )
895 }
896
897 pub fn with_uv_rect_kind(mut self, uv_rect_kind: UvRectKind) -> Self {
898 self.uv_rect_kind = uv_rect_kind;
899 self
900 }
901
902 pub fn new_image(
903 size: DeviceIntSize,
904 request: ImageRequest,
905 is_composited: bool,
906 ) -> Self {
907 RenderTask {
916 location: RenderTaskLocation::CacheRequest { size, },
917 children: TaskDependencies::new(),
918 kind: RenderTaskKind::Image(ImageRequestTask {
919 request,
920 is_composited,
921 }),
922 free_after: PassId::MAX,
923 render_on: PassId::MIN,
924 uv_rect_handle: GpuBufferAddress::INVALID,
925 uv_rect_kind: UvRectKind::Rect,
926 cache_handle: None,
927 sub_tasks: SubTaskRange::empty(),
928 }
929 }
930
931
932 #[cfg(test)]
933 pub fn new_test(
934 location: RenderTaskLocation,
935 target: RenderTargetKind,
936 ) -> Self {
937 RenderTask {
938 location,
939 children: TaskDependencies::new(),
940 kind: RenderTaskKind::Test(target),
941 free_after: PassId::MAX,
942 render_on: PassId::MIN,
943 uv_rect_handle: GpuBufferAddress::INVALID,
944 uv_rect_kind: UvRectKind::Rect,
945 cache_handle: None,
946 sub_tasks: SubTaskRange::empty(),
947 }
948 }
949
950 pub fn new_blit(
951 size: DeviceIntSize,
952 source: RenderTaskId,
953 source_rect: DeviceIntRect,
954 rg_builder: &mut RenderTaskGraphBuilder,
955 ) -> RenderTaskId {
956 let blit_task_id = rg_builder.add().init(RenderTask::new_dynamic(
963 size,
964 RenderTaskKind::Blit(BlitTask { source, source_rect }),
965 ));
966
967 rg_builder.add_dependency(blit_task_id, source);
968
969 blit_task_id
970 }
971
972 pub fn new_blur(
991 blur_std_deviation: DeviceSize,
992 src_task_id: RenderTaskId,
993 rg_builder: &mut RenderTaskGraphBuilder,
994 target_kind: RenderTargetKind,
995 mut blur_cache: Option<&mut BlurTaskCache>,
996 blur_region: DeviceIntSize,
997 edge_mode: BlurEdgeMode,
998 ) -> RenderTaskId {
999 let mut adjusted_blur_std_deviation = blur_std_deviation;
1001 let (blur_target_size, uv_rect_kind) = {
1002 let src_task = rg_builder.get_task(src_task_id);
1003 (src_task.location.size(), src_task.uv_rect_kind())
1004 };
1005 let mut adjusted_blur_target_size = blur_target_size;
1006 let mut downscaling_src_task_id = src_task_id;
1007 let mut scale_factor = 1.0;
1008 let mut n_downscales = 1;
1009 while adjusted_blur_std_deviation.width > MAX_BLUR_STD_DEVIATION &&
1010 adjusted_blur_std_deviation.height > MAX_BLUR_STD_DEVIATION {
1011 if adjusted_blur_target_size.width < MIN_DOWNSCALING_RT_SIZE ||
1012 adjusted_blur_target_size.height < MIN_DOWNSCALING_RT_SIZE {
1013 break;
1014 }
1015 adjusted_blur_std_deviation = adjusted_blur_std_deviation * 0.5;
1016 scale_factor *= 2.0;
1017 adjusted_blur_target_size = (blur_target_size.to_f32() / scale_factor).to_i32();
1018
1019 let cached_task = match blur_cache {
1020 Some(ref mut cache) => cache.get(&BlurTaskKey::DownScale(n_downscales)).cloned(),
1021 None => None,
1022 };
1023
1024 downscaling_src_task_id = cached_task.unwrap_or_else(|| {
1025 RenderTask::new_scaling(
1026 downscaling_src_task_id,
1027 rg_builder,
1028 target_kind,
1029 adjusted_blur_target_size,
1030 )
1031 });
1032
1033 if let Some(ref mut cache) = blur_cache {
1034 cache.insert(BlurTaskKey::DownScale(n_downscales), downscaling_src_task_id);
1035 }
1036
1037 n_downscales += 1;
1038 }
1039
1040
1041 let blur_key = BlurTaskKey::downscale_and_blur(n_downscales, adjusted_blur_std_deviation);
1042
1043 let cached_task = match blur_cache {
1044 Some(ref mut cache) => cache.get(&blur_key).cloned(),
1045 None => None,
1046 };
1047
1048 let blur_region = blur_region / (scale_factor as i32);
1049
1050 let blur_task_id = cached_task.unwrap_or_else(|| {
1051 let blur_task_v = rg_builder.add().init(RenderTask::new_dynamic(
1052 adjusted_blur_target_size,
1053 RenderTaskKind::VerticalBlur(BlurTask {
1054 blur_std_deviation: adjusted_blur_std_deviation.height,
1055 target_kind,
1056 blur_region,
1057 edge_mode,
1058 }),
1059 ).with_uv_rect_kind(uv_rect_kind));
1060 rg_builder.add_dependency(blur_task_v, downscaling_src_task_id);
1061
1062 let task_id = rg_builder.add().init(RenderTask::new_dynamic(
1063 adjusted_blur_target_size,
1064 RenderTaskKind::HorizontalBlur(BlurTask {
1065 blur_std_deviation: adjusted_blur_std_deviation.width,
1066 target_kind,
1067 blur_region,
1068 edge_mode,
1069 }),
1070 ).with_uv_rect_kind(uv_rect_kind));
1071 rg_builder.add_dependency(task_id, blur_task_v);
1072
1073 task_id
1074 });
1075
1076 if let Some(ref mut cache) = blur_cache {
1077 cache.insert(blur_key, blur_task_id);
1078 }
1079
1080 blur_task_id
1081 }
1082
1083 pub fn new_scaling(
1084 src_task_id: RenderTaskId,
1085 rg_builder: &mut RenderTaskGraphBuilder,
1086 target_kind: RenderTargetKind,
1087 size: DeviceIntSize,
1088 ) -> RenderTaskId {
1089 Self::new_scaling_with_padding(
1090 src_task_id,
1091 rg_builder,
1092 target_kind,
1093 size,
1094 DeviceIntSideOffsets::zero(),
1095 )
1096 }
1097
1098 pub fn new_scaling_with_padding(
1099 source: RenderTaskId,
1100 rg_builder: &mut RenderTaskGraphBuilder,
1101 target_kind: RenderTargetKind,
1102 padded_size: DeviceIntSize,
1103 padding: DeviceIntSideOffsets,
1104 ) -> RenderTaskId {
1105 let uv_rect_kind = rg_builder.get_task(source).uv_rect_kind();
1106
1107 let task_id = rg_builder.add().init(
1108 RenderTask::new_dynamic(
1109 padded_size,
1110 RenderTaskKind::Scaling(ScalingTask {
1111 target_kind,
1112 padding,
1113 }),
1114 ).with_uv_rect_kind(uv_rect_kind)
1115 );
1116
1117 rg_builder.add_dependency(task_id, source);
1118
1119 task_id
1120 }
1121
1122 pub fn set_sub_tasks(
1123 &mut self,
1124 sub_tasks: SubTaskRange,
1125 ) {
1126 assert!(self.sub_tasks.is_empty());
1127 self.sub_tasks = sub_tasks;
1128 }
1129
1130 pub fn new_svg_filter_graph(
1138 filter_nodes: &[(FilterGraphNode, FilterGraphOp)],
1139 rg_builder: &mut RenderTaskGraphBuilder,
1140 gpu_buffer: &mut GpuBufferBuilderF,
1141 data_stores: &mut DataStores,
1142 _uv_rect_kind: UvRectKind,
1143 original_task_id: RenderTaskId,
1144 source_subregion: LayoutRect,
1145 target_subregion: LayoutRect,
1146 prim_subregion: LayoutRect,
1147 subregion_to_device_scale_x: f32,
1148 subregion_to_device_scale_y: f32,
1149 subregion_to_device_offset_x: f32,
1150 subregion_to_device_offset_y: f32,
1151 ) -> RenderTaskId {
1152 const BUFFER_LIMIT: usize = SVGFE_GRAPH_MAX;
1153 let mut task_by_buffer_id: [RenderTaskId; BUFFER_LIMIT] = [RenderTaskId::INVALID; BUFFER_LIMIT];
1154 let mut subregion_by_buffer_id: [LayoutRect; BUFFER_LIMIT] = [LayoutRect::zero(); BUFFER_LIMIT];
1155 let mut output_task_id = original_task_id;
1158
1159 fn uv_rect_kind_for_task_size(clipped: DeviceRect, unclipped: DeviceRect) -> UvRectKind {
1177 let scale_x = 1.0 / clipped.width();
1178 let scale_y = 1.0 / clipped.height();
1179 UvRectKind::Quad{
1180 top_left: DeviceHomogeneousVector::new(
1181 (unclipped.min.x - clipped.min.x) * scale_x,
1182 (unclipped.min.y - clipped.min.y) * scale_y,
1183 0.0, 1.0),
1184 top_right: DeviceHomogeneousVector::new(
1185 (unclipped.max.x - clipped.min.x) * scale_x,
1186 (unclipped.min.y - clipped.min.y) * scale_y,
1187 0.0, 1.0),
1188 bottom_left: DeviceHomogeneousVector::new(
1189 (unclipped.min.x - clipped.min.x) * scale_x,
1190 (unclipped.max.y - clipped.min.y) * scale_y,
1191 0.0, 1.0),
1192 bottom_right: DeviceHomogeneousVector::new(
1193 (unclipped.max.x - clipped.min.x) * scale_x,
1194 (unclipped.max.y - clipped.min.y) * scale_y,
1195 0.0, 1.0),
1196 }
1197 }
1198
1199 let mut made_dependency_on_source = false;
1201 for (filter_index, (filter_node, op)) in filter_nodes.iter().enumerate() {
1202 let node = &filter_node;
1203 let is_output = filter_index == filter_nodes.len() - 1;
1204
1205 if !node.kept_by_optimizer {
1207 continue;
1208 }
1209
1210 let op = match op {
1213 FilterGraphOp::SVGFEBlendColor => op.clone(),
1214 FilterGraphOp::SVGFEBlendColorBurn => op.clone(),
1215 FilterGraphOp::SVGFEBlendColorDodge => op.clone(),
1216 FilterGraphOp::SVGFEBlendDarken => op.clone(),
1217 FilterGraphOp::SVGFEBlendDifference => op.clone(),
1218 FilterGraphOp::SVGFEBlendExclusion => op.clone(),
1219 FilterGraphOp::SVGFEBlendHardLight => op.clone(),
1220 FilterGraphOp::SVGFEBlendHue => op.clone(),
1221 FilterGraphOp::SVGFEBlendLighten => op.clone(),
1222 FilterGraphOp::SVGFEBlendLuminosity => op.clone(),
1223 FilterGraphOp::SVGFEBlendMultiply => op.clone(),
1224 FilterGraphOp::SVGFEBlendNormal => op.clone(),
1225 FilterGraphOp::SVGFEBlendOverlay => op.clone(),
1226 FilterGraphOp::SVGFEBlendSaturation => op.clone(),
1227 FilterGraphOp::SVGFEBlendScreen => op.clone(),
1228 FilterGraphOp::SVGFEBlendSoftLight => op.clone(),
1229 FilterGraphOp::SVGFEColorMatrix{..} => op.clone(),
1230 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
1231 FilterGraphOp::SVGFEComponentTransferInterned{..} => op.clone(),
1232 FilterGraphOp::SVGFECompositeArithmetic{..} => op.clone(),
1233 FilterGraphOp::SVGFECompositeATop => op.clone(),
1234 FilterGraphOp::SVGFECompositeIn => op.clone(),
1235 FilterGraphOp::SVGFECompositeLighter => op.clone(),
1236 FilterGraphOp::SVGFECompositeOut => op.clone(),
1237 FilterGraphOp::SVGFECompositeOver => op.clone(),
1238 FilterGraphOp::SVGFECompositeXOR => op.clone(),
1239 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{
1240 kernel_unit_length_x, kernel_unit_length_y, order_x,
1241 order_y, kernel, divisor, bias, target_x, target_y,
1242 preserve_alpha} => {
1243 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{
1244 kernel_unit_length_x:
1245 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1246 kernel_unit_length_y:
1247 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1248 order_x: *order_x, order_y: *order_y, kernel: *kernel,
1249 divisor: *divisor, bias: *bias, target_x: *target_x,
1250 target_y: *target_y, preserve_alpha: *preserve_alpha}
1251 },
1252 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{
1253 kernel_unit_length_x, kernel_unit_length_y, order_x,
1254 order_y, kernel, divisor, bias, target_x, target_y,
1255 preserve_alpha} => {
1256 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{
1257 kernel_unit_length_x:
1258 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1259 kernel_unit_length_y:
1260 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1261 order_x: *order_x, order_y: *order_y, kernel: *kernel,
1262 divisor: *divisor, bias: *bias, target_x: *target_x,
1263 target_y: *target_y, preserve_alpha: *preserve_alpha}
1264 },
1265 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{
1266 kernel_unit_length_x, kernel_unit_length_y, order_x,
1267 order_y, kernel, divisor, bias, target_x, target_y,
1268 preserve_alpha} => {
1269 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{
1270 kernel_unit_length_x:
1271 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1272 kernel_unit_length_y:
1273 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1274 order_x: *order_x, order_y: *order_y, kernel: *kernel,
1275 divisor: *divisor, bias: *bias, target_x: *target_x,
1276 target_y: *target_y, preserve_alpha: *preserve_alpha}
1277 },
1278 FilterGraphOp::SVGFEDiffuseLightingDistant{
1279 surface_scale, diffuse_constant, kernel_unit_length_x,
1280 kernel_unit_length_y, azimuth, elevation} => {
1281 FilterGraphOp::SVGFEDiffuseLightingDistant{
1282 surface_scale: *surface_scale,
1283 diffuse_constant: *diffuse_constant,
1284 kernel_unit_length_x:
1285 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1286 kernel_unit_length_y:
1287 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1288 azimuth: *azimuth, elevation: *elevation}
1289 },
1290 FilterGraphOp::SVGFEDiffuseLightingPoint{
1291 surface_scale, diffuse_constant, kernel_unit_length_x,
1292 kernel_unit_length_y, x, y, z} => {
1293 FilterGraphOp::SVGFEDiffuseLightingPoint{
1294 surface_scale: *surface_scale,
1295 diffuse_constant: *diffuse_constant,
1296 kernel_unit_length_x:
1297 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1298 kernel_unit_length_y:
1299 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1300 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1301 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1302 z: *z}
1303 },
1304 FilterGraphOp::SVGFEDiffuseLightingSpot{
1305 surface_scale, diffuse_constant, kernel_unit_length_x,
1306 kernel_unit_length_y, x, y, z, points_at_x, points_at_y,
1307 points_at_z, cone_exponent, limiting_cone_angle} => {
1308 FilterGraphOp::SVGFEDiffuseLightingSpot{
1309 surface_scale: *surface_scale,
1310 diffuse_constant: *diffuse_constant,
1311 kernel_unit_length_x:
1312 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1313 kernel_unit_length_y:
1314 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1315 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1316 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1317 z: *z,
1318 points_at_x: points_at_x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1319 points_at_y: points_at_y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1320 points_at_z: *points_at_z,
1321 cone_exponent: *cone_exponent,
1322 limiting_cone_angle: *limiting_cone_angle}
1323 },
1324 FilterGraphOp::SVGFEFlood{..} => op.clone(),
1325 FilterGraphOp::SVGFEDisplacementMap{
1326 scale, x_channel_selector, y_channel_selector} => {
1327 FilterGraphOp::SVGFEDisplacementMap{
1328 scale: scale * subregion_to_device_scale_x,
1329 x_channel_selector: *x_channel_selector,
1330 y_channel_selector: *y_channel_selector}
1331 },
1332 FilterGraphOp::SVGFEDropShadow{
1333 color, dx, dy, std_deviation_x, std_deviation_y} => {
1334 FilterGraphOp::SVGFEDropShadow{
1335 color: *color,
1336 dx: dx * subregion_to_device_scale_x,
1337 dy: dy * subregion_to_device_scale_y,
1338 std_deviation_x: std_deviation_x * subregion_to_device_scale_x,
1339 std_deviation_y: std_deviation_y * subregion_to_device_scale_y}
1340 },
1341 FilterGraphOp::SVGFEGaussianBlur{std_deviation_x, std_deviation_y} => {
1342 let std_deviation_x = std_deviation_x * subregion_to_device_scale_x;
1343 let std_deviation_y = std_deviation_y * subregion_to_device_scale_y;
1344 if std_deviation_x + std_deviation_y >= 0.125 {
1347 FilterGraphOp::SVGFEGaussianBlur{
1348 std_deviation_x,
1349 std_deviation_y}
1350 } else {
1351 FilterGraphOp::SVGFEIdentity
1352 }
1353 },
1354 FilterGraphOp::SVGFEIdentity => op.clone(),
1355 FilterGraphOp::SVGFEImage{..} => op.clone(),
1356 FilterGraphOp::SVGFEMorphologyDilate{radius_x, radius_y} => {
1357 FilterGraphOp::SVGFEMorphologyDilate{
1358 radius_x: (radius_x * subregion_to_device_scale_x).round(),
1359 radius_y: (radius_y * subregion_to_device_scale_y).round()}
1360 },
1361 FilterGraphOp::SVGFEMorphologyErode{radius_x, radius_y} => {
1362 FilterGraphOp::SVGFEMorphologyErode{
1363 radius_x: (radius_x * subregion_to_device_scale_x).round(),
1364 radius_y: (radius_y * subregion_to_device_scale_y).round()}
1365 },
1366 FilterGraphOp::SVGFEOpacity{..} => op.clone(),
1367 FilterGraphOp::SVGFESourceAlpha => op.clone(),
1368 FilterGraphOp::SVGFESourceGraphic => op.clone(),
1369 FilterGraphOp::SVGFESpecularLightingDistant{
1370 surface_scale, specular_constant, specular_exponent,
1371 kernel_unit_length_x, kernel_unit_length_y, azimuth,
1372 elevation} => {
1373 FilterGraphOp::SVGFESpecularLightingDistant{
1374 surface_scale: *surface_scale,
1375 specular_constant: *specular_constant,
1376 specular_exponent: *specular_exponent,
1377 kernel_unit_length_x:
1378 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1379 kernel_unit_length_y:
1380 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1381 azimuth: *azimuth, elevation: *elevation}
1382 },
1383 FilterGraphOp::SVGFESpecularLightingPoint{
1384 surface_scale, specular_constant, specular_exponent,
1385 kernel_unit_length_x, kernel_unit_length_y, x, y, z } => {
1386 FilterGraphOp::SVGFESpecularLightingPoint{
1387 surface_scale: *surface_scale,
1388 specular_constant: *specular_constant,
1389 specular_exponent: *specular_exponent,
1390 kernel_unit_length_x:
1391 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1392 kernel_unit_length_y:
1393 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1394 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1395 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1396 z: *z }
1397 },
1398 FilterGraphOp::SVGFESpecularLightingSpot{
1399 surface_scale, specular_constant, specular_exponent,
1400 kernel_unit_length_x, kernel_unit_length_y, x, y, z,
1401 points_at_x, points_at_y, points_at_z, cone_exponent,
1402 limiting_cone_angle} => {
1403 FilterGraphOp::SVGFESpecularLightingSpot{
1404 surface_scale: *surface_scale,
1405 specular_constant: *specular_constant,
1406 specular_exponent: *specular_exponent,
1407 kernel_unit_length_x:
1408 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1409 kernel_unit_length_y:
1410 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1411 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1412 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1413 z: *z,
1414 points_at_x: points_at_x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1415 points_at_y: points_at_y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1416 points_at_z: *points_at_z,
1417 cone_exponent: *cone_exponent,
1418 limiting_cone_angle: *limiting_cone_angle}
1419 },
1420 FilterGraphOp::SVGFETile => op.clone(),
1421 FilterGraphOp::SVGFEToAlpha => op.clone(),
1422 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1423 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1424 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1425 base_frequency_x:
1426 base_frequency_x * subregion_to_device_scale_x,
1427 base_frequency_y:
1428 base_frequency_y * subregion_to_device_scale_y,
1429 num_octaves: *num_octaves, seed: *seed}
1430 },
1431 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{
1432 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1433 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1434 base_frequency_x:
1435 base_frequency_x * subregion_to_device_scale_x,
1436 base_frequency_y:
1437 base_frequency_y * subregion_to_device_scale_y,
1438 num_octaves: *num_octaves, seed: *seed}
1439 },
1440 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{
1441 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1442 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1443 base_frequency_x:
1444 base_frequency_x * subregion_to_device_scale_x,
1445 base_frequency_y:
1446 base_frequency_y * subregion_to_device_scale_y,
1447 num_octaves: *num_octaves, seed: *seed}
1448 },
1449 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{
1450 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1451 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1452 base_frequency_x:
1453 base_frequency_x * subregion_to_device_scale_x,
1454 base_frequency_y:
1455 base_frequency_y * subregion_to_device_scale_y,
1456 num_octaves: *num_octaves, seed: *seed}
1457 },
1458 };
1459
1460 let mut used_subregion = LayoutRect::zero();
1466 let mut combined_input_subregion = LayoutRect::zero();
1467 let node_inputs: Vec<(FilterGraphPictureReference, RenderTaskId)> = node.inputs.iter().map(|input| {
1468 let (subregion, task) =
1469 match input.buffer_id {
1470 FilterOpGraphPictureBufferId::BufferId(id) => {
1471 (subregion_by_buffer_id[id as usize], task_by_buffer_id[id as usize])
1472 }
1473 FilterOpGraphPictureBufferId::None => {
1474 (LayoutRect::zero(), original_task_id)
1478 }
1479 };
1480 let offset = LayoutVector2D::new(
1482 (input.offset.x * subregion_to_device_scale_x).round(),
1483 (input.offset.y * subregion_to_device_scale_y).round(),
1484 );
1485 let target_padding = input.target_padding
1490 .scale(subregion_to_device_scale_x, subregion_to_device_scale_y)
1491 .round();
1492 let target_subregion =
1493 LayoutRect::new(
1494 LayoutPoint::new(
1495 subregion.min.x + target_padding.min.x,
1496 subregion.min.y + target_padding.min.y,
1497 ),
1498 LayoutPoint::new(
1499 subregion.max.x + target_padding.max.x,
1500 subregion.max.y + target_padding.max.y,
1501 ),
1502 );
1503 used_subregion = used_subregion.union(&target_subregion);
1504 combined_input_subregion = combined_input_subregion.union(&subregion);
1505 (FilterGraphPictureReference{
1506 buffer_id: input.buffer_id,
1507 subregion: subregion.translate(offset),
1509 offset: LayoutVector2D::zero(),
1510 inflate: input.inflate,
1511 source_padding: LayoutRect::zero(),
1513 target_padding: LayoutRect::zero(),
1514 }, task)
1515 }).collect();
1516
1517 let full_subregion = node.subregion
1519 .scale(subregion_to_device_scale_x, subregion_to_device_scale_y)
1520 .translate(LayoutVector2D::new(subregion_to_device_offset_x, subregion_to_device_offset_y))
1521 .round();
1522
1523 used_subregion = used_subregion
1530 .intersection(&full_subregion)
1531 .unwrap_or(LayoutRect::zero())
1532 .round();
1533
1534 match op {
1536 FilterGraphOp::SVGFEBlendColor => {},
1537 FilterGraphOp::SVGFEBlendColorBurn => {},
1538 FilterGraphOp::SVGFEBlendColorDodge => {},
1539 FilterGraphOp::SVGFEBlendDarken => {},
1540 FilterGraphOp::SVGFEBlendDifference => {},
1541 FilterGraphOp::SVGFEBlendExclusion => {},
1542 FilterGraphOp::SVGFEBlendHardLight => {},
1543 FilterGraphOp::SVGFEBlendHue => {},
1544 FilterGraphOp::SVGFEBlendLighten => {},
1545 FilterGraphOp::SVGFEBlendLuminosity => {},
1546 FilterGraphOp::SVGFEBlendMultiply => {},
1547 FilterGraphOp::SVGFEBlendNormal => {},
1548 FilterGraphOp::SVGFEBlendOverlay => {},
1549 FilterGraphOp::SVGFEBlendSaturation => {},
1550 FilterGraphOp::SVGFEBlendScreen => {},
1551 FilterGraphOp::SVGFEBlendSoftLight => {},
1552 FilterGraphOp::SVGFEColorMatrix{values} => {
1553 if values[19] > 0.0 {
1554 used_subregion = full_subregion;
1557 }
1558 },
1559 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
1560 FilterGraphOp::SVGFEComponentTransferInterned{handle: _, creates_pixels} => {
1561 if creates_pixels {
1565 used_subregion = full_subregion;
1566 }
1567 },
1568 FilterGraphOp::SVGFECompositeArithmetic { k1, k2, k3, k4 } => {
1569 if k4 > 0.0 {
1576 used_subregion = full_subregion;
1578 } else if k1 > 0.0 && k2 == 0.0 && k3 == 0.0 {
1579 used_subregion = full_subregion
1581 .intersection(&node_inputs[0].0.subregion)
1582 .unwrap_or(LayoutRect::zero())
1583 .intersection(&node_inputs[1].0.subregion)
1584 .unwrap_or(LayoutRect::zero());
1585 }
1586 else if k2 > 0.0 && k3 == 0.0 {
1587 used_subregion = full_subregion
1589 .intersection(&node_inputs[0].0.subregion)
1590 .unwrap_or(LayoutRect::zero());
1591 }
1592 else if k2 == 0.0 && k3 > 0.0 {
1593 used_subregion = full_subregion
1595 .intersection(&node_inputs[1].0.subregion)
1596 .unwrap_or(LayoutRect::zero());
1597 }
1598 },
1599 FilterGraphOp::SVGFECompositeATop => {
1600 used_subregion = full_subregion
1602 .intersection(&node_inputs[1].0.subregion)
1603 .unwrap_or(LayoutRect::zero());
1604 },
1605 FilterGraphOp::SVGFECompositeIn => {
1606 used_subregion = used_subregion
1608 .intersection(&node_inputs[0].0.subregion)
1609 .unwrap_or(LayoutRect::zero())
1610 .intersection(&node_inputs[1].0.subregion)
1611 .unwrap_or(LayoutRect::zero());
1612 },
1613 FilterGraphOp::SVGFECompositeLighter => {},
1614 FilterGraphOp::SVGFECompositeOut => {
1615 used_subregion = full_subregion
1617 .intersection(&node_inputs[0].0.subregion)
1618 .unwrap_or(LayoutRect::zero());
1619 },
1620 FilterGraphOp::SVGFECompositeOver => {},
1621 FilterGraphOp::SVGFECompositeXOR => {},
1622 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{..} => {},
1623 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{..} => {},
1624 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{..} => {},
1625 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {},
1626 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {},
1627 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {},
1628 FilterGraphOp::SVGFEDisplacementMap{..} => {},
1629 FilterGraphOp::SVGFEDropShadow{..} => {},
1630 FilterGraphOp::SVGFEFlood { color } => {
1631 if color.a > 0.0 {
1636 used_subregion = full_subregion;
1637 }
1638 },
1639 FilterGraphOp::SVGFEIdentity => {},
1640 FilterGraphOp::SVGFEImage { sampling_filter: _sampling_filter, matrix: _matrix } => {
1641 used_subregion = full_subregion;
1643 },
1644 FilterGraphOp::SVGFEGaussianBlur{..} => {},
1645 FilterGraphOp::SVGFEMorphologyDilate{..} => {},
1646 FilterGraphOp::SVGFEMorphologyErode{..} => {},
1647 FilterGraphOp::SVGFEOpacity{valuebinding: _valuebinding, value} => {
1648 if value <= 0.0 {
1650 used_subregion = LayoutRect::zero();
1651 }
1652 },
1653 FilterGraphOp::SVGFESourceAlpha |
1654 FilterGraphOp::SVGFESourceGraphic => {
1655 used_subregion = source_subregion
1656 .intersection(&full_subregion)
1657 .unwrap_or(LayoutRect::zero());
1658 },
1659 FilterGraphOp::SVGFESpecularLightingDistant{..} => {},
1660 FilterGraphOp::SVGFESpecularLightingPoint{..} => {},
1661 FilterGraphOp::SVGFESpecularLightingSpot{..} => {},
1662 FilterGraphOp::SVGFETile => {
1663 if !used_subregion.is_empty() {
1664 used_subregion = full_subregion;
1667 }
1668 },
1669 FilterGraphOp::SVGFEToAlpha => {},
1670 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} |
1671 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} |
1672 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} |
1673 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {
1674 used_subregion = full_subregion;
1677 },
1678 }
1679
1680 add_text_marker(
1681 "SVGFEGraph",
1682 &format!("{}({})", op.kind(), filter_index),
1683 Duration::from_micros((used_subregion.width() * used_subregion.height() / 1000.0) as u64),
1684 );
1685
1686 let mut node_inflate = node.inflate;
1697 if is_output {
1698 used_subregion = target_subregion;
1700 node_inflate = 0;
1701 }
1702
1703 let mut device_to_render_scale = 1.0;
1709 let mut render_to_device_scale = 1.0;
1710 let mut subregion = used_subregion;
1711 let padded_subregion = match op {
1712 FilterGraphOp::SVGFEGaussianBlur{std_deviation_x, std_deviation_y} |
1713 FilterGraphOp::SVGFEDropShadow{std_deviation_x, std_deviation_y, ..} => {
1714 used_subregion
1715 .inflate(
1716 std_deviation_x.ceil() * BLUR_SAMPLE_SCALE,
1717 std_deviation_y.ceil() * BLUR_SAMPLE_SCALE)
1718 }
1719 _ => used_subregion,
1720 }.union(&combined_input_subregion);
1721 while
1722 padded_subregion.scale(device_to_render_scale, device_to_render_scale).round().width() + node_inflate as f32 * 2.0 > MAX_SURFACE_SIZE as f32 ||
1723 padded_subregion.scale(device_to_render_scale, device_to_render_scale).round().height() + node_inflate as f32 * 2.0 > MAX_SURFACE_SIZE as f32 {
1724 device_to_render_scale *= 0.5;
1725 render_to_device_scale *= 2.0;
1726 subregion = used_subregion
1730 .scale(device_to_render_scale, device_to_render_scale)
1731 .round()
1732 .scale(render_to_device_scale, render_to_device_scale);
1733 }
1734
1735 let node_task_rect: DeviceRect =
1740 subregion
1741 .scale(device_to_render_scale, device_to_render_scale)
1742 .round()
1743 .inflate(node_inflate as f32, node_inflate as f32)
1744 .cast_unit();
1745 let node_task_size = node_task_rect.to_i32().size();
1746 let node_task_size =
1747 if node_task_size.width < 1 || node_task_size.height < 1 {
1748 DeviceIntSize::new(1, 1)
1749 } else {
1750 node_task_size
1751 };
1752
1753 let node_uv_rect_kind = uv_rect_kind_for_task_size(
1756 subregion
1757 .scale(device_to_render_scale, device_to_render_scale)
1758 .round()
1759 .inflate(node_inflate as f32, node_inflate as f32)
1760 .cast_unit(),
1761 prim_subregion
1762 .scale(device_to_render_scale, device_to_render_scale)
1763 .round()
1764 .inflate(node_inflate as f32, node_inflate as f32)
1765 .cast_unit(),
1766 );
1767
1768 let task_id;
1770 match op {
1771 FilterGraphOp::SVGFEGaussianBlur { std_deviation_x, std_deviation_y } => {
1772 assert!(node_inputs.len() == 1);
1780 let blur_input = &node_inputs[0].0;
1781 let source_task_id = node_inputs[0].1;
1782
1783 let adjusted_blur_std_deviation = DeviceSize::new(
1787 std_deviation_x.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
1788 std_deviation_y.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
1789 );
1790 let blur_subregion = blur_input.subregion
1791 .scale(device_to_render_scale, device_to_render_scale)
1792 .inflate(
1793 adjusted_blur_std_deviation.width * BLUR_SAMPLE_SCALE,
1794 adjusted_blur_std_deviation.height * BLUR_SAMPLE_SCALE)
1795 .round_out();
1796 let blur_task_size = blur_subregion
1797 .size()
1798 .cast_unit()
1799 .max(DeviceSize::new(1.0, 1.0));
1800 let adjusted_blur_task_size =
1802 BlurTask::adjusted_blur_source_size(
1803 blur_task_size,
1804 adjusted_blur_std_deviation,
1805 ).max(DeviceSize::new(1.0, 1.0));
1806 let corner = LayoutPoint::new(
1809 blur_subregion.min.x.floor() + ((
1810 blur_task_size.width -
1811 adjusted_blur_task_size.width) * 0.5).floor(),
1812 blur_subregion.min.y.floor() + ((
1813 blur_task_size.height -
1814 adjusted_blur_task_size.height) * 0.5).floor(),
1815 );
1816 let blur_subregion =
1820 LayoutRect::new(
1821 corner,
1822 LayoutPoint::new(
1823 corner.x + adjusted_blur_task_size.width,
1824 corner.y + adjusted_blur_task_size.height,
1825 ),
1826 )
1827 .scale(render_to_device_scale, render_to_device_scale);
1828
1829 let input_subregion_task_id = rg_builder.add().init(RenderTask::new_dynamic(
1830 adjusted_blur_task_size.to_i32(),
1831 RenderTaskKind::SVGFENode(
1832 SVGFEFilterTask{
1833 node: FilterGraphNode{
1834 kept_by_optimizer: true,
1835 linear: false,
1836 inflate: 0,
1837 inputs: [blur_input.clone()].to_vec(),
1838 subregion: blur_subregion,
1839 },
1840 op: FilterGraphOp::SVGFEIdentity,
1841 content_origin: DevicePoint::zero(),
1842 extra_gpu_data: None,
1843 }
1844 ),
1845 ).with_uv_rect_kind(UvRectKind::Rect));
1846 rg_builder.add_dependency(input_subregion_task_id, source_task_id);
1848
1849 let blur_task_id =
1855 RenderTask::new_blur(
1856 adjusted_blur_std_deviation,
1857 input_subregion_task_id,
1858 rg_builder,
1859 RenderTargetKind::Color,
1860 None,
1861 adjusted_blur_task_size.to_i32(),
1862 BlurEdgeMode::Duplicate,
1863 );
1864
1865 task_id = rg_builder.add().init(RenderTask::new_dynamic(
1866 node_task_size,
1867 RenderTaskKind::SVGFENode(
1868 SVGFEFilterTask{
1869 node: FilterGraphNode{
1870 kept_by_optimizer: true,
1871 linear: node.linear,
1872 inflate: node_inflate,
1873 inputs: [
1874 FilterGraphPictureReference{
1875 buffer_id: blur_input.buffer_id,
1876 subregion: blur_subregion,
1877 inflate: 0,
1878 offset: LayoutVector2D::zero(),
1879 source_padding: LayoutRect::zero(),
1880 target_padding: LayoutRect::zero(),
1881 }].to_vec(),
1882 subregion,
1883 },
1884 op: FilterGraphOp::SVGFEIdentity,
1885 content_origin: node_task_rect.min,
1886 extra_gpu_data: None,
1887 }
1888 ),
1889 ).with_uv_rect_kind(node_uv_rect_kind));
1890 rg_builder.add_dependency(task_id, blur_task_id);
1892 }
1893 FilterGraphOp::SVGFEDropShadow { color, dx, dy, std_deviation_x, std_deviation_y } => {
1894 assert!(node_inputs.len() == 1);
1902 let blur_input = &node_inputs[0].0;
1903 let source_task_id = node_inputs[0].1;
1904
1905 let adjusted_blur_std_deviation = DeviceSize::new(
1909 std_deviation_x.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
1910 std_deviation_y.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
1911 );
1912 let blur_subregion = blur_input.subregion
1913 .scale(device_to_render_scale, device_to_render_scale)
1914 .inflate(
1915 adjusted_blur_std_deviation.width * BLUR_SAMPLE_SCALE,
1916 adjusted_blur_std_deviation.height * BLUR_SAMPLE_SCALE)
1917 .round_out();
1918 let blur_task_size = blur_subregion
1919 .size()
1920 .cast_unit()
1921 .max(DeviceSize::new(1.0, 1.0));
1922 let adjusted_blur_task_size =
1924 BlurTask::adjusted_blur_source_size(
1925 blur_task_size,
1926 adjusted_blur_std_deviation,
1927 ).max(DeviceSize::new(1.0, 1.0));
1928 let corner = LayoutPoint::new(
1931 blur_subregion.min.x.floor() + ((
1932 blur_task_size.width -
1933 adjusted_blur_task_size.width) * 0.5).floor(),
1934 blur_subregion.min.y.floor() + ((
1935 blur_task_size.height -
1936 adjusted_blur_task_size.height) * 0.5).floor(),
1937 );
1938 let blur_subregion =
1942 LayoutRect::new(
1943 corner,
1944 LayoutPoint::new(
1945 corner.x + adjusted_blur_task_size.width,
1946 corner.y + adjusted_blur_task_size.height,
1947 ),
1948 )
1949 .scale(render_to_device_scale, render_to_device_scale);
1950
1951 let input_subregion_task_id = rg_builder.add().init(RenderTask::new_dynamic(
1952 adjusted_blur_task_size.to_i32(),
1953 RenderTaskKind::SVGFENode(
1954 SVGFEFilterTask{
1955 node: FilterGraphNode{
1956 kept_by_optimizer: true,
1957 linear: false,
1958 inputs: [
1959 FilterGraphPictureReference{
1960 buffer_id: blur_input.buffer_id,
1961 subregion: blur_input.subregion,
1962 offset: LayoutVector2D::zero(),
1963 inflate: blur_input.inflate,
1964 source_padding: LayoutRect::zero(),
1965 target_padding: LayoutRect::zero(),
1966 }].to_vec(),
1967 subregion: blur_subregion,
1968 inflate: 0,
1969 },
1970 op: FilterGraphOp::SVGFEIdentity,
1971 content_origin: node_task_rect.min,
1972 extra_gpu_data: None,
1973 }
1974 ),
1975 ).with_uv_rect_kind(UvRectKind::Rect));
1976 rg_builder.add_dependency(input_subregion_task_id, source_task_id);
1978
1979 let blur_task_id =
1984 RenderTask::new_blur(
1985 adjusted_blur_std_deviation,
1986 input_subregion_task_id,
1987 rg_builder,
1988 RenderTargetKind::Color,
1989 None,
1990 adjusted_blur_task_size.to_i32(),
1991 BlurEdgeMode::Duplicate,
1992 );
1993
1994 let blur_subregion_translated = blur_subregion
1997 .translate(LayoutVector2D::new(dx, dy));
1998 task_id = rg_builder.add().init(RenderTask::new_dynamic(
1999 node_task_size,
2000 RenderTaskKind::SVGFENode(
2001 SVGFEFilterTask{
2002 node: FilterGraphNode{
2003 kept_by_optimizer: true,
2004 linear: node.linear,
2005 inflate: node_inflate,
2006 inputs: [
2007 *blur_input,
2009 FilterGraphPictureReference{
2011 buffer_id: blur_input.buffer_id,
2012 subregion: blur_subregion_translated,
2013 inflate: 0,
2014 offset: LayoutVector2D::zero(),
2015 source_padding: LayoutRect::zero(),
2016 target_padding: LayoutRect::zero(),
2017 }].to_vec(),
2018 subregion,
2019 },
2020 op: FilterGraphOp::SVGFEDropShadow{
2021 color,
2022 dx: 0.0, dy: 0.0,
2024 std_deviation_x: 0.0, std_deviation_y: 0.0,
2025 },
2026 content_origin: node_task_rect.min,
2027 extra_gpu_data: None,
2028 }
2029 ),
2030 ).with_uv_rect_kind(node_uv_rect_kind));
2031 rg_builder.add_dependency(task_id, source_task_id);
2033 rg_builder.add_dependency(task_id, blur_task_id);
2034 }
2035 FilterGraphOp::SVGFESourceAlpha |
2036 FilterGraphOp::SVGFESourceGraphic => {
2037 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2042 node_task_size,
2043 RenderTaskKind::SVGFENode(
2044 SVGFEFilterTask{
2045 node: FilterGraphNode{
2046 kept_by_optimizer: true,
2047 linear: node.linear,
2048 inflate: node_inflate,
2049 inputs: [
2050 FilterGraphPictureReference{
2051 buffer_id: FilterOpGraphPictureBufferId::None,
2052 subregion: source_subregion.cast_unit(),
2055 offset: LayoutVector2D::zero(),
2056 inflate: 0,
2057 source_padding: LayoutRect::zero(),
2058 target_padding: LayoutRect::zero(),
2059 }
2060 ].to_vec(),
2061 subregion: source_subregion.cast_unit(),
2062 },
2063 op: op.clone(),
2064 content_origin: source_subregion.min.cast_unit(),
2065 extra_gpu_data: None,
2066 }
2067 ),
2068 ).with_uv_rect_kind(node_uv_rect_kind));
2069 rg_builder.add_dependency(task_id, original_task_id);
2070 made_dependency_on_source = true;
2071 }
2072 FilterGraphOp::SVGFEComponentTransferInterned { handle, creates_pixels: _ } => {
2073 let filter_data = &mut data_stores.filter_data[handle];
2076 filter_data.write_gpu_blocks(gpu_buffer);
2077 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2080 node_task_size,
2081 RenderTaskKind::SVGFENode(
2082 SVGFEFilterTask {
2083 node: FilterGraphNode{
2084 kept_by_optimizer: true,
2085 linear: node.linear,
2086 inputs: node_inputs.iter().map(|input| {input.0}).collect(),
2087 subregion,
2088 inflate: node_inflate,
2089 },
2090 op: op.clone(),
2091 content_origin: node_task_rect.min,
2092 extra_gpu_data: Some(filter_data.gpu_buffer_address),
2093 }
2094 ),
2095 ).with_uv_rect_kind(node_uv_rect_kind));
2096
2097 for (_input, input_task) in &node_inputs {
2100 if *input_task == original_task_id {
2101 made_dependency_on_source = true;
2102 }
2103 if *input_task != RenderTaskId::INVALID {
2104 rg_builder.add_dependency(task_id, *input_task);
2105 }
2106 }
2107 }
2108 _ => {
2109 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2112 node_task_size,
2113 RenderTaskKind::SVGFENode(
2114 SVGFEFilterTask{
2115 node: FilterGraphNode{
2116 kept_by_optimizer: true,
2117 linear: node.linear,
2118 inputs: node_inputs.iter().map(|input| {input.0}).collect(),
2119 subregion,
2120 inflate: node_inflate,
2121 },
2122 op: op.clone(),
2123 content_origin: node_task_rect.min,
2124 extra_gpu_data: None,
2125 }
2126 ),
2127 ).with_uv_rect_kind(node_uv_rect_kind));
2128
2129 for (_input, input_task) in &node_inputs {
2132 if *input_task == original_task_id {
2133 made_dependency_on_source = true;
2134 }
2135 if *input_task != RenderTaskId::INVALID {
2136 rg_builder.add_dependency(task_id, *input_task);
2137 }
2138 }
2139 }
2140 }
2141
2142 task_by_buffer_id[filter_index] = task_id;
2146 subregion_by_buffer_id[filter_index] = subregion;
2147
2148 output_task_id = task_id;
2150 }
2151
2152 if !made_dependency_on_source && output_task_id != original_task_id {
2155 rg_builder.add_dependency(output_task_id, original_task_id);
2156 }
2157
2158 output_task_id
2159 }
2160
2161 pub fn uv_rect_kind(&self) -> UvRectKind {
2162 self.uv_rect_kind
2163 }
2164
2165 pub fn get_texture_address(&self) -> GpuBufferAddress {
2166 self.uv_rect_handle
2167 }
2168
2169 pub fn get_target_texture(&self) -> CacheTextureId {
2170 match self.location {
2171 RenderTaskLocation::Dynamic { texture_id, .. } => {
2172 assert_ne!(texture_id, CacheTextureId::INVALID);
2173 texture_id
2174 }
2175 RenderTaskLocation::Static { surface: StaticRenderTaskSurface::TextureCache { texture, .. }, .. } => {
2176 texture
2177 }
2178 _ => {
2179 unreachable!();
2180 }
2181 }
2182 }
2183
2184 pub fn get_texture_source(&self) -> TextureSource {
2185 match self.location {
2186 RenderTaskLocation::Dynamic { texture_id, .. } => {
2187 assert_ne!(texture_id, CacheTextureId::INVALID);
2188 TextureSource::TextureCache(texture_id, Swizzle::default())
2189 }
2190 RenderTaskLocation::Static { surface: StaticRenderTaskSurface::ReadOnly { source }, .. } => {
2191 source
2192 }
2193 RenderTaskLocation::Static { surface: StaticRenderTaskSurface::TextureCache { texture, .. }, .. } => {
2194 TextureSource::TextureCache(texture, Swizzle::default())
2195 }
2196 RenderTaskLocation::Existing { .. } |
2197 RenderTaskLocation::Static { .. } |
2198 RenderTaskLocation::CacheRequest { .. } |
2199 RenderTaskLocation::Unallocated { .. } => {
2200 unreachable!();
2201 }
2202 }
2203 }
2204
2205 pub fn get_target_rect(&self) -> DeviceIntRect {
2206 match self.location {
2207 RenderTaskLocation::Dynamic { rect, .. } => rect,
2222 RenderTaskLocation::Static { rect, .. } => rect,
2223 RenderTaskLocation::Existing { .. } |
2224 RenderTaskLocation::CacheRequest { .. } |
2225 RenderTaskLocation::Unallocated { .. } => {
2226 panic!("bug: get_target_rect called before allocating");
2227 }
2228 }
2229 }
2230
2231 pub fn get_target_size(&self) -> DeviceIntSize {
2232 match self.location {
2233 RenderTaskLocation::Dynamic { rect, .. } => rect.size(),
2234 RenderTaskLocation::Static { rect, .. } => rect.size(),
2235 RenderTaskLocation::Existing { size, .. } => size,
2236 RenderTaskLocation::CacheRequest { size } => size,
2237 RenderTaskLocation::Unallocated { size } => size,
2238 }
2239 }
2240
2241 pub fn target_kind(&self) -> RenderTargetKind {
2242 self.kind.target_kind()
2243 }
2244
2245 pub fn mark_cached(&mut self, handle: RenderTaskCacheEntryHandle) {
2250 self.cache_handle = Some(handle);
2251 }
2252}
2253
2254#[cfg_attr(feature = "capture", derive(Serialize))]
2256#[cfg_attr(feature = "replay", derive(Deserialize))]
2257pub enum SubTask {
2258 RectangleClip(RectangleClipSubTask),
2259 ImageClip(ImageClipSubTask),
2260}
2261
2262#[derive(Debug)]
2265#[cfg_attr(feature = "capture", derive(Serialize))]
2266#[cfg_attr(feature = "replay", derive(Deserialize))]
2267pub struct RectangleClipSubTask {
2268 pub quad_address: GpuBufferAddress,
2270 pub clip_address: GpuBufferAddress,
2272 pub clip_space: ClipSpace,
2284 pub quad_transform_id: GpuTransformId,
2286 pub clip_transform_id: GpuTransformId,
2288 pub quad_flags: QuadFlags,
2289 pub needs_scissor_rect: bool,
2290 pub rounded_rect_fast_path: bool,
2291}
2292
2293#[derive(Debug)]
2296#[cfg_attr(feature = "capture", derive(Serialize))]
2297#[cfg_attr(feature = "replay", derive(Deserialize))]
2298pub struct ImageClipSubTask {
2299 pub quad_address: GpuBufferAddress,
2301 pub quad_transform_id: GpuTransformId,
2304 pub src_task: RenderTaskId,
2305 pub quad_flags: QuadFlags,
2306 pub needs_scissor_rect: bool,
2307}