1use api::{CompositeOperator, FilterPrimitive, FilterPrimitiveInput, FilterPrimitiveKind, SVGFE_GRAPH_MAX};
6use api::{LineStyle, LineOrientation, ClipMode, MixBlendMode, ColorF, ColorSpace, FilterOpGraphPictureBufferId};
7use api::MAX_RENDER_TASK_SIZE;
8use api::units::*;
9use std::time::Duration;
10use crate::box_shadow::BLUR_SAMPLE_SCALE;
11use crate::clip::{ClipDataStore, ClipItemKind, ClipStore, 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::filterdata::SFilterData;
17use crate::frame_builder::FrameBuilderConfig;
18use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
19use crate::gpu_types::{BorderInstance, ImageSource, UvRectKind, TransformPaletteId, BlurEdgeMode};
20use crate::internal_types::{CacheTextureId, FastHashMap, FilterGraphNode, FilterGraphOp, FilterGraphPictureReference, SVGFE_CONVOLVE_VALUES_LIMIT, TextureSource, Swizzle};
21use crate::picture::{ResolvedSurfaceTexture, MAX_SURFACE_SIZE};
22use crate::prim_store::ClipData;
23use crate::prim_store::gradient::{
24 FastLinearGradientTask, RadialGradientTask,
25 ConicGradientTask, LinearGradientTask,
26};
27use crate::resource_cache::{ResourceCache, ImageRequest};
28use std::{usize, f32, i32, u32};
29use crate::renderer::{GpuBufferAddress, GpuBufferBuilderF};
30use crate::render_backend::DataStores;
31use crate::render_target::{ResolveOp, RenderTargetKind};
32use crate::render_task_graph::{PassId, RenderTaskId, RenderTaskGraphBuilder};
33use crate::render_task_cache::{RenderTaskCacheEntryHandle, RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskParent};
34use crate::segment::EdgeAaSegmentMask;
35use crate::surface::SurfaceBuilder;
36use smallvec::SmallVec;
37
38const FLOATS_PER_RENDER_TASK_INFO: usize = 8;
39pub const MAX_BLUR_STD_DEVIATION: f32 = 4.0;
40pub const MIN_DOWNSCALING_RT_SIZE: i32 = 8;
41
42fn render_task_sanity_check(size: &DeviceIntSize) {
43 if size.width > MAX_RENDER_TASK_SIZE ||
44 size.height > MAX_RENDER_TASK_SIZE {
45 error!("Attempting to create a render task of size {}x{}", size.width, size.height);
46 panic!();
47 }
48}
49
50#[derive(Debug, Copy, Clone, PartialEq)]
51#[repr(C)]
52#[cfg_attr(feature = "capture", derive(Serialize))]
53#[cfg_attr(feature = "replay", derive(Deserialize))]
54pub struct RenderTaskAddress(pub i32);
55
56impl Into<RenderTaskAddress> for RenderTaskId {
57 fn into(self) -> RenderTaskAddress {
58 RenderTaskAddress(self.index as i32)
59 }
60}
61
62#[derive(Clone, Debug, Eq, PartialEq, Hash)]
65#[cfg_attr(feature = "capture", derive(Serialize))]
66#[cfg_attr(feature = "replay", derive(Deserialize))]
67pub enum StaticRenderTaskSurface {
68 TextureCache {
71 texture: CacheTextureId,
73 target_kind: RenderTargetKind,
75 },
76 ReadOnly {
79 source: TextureSource,
80 },
81 PictureCache {
84 surface: ResolvedSurfaceTexture,
86 },
87}
88
89#[derive(Clone, Debug)]
91#[cfg_attr(feature = "capture", derive(Serialize))]
92#[cfg_attr(feature = "replay", derive(Deserialize))]
93pub enum RenderTaskLocation {
94 Unallocated {
99 size: DeviceIntSize,
101 },
102 CacheRequest {
104 size: DeviceIntSize,
105 },
106 Existing {
108 parent_task_id: RenderTaskId,
109 size: DeviceIntSize,
111 },
112
113 Dynamic {
119 texture_id: CacheTextureId,
121 rect: DeviceIntRect,
123 },
124 Static {
126 surface: StaticRenderTaskSurface,
128 rect: DeviceIntRect,
130 },
131}
132
133impl RenderTaskLocation {
134 pub fn is_dynamic(&self) -> bool {
136 match *self {
137 RenderTaskLocation::Dynamic { .. } => true,
138 _ => false,
139 }
140 }
141
142 pub fn size(&self) -> DeviceIntSize {
143 match self {
144 RenderTaskLocation::Unallocated { size } => *size,
145 RenderTaskLocation::Dynamic { rect, .. } => rect.size(),
146 RenderTaskLocation::Static { rect, .. } => rect.size(),
147 RenderTaskLocation::CacheRequest { size } => *size,
148 RenderTaskLocation::Existing { size, .. } => *size,
149 }
150 }
151}
152
153#[derive(Debug)]
154#[cfg_attr(feature = "capture", derive(Serialize))]
155#[cfg_attr(feature = "replay", derive(Deserialize))]
156pub struct CachedTask {
157 pub target_kind: RenderTargetKind,
158}
159
160#[derive(Debug)]
161#[cfg_attr(feature = "capture", derive(Serialize))]
162#[cfg_attr(feature = "replay", derive(Deserialize))]
163pub struct ImageRequestTask {
164 pub request: ImageRequest,
165 pub is_composited: bool,
166}
167
168#[derive(Debug)]
169#[cfg_attr(feature = "capture", derive(Serialize))]
170#[cfg_attr(feature = "replay", derive(Deserialize))]
171pub struct CacheMaskTask {
172 pub actual_rect: DeviceRect,
173 pub root_spatial_node_index: SpatialNodeIndex,
174 pub clip_node_range: ClipNodeRange,
175 pub device_pixel_scale: DevicePixelScale,
176 pub clear_to_one: bool,
177}
178
179#[derive(Debug)]
180#[cfg_attr(feature = "capture", derive(Serialize))]
181#[cfg_attr(feature = "replay", derive(Deserialize))]
182pub struct ClipRegionTask {
183 pub local_pos: LayoutPoint,
184 pub device_pixel_scale: DevicePixelScale,
185 pub clip_data: ClipData,
186 pub clear_to_one: bool,
187}
188
189#[cfg_attr(feature = "capture", derive(Serialize))]
190#[cfg_attr(feature = "replay", derive(Deserialize))]
191pub struct EmptyTask {
192 pub content_origin: DevicePoint,
193 pub device_pixel_scale: DevicePixelScale,
194 pub raster_spatial_node_index: SpatialNodeIndex,
195}
196
197#[cfg_attr(feature = "capture", derive(Serialize))]
198#[cfg_attr(feature = "replay", derive(Deserialize))]
199pub struct PrimTask {
200 pub pattern: PatternKind,
201 pub pattern_input: PatternShaderInput,
202 pub device_pixel_scale: DevicePixelScale,
203 pub content_origin: DevicePoint,
204 pub prim_address_f: GpuBufferAddress,
205 pub raster_spatial_node_index: SpatialNodeIndex,
206 pub transform_id: TransformPaletteId,
207 pub edge_flags: EdgeAaSegmentMask,
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 enum SvgFilterInfo {
330 Blend(MixBlendMode),
331 Flood(ColorF),
332 LinearToSrgb,
333 SrgbToLinear,
334 Opacity(f32),
335 ColorMatrix(Box<[f32; 20]>),
336 DropShadow(ColorF),
337 Offset(DeviceVector2D),
338 ComponentTransfer(SFilterData),
339 Composite(CompositeOperator),
340 Identity,
342}
343
344#[derive(Debug)]
345#[cfg_attr(feature = "capture", derive(Serialize))]
346#[cfg_attr(feature = "replay", derive(Deserialize))]
347pub struct SvgFilterTask {
348 pub info: SvgFilterInfo,
349 pub extra_gpu_cache_handle: Option<GpuCacheHandle>,
350}
351
352#[derive(Debug)]
353#[cfg_attr(feature = "capture", derive(Serialize))]
354#[cfg_attr(feature = "replay", derive(Deserialize))]
355pub struct SVGFEFilterTask {
356 pub node: FilterGraphNode,
357 pub op: FilterGraphOp,
358 pub content_origin: DevicePoint,
359 pub extra_gpu_cache_handle: Option<GpuCacheHandle>,
360}
361
362#[cfg_attr(feature = "capture", derive(Serialize))]
363#[cfg_attr(feature = "replay", derive(Deserialize))]
364pub struct ReadbackTask {
365 pub readback_origin: Option<DevicePoint>,
370}
371
372#[derive(Debug)]
373#[cfg_attr(feature = "capture", derive(Serialize))]
374#[cfg_attr(feature = "replay", derive(Deserialize))]
375pub struct RenderTaskData {
376 pub data: [f32; FLOATS_PER_RENDER_TASK_INFO],
377}
378
379#[cfg_attr(feature = "capture", derive(Serialize))]
380#[cfg_attr(feature = "replay", derive(Deserialize))]
381pub enum RenderTaskKind {
382 Image(ImageRequestTask),
383 Cached(CachedTask),
384 Picture(PictureTask),
385 CacheMask(CacheMaskTask),
386 ClipRegion(ClipRegionTask),
387 VerticalBlur(BlurTask),
388 HorizontalBlur(BlurTask),
389 Readback(ReadbackTask),
390 Scaling(ScalingTask),
391 Blit(BlitTask),
392 Border(BorderTask),
393 LineDecoration(LineDecorationTask),
394 FastLinearGradient(FastLinearGradientTask),
395 LinearGradient(LinearGradientTask),
396 RadialGradient(RadialGradientTask),
397 ConicGradient(ConicGradientTask),
398 SvgFilter(SvgFilterTask),
399 SVGFENode(SVGFEFilterTask),
400 TileComposite(TileCompositeTask),
401 Prim(PrimTask),
402 Empty(EmptyTask),
403 #[cfg(test)]
404 Test(RenderTargetKind),
405}
406
407impl RenderTaskKind {
408 pub fn is_a_rendering_operation(&self) -> bool {
409 match self {
410 &RenderTaskKind::Image(..) => false,
411 &RenderTaskKind::Cached(..) => false,
412 _ => true,
413 }
414 }
415
416 pub fn can_use_shared_surface(&self) -> bool {
418 match self {
419 &RenderTaskKind::Picture(ref info) => info.can_use_shared_surface,
420 _ => true,
421 }
422 }
423
424 pub fn should_advance_pass(&self) -> bool {
425 match self {
426 &RenderTaskKind::Image(..) => false,
427 &RenderTaskKind::Cached(..) => false,
428 _ => true,
429 }
430 }
431
432 pub fn as_str(&self) -> &'static str {
433 match *self {
434 RenderTaskKind::Image(..) => "Image",
435 RenderTaskKind::Cached(..) => "Cached",
436 RenderTaskKind::Picture(..) => "Picture",
437 RenderTaskKind::CacheMask(..) => "CacheMask",
438 RenderTaskKind::ClipRegion(..) => "ClipRegion",
439 RenderTaskKind::VerticalBlur(..) => "VerticalBlur",
440 RenderTaskKind::HorizontalBlur(..) => "HorizontalBlur",
441 RenderTaskKind::Readback(..) => "Readback",
442 RenderTaskKind::Scaling(..) => "Scaling",
443 RenderTaskKind::Blit(..) => "Blit",
444 RenderTaskKind::Border(..) => "Border",
445 RenderTaskKind::LineDecoration(..) => "LineDecoration",
446 RenderTaskKind::FastLinearGradient(..) => "FastLinearGradient",
447 RenderTaskKind::LinearGradient(..) => "LinearGradient",
448 RenderTaskKind::RadialGradient(..) => "RadialGradient",
449 RenderTaskKind::ConicGradient(..) => "ConicGradient",
450 RenderTaskKind::SvgFilter(..) => "SvgFilter",
451 RenderTaskKind::SVGFENode(..) => "SVGFENode",
452 RenderTaskKind::TileComposite(..) => "TileComposite",
453 RenderTaskKind::Prim(..) => "Prim",
454 RenderTaskKind::Empty(..) => "Empty",
455 #[cfg(test)]
456 RenderTaskKind::Test(..) => "Test",
457 }
458 }
459
460 pub fn target_kind(&self) -> RenderTargetKind {
461 match *self {
462 RenderTaskKind::Image(..) |
463 RenderTaskKind::LineDecoration(..) |
464 RenderTaskKind::Readback(..) |
465 RenderTaskKind::Border(..) |
466 RenderTaskKind::FastLinearGradient(..) |
467 RenderTaskKind::LinearGradient(..) |
468 RenderTaskKind::RadialGradient(..) |
469 RenderTaskKind::ConicGradient(..) |
470 RenderTaskKind::Picture(..) |
471 RenderTaskKind::Blit(..) |
472 RenderTaskKind::TileComposite(..) |
473 RenderTaskKind::Prim(..) |
474 RenderTaskKind::SvgFilter(..) => {
475 RenderTargetKind::Color
476 }
477 RenderTaskKind::SVGFENode(..) => {
478 RenderTargetKind::Color
479 }
480
481 RenderTaskKind::ClipRegion(..) |
482 RenderTaskKind::CacheMask(..) |
483 RenderTaskKind::Empty(..) => {
484 RenderTargetKind::Alpha
485 }
486
487 RenderTaskKind::VerticalBlur(ref task_info) |
488 RenderTaskKind::HorizontalBlur(ref task_info) => {
489 task_info.target_kind
490 }
491
492 RenderTaskKind::Scaling(ref task_info) => {
493 task_info.target_kind
494 }
495
496 RenderTaskKind::Cached(ref task_info) => {
497 task_info.target_kind
498 }
499
500 #[cfg(test)]
501 RenderTaskKind::Test(kind) => kind,
502 }
503 }
504
505 pub fn new_tile_composite(
506 sub_rect_offset: DeviceIntVector2D,
507 scissor_rect: DeviceIntRect,
508 valid_rect: DeviceIntRect,
509 clear_color: ColorF,
510 ) -> Self {
511 RenderTaskKind::TileComposite(TileCompositeTask {
512 task_id: None,
513 sub_rect_offset,
514 scissor_rect,
515 valid_rect,
516 clear_color,
517 })
518 }
519
520 pub fn new_picture(
521 size: DeviceIntSize,
522 needs_scissor_rect: bool,
523 content_origin: DevicePoint,
524 surface_spatial_node_index: SpatialNodeIndex,
525 raster_spatial_node_index: SpatialNodeIndex,
526 device_pixel_scale: DevicePixelScale,
527 scissor_rect: Option<DeviceIntRect>,
528 valid_rect: Option<DeviceIntRect>,
529 clear_color: Option<ColorF>,
530 cmd_buffer_index: CommandBufferIndex,
531 can_use_shared_surface: bool,
532 content_size: Option<DeviceIntSize>,
533 ) -> Self {
534 render_task_sanity_check(&size);
535
536 RenderTaskKind::Picture(PictureTask {
537 content_origin,
538 can_merge: !needs_scissor_rect,
539 surface_spatial_node_index,
540 raster_spatial_node_index,
541 device_pixel_scale,
542 scissor_rect,
543 valid_rect,
544 clear_color,
545 cmd_buffer_index,
546 resolve_op: None,
547 can_use_shared_surface,
548 content_size: content_size.unwrap_or(size),
549 })
550 }
551
552 pub fn new_prim(
553 pattern: PatternKind,
554 pattern_input: PatternShaderInput,
555 raster_spatial_node_index: SpatialNodeIndex,
556 device_pixel_scale: DevicePixelScale,
557 content_origin: DevicePoint,
558 prim_address_f: GpuBufferAddress,
559 transform_id: TransformPaletteId,
560 edge_flags: EdgeAaSegmentMask,
561 quad_flags: QuadFlags,
562 prim_needs_scissor_rect: bool,
563 texture_input: RenderTaskId,
564 ) -> Self {
565 RenderTaskKind::Prim(PrimTask {
566 pattern,
567 pattern_input,
568 raster_spatial_node_index,
569 device_pixel_scale,
570 content_origin,
571 prim_address_f,
572 transform_id,
573 edge_flags,
574 quad_flags,
575 prim_needs_scissor_rect,
576 texture_input,
577 })
578 }
579
580 pub fn new_readback(
581 readback_origin: Option<DevicePoint>,
582 ) -> Self {
583 RenderTaskKind::Readback(
584 ReadbackTask {
585 readback_origin,
586 }
587 )
588 }
589
590 pub fn new_line_decoration(
591 style: LineStyle,
592 orientation: LineOrientation,
593 wavy_line_thickness: f32,
594 local_size: LayoutSize,
595 ) -> Self {
596 RenderTaskKind::LineDecoration(LineDecorationTask {
597 style,
598 orientation,
599 wavy_line_thickness,
600 local_size,
601 })
602 }
603
604 pub fn new_border_segment(
605 instances: Vec<BorderInstance>,
606 ) -> Self {
607 RenderTaskKind::Border(BorderTask {
608 instances,
609 })
610 }
611
612 pub fn new_rounded_rect_mask(
613 local_pos: LayoutPoint,
614 clip_data: ClipData,
615 device_pixel_scale: DevicePixelScale,
616 fb_config: &FrameBuilderConfig,
617 ) -> Self {
618 RenderTaskKind::ClipRegion(ClipRegionTask {
619 local_pos,
620 device_pixel_scale,
621 clip_data,
622 clear_to_one: fb_config.gpu_supports_fast_clears,
623 })
624 }
625
626 pub fn new_mask(
627 outer_rect: DeviceIntRect,
628 clip_node_range: ClipNodeRange,
629 root_spatial_node_index: SpatialNodeIndex,
630 clip_store: &mut ClipStore,
631 gpu_cache: &mut GpuCache,
632 gpu_buffer_builder: &mut GpuBufferBuilderF,
633 resource_cache: &mut ResourceCache,
634 rg_builder: &mut RenderTaskGraphBuilder,
635 clip_data_store: &mut ClipDataStore,
636 device_pixel_scale: DevicePixelScale,
637 fb_config: &FrameBuilderConfig,
638 surface_builder: &mut SurfaceBuilder,
639 ) -> RenderTaskId {
640 let task_size = outer_rect.size();
650
651 let clip_task_id = rg_builder.add().init(
656 RenderTask::new_dynamic(
657 task_size,
658 RenderTaskKind::CacheMask(CacheMaskTask {
659 actual_rect: outer_rect.to_f32(),
660 clip_node_range,
661 root_spatial_node_index,
662 device_pixel_scale,
663 clear_to_one: fb_config.gpu_supports_fast_clears,
664 }),
665 )
666 );
667
668 for i in 0 .. clip_node_range.count {
669 let clip_instance = clip_store.get_instance_from_range(&clip_node_range, i);
670 let clip_node = &mut clip_data_store[clip_instance.handle];
671 match clip_node.item.kind {
672 ClipItemKind::BoxShadow { ref mut source } => {
673 let (cache_size, cache_key) = source.cache_key
674 .as_ref()
675 .expect("bug: no cache key set")
676 .clone();
677 let blur_radius_dp = cache_key.blur_radius_dp as f32;
678 let device_pixel_scale = DevicePixelScale::new(cache_key.device_pixel_scale.to_f32_px());
679
680 source.render_task = Some(resource_cache.request_render_task(
683 Some(RenderTaskCacheKey {
684 size: cache_size,
685 kind: RenderTaskCacheKeyKind::BoxShadow(cache_key),
686 }),
687 false,
688 RenderTaskParent::RenderTask(clip_task_id),
689 gpu_cache,
690 gpu_buffer_builder,
691 rg_builder,
692 surface_builder,
693 &mut |rg_builder, _, _| {
694 let clip_data = ClipData::rounded_rect(
695 source.minimal_shadow_rect.size(),
696 &source.shadow_radius,
697 ClipMode::Clip,
698 );
699
700 let mask_task_id = rg_builder.add().init(RenderTask::new_dynamic(
702 cache_size,
703 RenderTaskKind::new_rounded_rect_mask(
704 source.minimal_shadow_rect.min,
705 clip_data,
706 device_pixel_scale,
707 fb_config,
708 ),
709 ));
710
711 RenderTask::new_blur(
713 DeviceSize::new(blur_radius_dp, blur_radius_dp),
714 mask_task_id,
715 rg_builder,
716 RenderTargetKind::Alpha,
717 None,
718 cache_size,
719 BlurEdgeMode::Duplicate,
720 )
721 }
722 ));
723 }
724 ClipItemKind::Rectangle { .. } |
725 ClipItemKind::RoundedRectangle { .. } |
726 ClipItemKind::Image { .. } => {}
727 }
728 }
729
730 clip_task_id
731 }
732
733 pub fn write_task_data(
737 &self,
738 target_rect: DeviceIntRect,
739 ) -> RenderTaskData {
740 let data = match self {
749 RenderTaskKind::Picture(ref task) => {
750 [
752 task.device_pixel_scale.0,
753 task.content_origin.x,
754 task.content_origin.y,
755 0.0,
756 ]
757 }
758 RenderTaskKind::Prim(ref task) => {
759 [
760 task.device_pixel_scale.0,
762 task.content_origin.x,
763 task.content_origin.y,
764 0.0,
765 ]
766 }
767 RenderTaskKind::Empty(ref task) => {
768 [
769 task.device_pixel_scale.0,
771 task.content_origin.x,
772 task.content_origin.y,
773 0.0,
774 ]
775 }
776 RenderTaskKind::CacheMask(ref task) => {
777 [
778 task.device_pixel_scale.0,
779 task.actual_rect.min.x,
780 task.actual_rect.min.y,
781 0.0,
782 ]
783 }
784 RenderTaskKind::ClipRegion(ref task) => {
785 [
786 task.device_pixel_scale.0,
787 0.0,
788 0.0,
789 0.0,
790 ]
791 }
792 RenderTaskKind::VerticalBlur(_) |
793 RenderTaskKind::HorizontalBlur(_) => {
794 [
797 0.0,
798 0.0,
799 0.0,
800 0.0,
801 ]
802 }
803 RenderTaskKind::Image(..) |
804 RenderTaskKind::Cached(..) |
805 RenderTaskKind::Readback(..) |
806 RenderTaskKind::Scaling(..) |
807 RenderTaskKind::Border(..) |
808 RenderTaskKind::LineDecoration(..) |
809 RenderTaskKind::FastLinearGradient(..) |
810 RenderTaskKind::LinearGradient(..) |
811 RenderTaskKind::RadialGradient(..) |
812 RenderTaskKind::ConicGradient(..) |
813 RenderTaskKind::TileComposite(..) |
814 RenderTaskKind::Blit(..) => {
815 [0.0; 4]
816 }
817
818 RenderTaskKind::SvgFilter(ref task) => {
819 match task.info {
820 SvgFilterInfo::Opacity(opacity) => [opacity, 0.0, 0.0, 0.0],
821 SvgFilterInfo::Offset(offset) => [offset.x, offset.y, 0.0, 0.0],
822 _ => [0.0; 4]
823 }
824 }
825 RenderTaskKind::SVGFENode(_task) => {
826 [0.0; 4]
829 }
830
831 #[cfg(test)]
832 RenderTaskKind::Test(..) => {
833 [0.0; 4]
834 }
835 };
836
837 RenderTaskData {
838 data: [
839 target_rect.min.x as f32,
840 target_rect.min.y as f32,
841 target_rect.max.x as f32,
842 target_rect.max.y as f32,
843 data[0],
844 data[1],
845 data[2],
846 data[3],
847 ]
848 }
849 }
850
851 pub fn write_gpu_blocks(
852 &mut self,
853 gpu_cache: &mut GpuCache,
854 ) {
855 match self {
856 RenderTaskKind::SvgFilter(ref mut filter_task) => {
857 match filter_task.info {
858 SvgFilterInfo::ColorMatrix(ref matrix) => {
859 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
860 if let Some(mut request) = gpu_cache.request(handle) {
861 for i in 0..5 {
862 request.push([matrix[i*4], matrix[i*4+1], matrix[i*4+2], matrix[i*4+3]]);
863 }
864 }
865 }
866 SvgFilterInfo::DropShadow(color) |
867 SvgFilterInfo::Flood(color) => {
868 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
869 if let Some(mut request) = gpu_cache.request(handle) {
870 request.push(color.to_array());
871 }
872 }
873 SvgFilterInfo::ComponentTransfer(ref data) => {
874 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
875 if let Some(request) = gpu_cache.request(handle) {
876 data.update(request);
877 }
878 }
879 SvgFilterInfo::Composite(ref operator) => {
880 if let CompositeOperator::Arithmetic(k_vals) = operator {
881 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
882 if let Some(mut request) = gpu_cache.request(handle) {
883 request.push(*k_vals);
884 }
885 }
886 }
887 _ => {},
888 }
889 }
890 RenderTaskKind::SVGFENode(ref mut filter_task) => {
891 match filter_task.op {
892 FilterGraphOp::SVGFEBlendDarken => {}
893 FilterGraphOp::SVGFEBlendLighten => {}
894 FilterGraphOp::SVGFEBlendMultiply => {}
895 FilterGraphOp::SVGFEBlendNormal => {}
896 FilterGraphOp::SVGFEBlendScreen => {}
897 FilterGraphOp::SVGFEBlendOverlay => {}
898 FilterGraphOp::SVGFEBlendColorDodge => {}
899 FilterGraphOp::SVGFEBlendColorBurn => {}
900 FilterGraphOp::SVGFEBlendHardLight => {}
901 FilterGraphOp::SVGFEBlendSoftLight => {}
902 FilterGraphOp::SVGFEBlendDifference => {}
903 FilterGraphOp::SVGFEBlendExclusion => {}
904 FilterGraphOp::SVGFEBlendHue => {}
905 FilterGraphOp::SVGFEBlendSaturation => {}
906 FilterGraphOp::SVGFEBlendColor => {}
907 FilterGraphOp::SVGFEBlendLuminosity => {}
908 FilterGraphOp::SVGFEColorMatrix{values: matrix} => {
909 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
910 if let Some(mut request) = gpu_cache.request(handle) {
911 for i in 0..5 {
912 request.push([matrix[i*4], matrix[i*4+1], matrix[i*4+2], matrix[i*4+3]]);
913 }
914 }
915 }
916 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
917 FilterGraphOp::SVGFEComponentTransferInterned{..} => {}
918 FilterGraphOp::SVGFECompositeArithmetic{k1, k2, k3, k4} => {
919 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
920 if let Some(mut request) = gpu_cache.request(handle) {
921 request.push([k1, k2, k3, k4]);
922 }
923 }
924 FilterGraphOp::SVGFECompositeATop => {}
925 FilterGraphOp::SVGFECompositeIn => {}
926 FilterGraphOp::SVGFECompositeLighter => {}
927 FilterGraphOp::SVGFECompositeOut => {}
928 FilterGraphOp::SVGFECompositeOver => {}
929 FilterGraphOp::SVGFECompositeXOR => {}
930 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} |
931 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} |
932 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} => {
933 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
934 if let Some(mut request) = gpu_cache.request(handle) {
935 request.push([-target_x as f32, -target_y as f32, order_x as f32, order_y as f32]);
936 request.push([kernel_unit_length_x as f32, kernel_unit_length_y as f32, 1.0 / divisor, bias]);
937 assert!(SVGFE_CONVOLVE_VALUES_LIMIT == 25);
938 request.push([kernel[0], kernel[1], kernel[2], kernel[3]]);
939 request.push([kernel[4], kernel[5], kernel[6], kernel[7]]);
940 request.push([kernel[8], kernel[9], kernel[10], kernel[11]]);
941 request.push([kernel[12], kernel[13], kernel[14], kernel[15]]);
942 request.push([kernel[16], kernel[17], kernel[18], kernel[19]]);
943 request.push([kernel[20], 0.0, 0.0, preserve_alpha as f32]);
944 }
945 }
946 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {}
947 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {}
948 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {}
949 FilterGraphOp::SVGFEDisplacementMap{scale, x_channel_selector, y_channel_selector} => {
950 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
951 if let Some(mut request) = gpu_cache.request(handle) {
952 request.push([x_channel_selector as f32, y_channel_selector as f32, scale, 0.0]);
953 }
954 }
955 FilterGraphOp::SVGFEDropShadow{color, ..} |
956 FilterGraphOp::SVGFEFlood{color} => {
957 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
958 if let Some(mut request) = gpu_cache.request(handle) {
959 request.push(color.to_array());
960 }
961 }
962 FilterGraphOp::SVGFEGaussianBlur{..} => {}
963 FilterGraphOp::SVGFEIdentity => {}
964 FilterGraphOp::SVGFEImage{..} => {}
965 FilterGraphOp::SVGFEMorphologyDilate{radius_x, radius_y} |
966 FilterGraphOp::SVGFEMorphologyErode{radius_x, radius_y} => {
967 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
968 if let Some(mut request) = gpu_cache.request(handle) {
969 request.push([radius_x, radius_y, 0.0, 0.0]);
970 }
971 }
972 FilterGraphOp::SVGFEOpacity{..} => {}
973 FilterGraphOp::SVGFESourceAlpha => {}
974 FilterGraphOp::SVGFESourceGraphic => {}
975 FilterGraphOp::SVGFESpecularLightingDistant{..} => {}
976 FilterGraphOp::SVGFESpecularLightingPoint{..} => {}
977 FilterGraphOp::SVGFESpecularLightingSpot{..} => {}
978 FilterGraphOp::SVGFETile => {}
979 FilterGraphOp::SVGFEToAlpha{..} => {}
980 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} => {}
981 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} => {}
982 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} => {}
983 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {}
984 }
985 }
986 _ => {}
987 }
988 }
989}
990
991pub type BlurTaskCache = FastHashMap<BlurTaskKey, RenderTaskId>;
995
996#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
999pub enum BlurTaskKey {
1000 DownScale(u32),
1001 Blur { downscale_level: u32, stddev_x: u32, stddev_y: u32 },
1002}
1003
1004impl BlurTaskKey {
1005 fn downscale_and_blur(downscale_level: u32, blur_stddev: DeviceSize) -> Self {
1006 const QUANTIZATION_FACTOR: f32 = 1024.0;
1011 let stddev_x = (blur_stddev.width * QUANTIZATION_FACTOR) as u32;
1012 let stddev_y = (blur_stddev.height * QUANTIZATION_FACTOR) as u32;
1013 BlurTaskKey::Blur { downscale_level, stddev_x, stddev_y }
1014 }
1015}
1016
1017pub type TaskDependencies = SmallVec<[RenderTaskId;2]>;
1022
1023#[cfg_attr(feature = "capture", derive(Serialize))]
1024#[cfg_attr(feature = "replay", derive(Deserialize))]
1025pub struct MaskSubPass {
1026 pub clip_node_range: ClipNodeRange,
1027 pub prim_spatial_node_index: SpatialNodeIndex,
1028 pub prim_address_f: GpuBufferAddress,
1029}
1030
1031#[cfg_attr(feature = "capture", derive(Serialize))]
1032#[cfg_attr(feature = "replay", derive(Deserialize))]
1033pub enum SubPass {
1034 Masks {
1035 masks: MaskSubPass,
1036 },
1037}
1038
1039#[cfg_attr(feature = "capture", derive(Serialize))]
1040#[cfg_attr(feature = "replay", derive(Deserialize))]
1041pub struct RenderTask {
1042 pub location: RenderTaskLocation,
1043 pub children: TaskDependencies,
1044 pub kind: RenderTaskKind,
1045 pub sub_pass: Option<SubPass>,
1046
1047 pub free_after: PassId,
1050 pub render_on: PassId,
1051
1052 pub uv_rect_handle: GpuCacheHandle,
1057 pub cache_handle: Option<RenderTaskCacheEntryHandle>,
1058 uv_rect_kind: UvRectKind,
1059}
1060
1061impl RenderTask {
1062 pub fn new(
1063 location: RenderTaskLocation,
1064 kind: RenderTaskKind,
1065 ) -> Self {
1066 render_task_sanity_check(&location.size());
1067
1068 RenderTask {
1069 location,
1070 children: TaskDependencies::new(),
1071 kind,
1072 free_after: PassId::MAX,
1073 render_on: PassId::MIN,
1074 uv_rect_handle: GpuCacheHandle::new(),
1075 uv_rect_kind: UvRectKind::Rect,
1076 cache_handle: None,
1077 sub_pass: None,
1078 }
1079 }
1080
1081 pub fn new_dynamic(
1082 size: DeviceIntSize,
1083 kind: RenderTaskKind,
1084 ) -> Self {
1085 assert!(!size.is_empty(), "Bad {} render task size: {:?}", kind.as_str(), size);
1086 RenderTask::new(
1087 RenderTaskLocation::Unallocated { size },
1088 kind,
1089 )
1090 }
1091
1092 pub fn with_uv_rect_kind(mut self, uv_rect_kind: UvRectKind) -> Self {
1093 self.uv_rect_kind = uv_rect_kind;
1094 self
1095 }
1096
1097 pub fn new_image(
1098 size: DeviceIntSize,
1099 request: ImageRequest,
1100 is_composited: bool,
1101 ) -> Self {
1102 RenderTask {
1111 location: RenderTaskLocation::CacheRequest { size, },
1112 children: TaskDependencies::new(),
1113 kind: RenderTaskKind::Image(ImageRequestTask {
1114 request,
1115 is_composited,
1116 }),
1117 free_after: PassId::MAX,
1118 render_on: PassId::MIN,
1119 uv_rect_handle: GpuCacheHandle::new(),
1120 uv_rect_kind: UvRectKind::Rect,
1121 cache_handle: None,
1122 sub_pass: None,
1123 }
1124 }
1125
1126
1127 #[cfg(test)]
1128 pub fn new_test(
1129 location: RenderTaskLocation,
1130 target: RenderTargetKind,
1131 ) -> Self {
1132 RenderTask {
1133 location,
1134 children: TaskDependencies::new(),
1135 kind: RenderTaskKind::Test(target),
1136 free_after: PassId::MAX,
1137 render_on: PassId::MIN,
1138 uv_rect_handle: GpuCacheHandle::new(),
1139 uv_rect_kind: UvRectKind::Rect,
1140 cache_handle: None,
1141 sub_pass: None,
1142 }
1143 }
1144
1145 pub fn new_blit(
1146 size: DeviceIntSize,
1147 source: RenderTaskId,
1148 source_rect: DeviceIntRect,
1149 rg_builder: &mut RenderTaskGraphBuilder,
1150 ) -> RenderTaskId {
1151 let blit_task_id = rg_builder.add().init(RenderTask::new_dynamic(
1158 size,
1159 RenderTaskKind::Blit(BlitTask { source, source_rect }),
1160 ));
1161
1162 rg_builder.add_dependency(blit_task_id, source);
1163
1164 blit_task_id
1165 }
1166
1167 pub fn new_blur(
1186 blur_std_deviation: DeviceSize,
1187 src_task_id: RenderTaskId,
1188 rg_builder: &mut RenderTaskGraphBuilder,
1189 target_kind: RenderTargetKind,
1190 mut blur_cache: Option<&mut BlurTaskCache>,
1191 blur_region: DeviceIntSize,
1192 edge_mode: BlurEdgeMode,
1193 ) -> RenderTaskId {
1194 let mut adjusted_blur_std_deviation = blur_std_deviation;
1196 let (blur_target_size, uv_rect_kind) = {
1197 let src_task = rg_builder.get_task(src_task_id);
1198 (src_task.location.size(), src_task.uv_rect_kind())
1199 };
1200 let mut adjusted_blur_target_size = blur_target_size;
1201 let mut downscaling_src_task_id = src_task_id;
1202 let mut scale_factor = 1.0;
1203 let mut n_downscales = 1;
1204 while adjusted_blur_std_deviation.width > MAX_BLUR_STD_DEVIATION &&
1205 adjusted_blur_std_deviation.height > MAX_BLUR_STD_DEVIATION {
1206 if adjusted_blur_target_size.width < MIN_DOWNSCALING_RT_SIZE ||
1207 adjusted_blur_target_size.height < MIN_DOWNSCALING_RT_SIZE {
1208 break;
1209 }
1210 adjusted_blur_std_deviation = adjusted_blur_std_deviation * 0.5;
1211 scale_factor *= 2.0;
1212 adjusted_blur_target_size = (blur_target_size.to_f32() / scale_factor).to_i32();
1213
1214 let cached_task = match blur_cache {
1215 Some(ref mut cache) => cache.get(&BlurTaskKey::DownScale(n_downscales)).cloned(),
1216 None => None,
1217 };
1218
1219 downscaling_src_task_id = cached_task.unwrap_or_else(|| {
1220 RenderTask::new_scaling(
1221 downscaling_src_task_id,
1222 rg_builder,
1223 target_kind,
1224 adjusted_blur_target_size,
1225 )
1226 });
1227
1228 if let Some(ref mut cache) = blur_cache {
1229 cache.insert(BlurTaskKey::DownScale(n_downscales), downscaling_src_task_id);
1230 }
1231
1232 n_downscales += 1;
1233 }
1234
1235
1236 let blur_key = BlurTaskKey::downscale_and_blur(n_downscales, adjusted_blur_std_deviation);
1237
1238 let cached_task = match blur_cache {
1239 Some(ref mut cache) => cache.get(&blur_key).cloned(),
1240 None => None,
1241 };
1242
1243 let blur_region = blur_region / (scale_factor as i32);
1244
1245 let blur_task_id = cached_task.unwrap_or_else(|| {
1246 let blur_task_v = rg_builder.add().init(RenderTask::new_dynamic(
1247 adjusted_blur_target_size,
1248 RenderTaskKind::VerticalBlur(BlurTask {
1249 blur_std_deviation: adjusted_blur_std_deviation.height,
1250 target_kind,
1251 blur_region,
1252 edge_mode,
1253 }),
1254 ).with_uv_rect_kind(uv_rect_kind));
1255 rg_builder.add_dependency(blur_task_v, downscaling_src_task_id);
1256
1257 let task_id = rg_builder.add().init(RenderTask::new_dynamic(
1258 adjusted_blur_target_size,
1259 RenderTaskKind::HorizontalBlur(BlurTask {
1260 blur_std_deviation: adjusted_blur_std_deviation.width,
1261 target_kind,
1262 blur_region,
1263 edge_mode,
1264 }),
1265 ).with_uv_rect_kind(uv_rect_kind));
1266 rg_builder.add_dependency(task_id, blur_task_v);
1267
1268 task_id
1269 });
1270
1271 if let Some(ref mut cache) = blur_cache {
1272 cache.insert(blur_key, blur_task_id);
1273 }
1274
1275 blur_task_id
1276 }
1277
1278 pub fn new_scaling(
1279 src_task_id: RenderTaskId,
1280 rg_builder: &mut RenderTaskGraphBuilder,
1281 target_kind: RenderTargetKind,
1282 size: DeviceIntSize,
1283 ) -> RenderTaskId {
1284 Self::new_scaling_with_padding(
1285 src_task_id,
1286 rg_builder,
1287 target_kind,
1288 size,
1289 DeviceIntSideOffsets::zero(),
1290 )
1291 }
1292
1293 pub fn new_scaling_with_padding(
1294 source: RenderTaskId,
1295 rg_builder: &mut RenderTaskGraphBuilder,
1296 target_kind: RenderTargetKind,
1297 padded_size: DeviceIntSize,
1298 padding: DeviceIntSideOffsets,
1299 ) -> RenderTaskId {
1300 let uv_rect_kind = rg_builder.get_task(source).uv_rect_kind();
1301
1302 let task_id = rg_builder.add().init(
1303 RenderTask::new_dynamic(
1304 padded_size,
1305 RenderTaskKind::Scaling(ScalingTask {
1306 target_kind,
1307 padding,
1308 }),
1309 ).with_uv_rect_kind(uv_rect_kind)
1310 );
1311
1312 rg_builder.add_dependency(task_id, source);
1313
1314 task_id
1315 }
1316
1317 pub fn new_svg_filter(
1318 filter_primitives: &[FilterPrimitive],
1319 filter_datas: &[SFilterData],
1320 rg_builder: &mut RenderTaskGraphBuilder,
1321 content_size: DeviceIntSize,
1322 uv_rect_kind: UvRectKind,
1323 original_task_id: RenderTaskId,
1324 device_pixel_scale: DevicePixelScale,
1325 ) -> RenderTaskId {
1326
1327 if filter_primitives.is_empty() {
1328 return original_task_id;
1329 }
1330
1331 let get_task_input = |
1333 input: &FilterPrimitiveInput,
1334 filter_primitives: &[FilterPrimitive],
1335 rg_builder: &mut RenderTaskGraphBuilder,
1336 cur_index: usize,
1337 outputs: &[RenderTaskId],
1338 original: RenderTaskId,
1339 color_space: ColorSpace,
1340 | {
1341 let (mut task_id, input_color_space) = match input.to_index(cur_index) {
1343 Some(index) => (outputs[index], filter_primitives[index].color_space),
1344 None => (original, ColorSpace::Srgb),
1345 };
1346
1347 match (input_color_space, color_space) {
1348 (ColorSpace::Srgb, ColorSpace::LinearRgb) => {
1349 task_id = RenderTask::new_svg_filter_primitive(
1350 smallvec![task_id],
1351 content_size,
1352 uv_rect_kind,
1353 SvgFilterInfo::SrgbToLinear,
1354 rg_builder,
1355 );
1356 },
1357 (ColorSpace::LinearRgb, ColorSpace::Srgb) => {
1358 task_id = RenderTask::new_svg_filter_primitive(
1359 smallvec![task_id],
1360 content_size,
1361 uv_rect_kind,
1362 SvgFilterInfo::LinearToSrgb,
1363 rg_builder,
1364 );
1365 },
1366 _ => {},
1367 }
1368
1369 task_id
1370 };
1371
1372 let mut outputs = vec![];
1373 let mut cur_filter_data = 0;
1374 for (cur_index, primitive) in filter_primitives.iter().enumerate() {
1375 let render_task_id = match primitive.kind {
1376 FilterPrimitiveKind::Identity(ref identity) => {
1377 get_task_input(
1379 &identity.input,
1380 filter_primitives,
1381 rg_builder,
1382 cur_index,
1383 &outputs,
1384 original_task_id,
1385 primitive.color_space
1386 )
1387 }
1388 FilterPrimitiveKind::Blend(ref blend) => {
1389 let input_1_task_id = get_task_input(
1390 &blend.input1,
1391 filter_primitives,
1392 rg_builder,
1393 cur_index,
1394 &outputs,
1395 original_task_id,
1396 primitive.color_space
1397 );
1398 let input_2_task_id = get_task_input(
1399 &blend.input2,
1400 filter_primitives,
1401 rg_builder,
1402 cur_index,
1403 &outputs,
1404 original_task_id,
1405 primitive.color_space
1406 );
1407
1408 RenderTask::new_svg_filter_primitive(
1409 smallvec![input_1_task_id, input_2_task_id],
1410 content_size,
1411 uv_rect_kind,
1412 SvgFilterInfo::Blend(blend.mode),
1413 rg_builder,
1414 )
1415 },
1416 FilterPrimitiveKind::Flood(ref flood) => {
1417 RenderTask::new_svg_filter_primitive(
1418 smallvec![],
1419 content_size,
1420 uv_rect_kind,
1421 SvgFilterInfo::Flood(flood.color),
1422 rg_builder,
1423 )
1424 }
1425 FilterPrimitiveKind::Blur(ref blur) => {
1426 let width_std_deviation = blur.width * device_pixel_scale.0;
1427 let height_std_deviation = blur.height * device_pixel_scale.0;
1428 let input_task_id = get_task_input(
1429 &blur.input,
1430 filter_primitives,
1431 rg_builder,
1432 cur_index,
1433 &outputs,
1434 original_task_id,
1435 primitive.color_space
1436 );
1437
1438 RenderTask::new_blur(
1439 DeviceSize::new(width_std_deviation, height_std_deviation),
1440 RenderTask::new_svg_filter_primitive(
1443 smallvec![input_task_id],
1444 content_size,
1445 uv_rect_kind,
1446 SvgFilterInfo::Identity,
1447 rg_builder,
1448 ),
1449 rg_builder,
1450 RenderTargetKind::Color,
1451 None,
1452 content_size,
1453 BlurEdgeMode::Duplicate,
1454 )
1455 }
1456 FilterPrimitiveKind::Opacity(ref opacity) => {
1457 let input_task_id = get_task_input(
1458 &opacity.input,
1459 filter_primitives,
1460 rg_builder,
1461 cur_index,
1462 &outputs,
1463 original_task_id,
1464 primitive.color_space
1465 );
1466
1467 RenderTask::new_svg_filter_primitive(
1468 smallvec![input_task_id],
1469 content_size,
1470 uv_rect_kind,
1471 SvgFilterInfo::Opacity(opacity.opacity),
1472 rg_builder,
1473 )
1474 }
1475 FilterPrimitiveKind::ColorMatrix(ref color_matrix) => {
1476 let input_task_id = get_task_input(
1477 &color_matrix.input,
1478 filter_primitives,
1479 rg_builder,
1480 cur_index,
1481 &outputs,
1482 original_task_id,
1483 primitive.color_space
1484 );
1485
1486 RenderTask::new_svg_filter_primitive(
1487 smallvec![input_task_id],
1488 content_size,
1489 uv_rect_kind,
1490 SvgFilterInfo::ColorMatrix(Box::new(color_matrix.matrix)),
1491 rg_builder,
1492 )
1493 }
1494 FilterPrimitiveKind::DropShadow(ref drop_shadow) => {
1495 let input_task_id = get_task_input(
1496 &drop_shadow.input,
1497 filter_primitives,
1498 rg_builder,
1499 cur_index,
1500 &outputs,
1501 original_task_id,
1502 primitive.color_space
1503 );
1504
1505 let blur_std_deviation = drop_shadow.shadow.blur_radius * device_pixel_scale.0;
1506 let offset = drop_shadow.shadow.offset * LayoutToWorldScale::new(1.0) * device_pixel_scale;
1507
1508 let offset_task_id = RenderTask::new_svg_filter_primitive(
1509 smallvec![input_task_id],
1510 content_size,
1511 uv_rect_kind,
1512 SvgFilterInfo::Offset(offset),
1513 rg_builder,
1514 );
1515
1516 let blur_task_id = RenderTask::new_blur(
1517 DeviceSize::new(blur_std_deviation, blur_std_deviation),
1518 offset_task_id,
1519 rg_builder,
1520 RenderTargetKind::Color,
1521 None,
1522 content_size,
1523 BlurEdgeMode::Duplicate,
1524 );
1525
1526 RenderTask::new_svg_filter_primitive(
1527 smallvec![input_task_id, blur_task_id],
1528 content_size,
1529 uv_rect_kind,
1530 SvgFilterInfo::DropShadow(drop_shadow.shadow.color),
1531 rg_builder,
1532 )
1533 }
1534 FilterPrimitiveKind::ComponentTransfer(ref component_transfer) => {
1535 let input_task_id = get_task_input(
1536 &component_transfer.input,
1537 filter_primitives,
1538 rg_builder,
1539 cur_index,
1540 &outputs,
1541 original_task_id,
1542 primitive.color_space
1543 );
1544
1545 let filter_data = &filter_datas[cur_filter_data];
1546 cur_filter_data += 1;
1547 if filter_data.is_identity() {
1548 input_task_id
1549 } else {
1550 RenderTask::new_svg_filter_primitive(
1551 smallvec![input_task_id],
1552 content_size,
1553 uv_rect_kind,
1554 SvgFilterInfo::ComponentTransfer(filter_data.clone()),
1555 rg_builder,
1556 )
1557 }
1558 }
1559 FilterPrimitiveKind::Offset(ref info) => {
1560 let input_task_id = get_task_input(
1561 &info.input,
1562 filter_primitives,
1563 rg_builder,
1564 cur_index,
1565 &outputs,
1566 original_task_id,
1567 primitive.color_space
1568 );
1569
1570 let offset = info.offset * LayoutToWorldScale::new(1.0) * device_pixel_scale;
1571 RenderTask::new_svg_filter_primitive(
1572 smallvec![input_task_id],
1573 content_size,
1574 uv_rect_kind,
1575 SvgFilterInfo::Offset(offset),
1576 rg_builder,
1577 )
1578 }
1579 FilterPrimitiveKind::Composite(info) => {
1580 let input_1_task_id = get_task_input(
1581 &info.input1,
1582 filter_primitives,
1583 rg_builder,
1584 cur_index,
1585 &outputs,
1586 original_task_id,
1587 primitive.color_space
1588 );
1589 let input_2_task_id = get_task_input(
1590 &info.input2,
1591 filter_primitives,
1592 rg_builder,
1593 cur_index,
1594 &outputs,
1595 original_task_id,
1596 primitive.color_space
1597 );
1598
1599 RenderTask::new_svg_filter_primitive(
1600 smallvec![input_1_task_id, input_2_task_id],
1601 content_size,
1602 uv_rect_kind,
1603 SvgFilterInfo::Composite(info.operator),
1604 rg_builder,
1605 )
1606 }
1607 };
1608 outputs.push(render_task_id);
1609 }
1610
1611 let mut render_task_id = *outputs.last().unwrap();
1613
1614 if filter_primitives.last().unwrap().color_space == ColorSpace::LinearRgb {
1616 render_task_id = RenderTask::new_svg_filter_primitive(
1617 smallvec![render_task_id],
1618 content_size,
1619 uv_rect_kind,
1620 SvgFilterInfo::LinearToSrgb,
1621 rg_builder,
1622 );
1623 }
1624
1625 render_task_id
1626 }
1627
1628 pub fn new_svg_filter_primitive(
1629 tasks: TaskDependencies,
1630 target_size: DeviceIntSize,
1631 uv_rect_kind: UvRectKind,
1632 info: SvgFilterInfo,
1633 rg_builder: &mut RenderTaskGraphBuilder,
1634 ) -> RenderTaskId {
1635 let task_id = rg_builder.add().init(RenderTask::new_dynamic(
1636 target_size,
1637 RenderTaskKind::SvgFilter(SvgFilterTask {
1638 extra_gpu_cache_handle: None,
1639 info,
1640 }),
1641 ).with_uv_rect_kind(uv_rect_kind));
1642
1643 for child_id in tasks {
1644 rg_builder.add_dependency(task_id, child_id);
1645 }
1646
1647 task_id
1648 }
1649
1650 pub fn add_sub_pass(
1651 &mut self,
1652 sub_pass: SubPass,
1653 ) {
1654 assert!(self.sub_pass.is_none(), "multiple sub-passes are not supported for now");
1655 self.sub_pass = Some(sub_pass);
1656 }
1657
1658 pub fn new_svg_filter_graph(
1666 filter_nodes: &[(FilterGraphNode, FilterGraphOp)],
1667 rg_builder: &mut RenderTaskGraphBuilder,
1668 gpu_cache: &mut GpuCache,
1669 data_stores: &mut DataStores,
1670 _uv_rect_kind: UvRectKind,
1671 original_task_id: RenderTaskId,
1672 source_subregion: LayoutRect,
1673 target_subregion: LayoutRect,
1674 prim_subregion: LayoutRect,
1675 subregion_to_device_scale_x: f32,
1676 subregion_to_device_scale_y: f32,
1677 subregion_to_device_offset_x: f32,
1678 subregion_to_device_offset_y: f32,
1679 ) -> RenderTaskId {
1680 const BUFFER_LIMIT: usize = SVGFE_GRAPH_MAX;
1681 let mut task_by_buffer_id: [RenderTaskId; BUFFER_LIMIT] = [RenderTaskId::INVALID; BUFFER_LIMIT];
1682 let mut subregion_by_buffer_id: [LayoutRect; BUFFER_LIMIT] = [LayoutRect::zero(); BUFFER_LIMIT];
1683 let mut output_task_id = original_task_id;
1686
1687 fn uv_rect_kind_for_task_size(clipped: DeviceRect, unclipped: DeviceRect) -> UvRectKind {
1705 let scale_x = 1.0 / clipped.width();
1706 let scale_y = 1.0 / clipped.height();
1707 UvRectKind::Quad{
1708 top_left: DeviceHomogeneousVector::new(
1709 (unclipped.min.x - clipped.min.x) * scale_x,
1710 (unclipped.min.y - clipped.min.y) * scale_y,
1711 0.0, 1.0),
1712 top_right: DeviceHomogeneousVector::new(
1713 (unclipped.max.x - clipped.min.x) * scale_x,
1714 (unclipped.min.y - clipped.min.y) * scale_y,
1715 0.0, 1.0),
1716 bottom_left: DeviceHomogeneousVector::new(
1717 (unclipped.min.x - clipped.min.x) * scale_x,
1718 (unclipped.max.y - clipped.min.y) * scale_y,
1719 0.0, 1.0),
1720 bottom_right: DeviceHomogeneousVector::new(
1721 (unclipped.max.x - clipped.min.x) * scale_x,
1722 (unclipped.max.y - clipped.min.y) * scale_y,
1723 0.0, 1.0),
1724 }
1725 }
1726
1727 let mut made_dependency_on_source = false;
1729 for (filter_index, (filter_node, op)) in filter_nodes.iter().enumerate() {
1730 let node = &filter_node;
1731 let is_output = filter_index == filter_nodes.len() - 1;
1732
1733 if !node.kept_by_optimizer {
1735 continue;
1736 }
1737
1738 let op = match op {
1741 FilterGraphOp::SVGFEBlendColor => op.clone(),
1742 FilterGraphOp::SVGFEBlendColorBurn => op.clone(),
1743 FilterGraphOp::SVGFEBlendColorDodge => op.clone(),
1744 FilterGraphOp::SVGFEBlendDarken => op.clone(),
1745 FilterGraphOp::SVGFEBlendDifference => op.clone(),
1746 FilterGraphOp::SVGFEBlendExclusion => op.clone(),
1747 FilterGraphOp::SVGFEBlendHardLight => op.clone(),
1748 FilterGraphOp::SVGFEBlendHue => op.clone(),
1749 FilterGraphOp::SVGFEBlendLighten => op.clone(),
1750 FilterGraphOp::SVGFEBlendLuminosity => op.clone(),
1751 FilterGraphOp::SVGFEBlendMultiply => op.clone(),
1752 FilterGraphOp::SVGFEBlendNormal => op.clone(),
1753 FilterGraphOp::SVGFEBlendOverlay => op.clone(),
1754 FilterGraphOp::SVGFEBlendSaturation => op.clone(),
1755 FilterGraphOp::SVGFEBlendScreen => op.clone(),
1756 FilterGraphOp::SVGFEBlendSoftLight => op.clone(),
1757 FilterGraphOp::SVGFEColorMatrix{..} => op.clone(),
1758 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
1759 FilterGraphOp::SVGFEComponentTransferInterned{..} => op.clone(),
1760 FilterGraphOp::SVGFECompositeArithmetic{..} => op.clone(),
1761 FilterGraphOp::SVGFECompositeATop => op.clone(),
1762 FilterGraphOp::SVGFECompositeIn => op.clone(),
1763 FilterGraphOp::SVGFECompositeLighter => op.clone(),
1764 FilterGraphOp::SVGFECompositeOut => op.clone(),
1765 FilterGraphOp::SVGFECompositeOver => op.clone(),
1766 FilterGraphOp::SVGFECompositeXOR => op.clone(),
1767 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{
1768 kernel_unit_length_x, kernel_unit_length_y, order_x,
1769 order_y, kernel, divisor, bias, target_x, target_y,
1770 preserve_alpha} => {
1771 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{
1772 kernel_unit_length_x:
1773 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1774 kernel_unit_length_y:
1775 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1776 order_x: *order_x, order_y: *order_y, kernel: *kernel,
1777 divisor: *divisor, bias: *bias, target_x: *target_x,
1778 target_y: *target_y, preserve_alpha: *preserve_alpha}
1779 },
1780 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{
1781 kernel_unit_length_x, kernel_unit_length_y, order_x,
1782 order_y, kernel, divisor, bias, target_x, target_y,
1783 preserve_alpha} => {
1784 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{
1785 kernel_unit_length_x:
1786 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1787 kernel_unit_length_y:
1788 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1789 order_x: *order_x, order_y: *order_y, kernel: *kernel,
1790 divisor: *divisor, bias: *bias, target_x: *target_x,
1791 target_y: *target_y, preserve_alpha: *preserve_alpha}
1792 },
1793 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{
1794 kernel_unit_length_x, kernel_unit_length_y, order_x,
1795 order_y, kernel, divisor, bias, target_x, target_y,
1796 preserve_alpha} => {
1797 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{
1798 kernel_unit_length_x:
1799 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1800 kernel_unit_length_y:
1801 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1802 order_x: *order_x, order_y: *order_y, kernel: *kernel,
1803 divisor: *divisor, bias: *bias, target_x: *target_x,
1804 target_y: *target_y, preserve_alpha: *preserve_alpha}
1805 },
1806 FilterGraphOp::SVGFEDiffuseLightingDistant{
1807 surface_scale, diffuse_constant, kernel_unit_length_x,
1808 kernel_unit_length_y, azimuth, elevation} => {
1809 FilterGraphOp::SVGFEDiffuseLightingDistant{
1810 surface_scale: *surface_scale,
1811 diffuse_constant: *diffuse_constant,
1812 kernel_unit_length_x:
1813 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1814 kernel_unit_length_y:
1815 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1816 azimuth: *azimuth, elevation: *elevation}
1817 },
1818 FilterGraphOp::SVGFEDiffuseLightingPoint{
1819 surface_scale, diffuse_constant, kernel_unit_length_x,
1820 kernel_unit_length_y, x, y, z} => {
1821 FilterGraphOp::SVGFEDiffuseLightingPoint{
1822 surface_scale: *surface_scale,
1823 diffuse_constant: *diffuse_constant,
1824 kernel_unit_length_x:
1825 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1826 kernel_unit_length_y:
1827 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1828 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1829 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1830 z: *z}
1831 },
1832 FilterGraphOp::SVGFEDiffuseLightingSpot{
1833 surface_scale, diffuse_constant, kernel_unit_length_x,
1834 kernel_unit_length_y, x, y, z, points_at_x, points_at_y,
1835 points_at_z, cone_exponent, limiting_cone_angle} => {
1836 FilterGraphOp::SVGFEDiffuseLightingSpot{
1837 surface_scale: *surface_scale,
1838 diffuse_constant: *diffuse_constant,
1839 kernel_unit_length_x:
1840 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1841 kernel_unit_length_y:
1842 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1843 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1844 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1845 z: *z,
1846 points_at_x: points_at_x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1847 points_at_y: points_at_y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1848 points_at_z: *points_at_z,
1849 cone_exponent: *cone_exponent,
1850 limiting_cone_angle: *limiting_cone_angle}
1851 },
1852 FilterGraphOp::SVGFEFlood{..} => op.clone(),
1853 FilterGraphOp::SVGFEDisplacementMap{
1854 scale, x_channel_selector, y_channel_selector} => {
1855 FilterGraphOp::SVGFEDisplacementMap{
1856 scale: scale * subregion_to_device_scale_x,
1857 x_channel_selector: *x_channel_selector,
1858 y_channel_selector: *y_channel_selector}
1859 },
1860 FilterGraphOp::SVGFEDropShadow{
1861 color, dx, dy, std_deviation_x, std_deviation_y} => {
1862 FilterGraphOp::SVGFEDropShadow{
1863 color: *color,
1864 dx: dx * subregion_to_device_scale_x,
1865 dy: dy * subregion_to_device_scale_y,
1866 std_deviation_x: std_deviation_x * subregion_to_device_scale_x,
1867 std_deviation_y: std_deviation_y * subregion_to_device_scale_y}
1868 },
1869 FilterGraphOp::SVGFEGaussianBlur{std_deviation_x, std_deviation_y} => {
1870 let std_deviation_x = std_deviation_x * subregion_to_device_scale_x;
1871 let std_deviation_y = std_deviation_y * subregion_to_device_scale_y;
1872 if std_deviation_x + std_deviation_y >= 0.125 {
1875 FilterGraphOp::SVGFEGaussianBlur{
1876 std_deviation_x,
1877 std_deviation_y}
1878 } else {
1879 FilterGraphOp::SVGFEIdentity
1880 }
1881 },
1882 FilterGraphOp::SVGFEIdentity => op.clone(),
1883 FilterGraphOp::SVGFEImage{..} => op.clone(),
1884 FilterGraphOp::SVGFEMorphologyDilate{radius_x, radius_y} => {
1885 FilterGraphOp::SVGFEMorphologyDilate{
1886 radius_x: (radius_x * subregion_to_device_scale_x).round(),
1887 radius_y: (radius_y * subregion_to_device_scale_y).round()}
1888 },
1889 FilterGraphOp::SVGFEMorphologyErode{radius_x, radius_y} => {
1890 FilterGraphOp::SVGFEMorphologyErode{
1891 radius_x: (radius_x * subregion_to_device_scale_x).round(),
1892 radius_y: (radius_y * subregion_to_device_scale_y).round()}
1893 },
1894 FilterGraphOp::SVGFEOpacity{..} => op.clone(),
1895 FilterGraphOp::SVGFESourceAlpha => op.clone(),
1896 FilterGraphOp::SVGFESourceGraphic => op.clone(),
1897 FilterGraphOp::SVGFESpecularLightingDistant{
1898 surface_scale, specular_constant, specular_exponent,
1899 kernel_unit_length_x, kernel_unit_length_y, azimuth,
1900 elevation} => {
1901 FilterGraphOp::SVGFESpecularLightingDistant{
1902 surface_scale: *surface_scale,
1903 specular_constant: *specular_constant,
1904 specular_exponent: *specular_exponent,
1905 kernel_unit_length_x:
1906 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1907 kernel_unit_length_y:
1908 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1909 azimuth: *azimuth, elevation: *elevation}
1910 },
1911 FilterGraphOp::SVGFESpecularLightingPoint{
1912 surface_scale, specular_constant, specular_exponent,
1913 kernel_unit_length_x, kernel_unit_length_y, x, y, z } => {
1914 FilterGraphOp::SVGFESpecularLightingPoint{
1915 surface_scale: *surface_scale,
1916 specular_constant: *specular_constant,
1917 specular_exponent: *specular_exponent,
1918 kernel_unit_length_x:
1919 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1920 kernel_unit_length_y:
1921 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1922 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1923 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1924 z: *z }
1925 },
1926 FilterGraphOp::SVGFESpecularLightingSpot{
1927 surface_scale, specular_constant, specular_exponent,
1928 kernel_unit_length_x, kernel_unit_length_y, x, y, z,
1929 points_at_x, points_at_y, points_at_z, cone_exponent,
1930 limiting_cone_angle} => {
1931 FilterGraphOp::SVGFESpecularLightingSpot{
1932 surface_scale: *surface_scale,
1933 specular_constant: *specular_constant,
1934 specular_exponent: *specular_exponent,
1935 kernel_unit_length_x:
1936 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1937 kernel_unit_length_y:
1938 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1939 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1940 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1941 z: *z,
1942 points_at_x: points_at_x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1943 points_at_y: points_at_y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1944 points_at_z: *points_at_z,
1945 cone_exponent: *cone_exponent,
1946 limiting_cone_angle: *limiting_cone_angle}
1947 },
1948 FilterGraphOp::SVGFETile => op.clone(),
1949 FilterGraphOp::SVGFEToAlpha => op.clone(),
1950 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1951 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1952 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1953 base_frequency_x:
1954 base_frequency_x * subregion_to_device_scale_x,
1955 base_frequency_y:
1956 base_frequency_y * subregion_to_device_scale_y,
1957 num_octaves: *num_octaves, seed: *seed}
1958 },
1959 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{
1960 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1961 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1962 base_frequency_x:
1963 base_frequency_x * subregion_to_device_scale_x,
1964 base_frequency_y:
1965 base_frequency_y * subregion_to_device_scale_y,
1966 num_octaves: *num_octaves, seed: *seed}
1967 },
1968 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{
1969 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1970 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1971 base_frequency_x:
1972 base_frequency_x * subregion_to_device_scale_x,
1973 base_frequency_y:
1974 base_frequency_y * subregion_to_device_scale_y,
1975 num_octaves: *num_octaves, seed: *seed}
1976 },
1977 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{
1978 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1979 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1980 base_frequency_x:
1981 base_frequency_x * subregion_to_device_scale_x,
1982 base_frequency_y:
1983 base_frequency_y * subregion_to_device_scale_y,
1984 num_octaves: *num_octaves, seed: *seed}
1985 },
1986 };
1987
1988 let mut used_subregion = LayoutRect::zero();
1994 let mut combined_input_subregion = LayoutRect::zero();
1995 let node_inputs: Vec<(FilterGraphPictureReference, RenderTaskId)> = node.inputs.iter().map(|input| {
1996 let (subregion, task) =
1997 match input.buffer_id {
1998 FilterOpGraphPictureBufferId::BufferId(id) => {
1999 (subregion_by_buffer_id[id as usize], task_by_buffer_id[id as usize])
2000 }
2001 FilterOpGraphPictureBufferId::None => {
2002 (LayoutRect::zero(), original_task_id)
2006 }
2007 };
2008 let offset = LayoutVector2D::new(
2010 (input.offset.x * subregion_to_device_scale_x).round(),
2011 (input.offset.y * subregion_to_device_scale_y).round(),
2012 );
2013 let target_padding = input.target_padding
2018 .scale(subregion_to_device_scale_x, subregion_to_device_scale_y)
2019 .round();
2020 let target_subregion =
2021 LayoutRect::new(
2022 LayoutPoint::new(
2023 subregion.min.x + target_padding.min.x,
2024 subregion.min.y + target_padding.min.y,
2025 ),
2026 LayoutPoint::new(
2027 subregion.max.x + target_padding.max.x,
2028 subregion.max.y + target_padding.max.y,
2029 ),
2030 );
2031 used_subregion = used_subregion.union(&target_subregion);
2032 combined_input_subregion = combined_input_subregion.union(&subregion);
2033 (FilterGraphPictureReference{
2034 buffer_id: input.buffer_id,
2035 subregion: subregion.translate(offset),
2037 offset: LayoutVector2D::zero(),
2038 inflate: input.inflate,
2039 source_padding: LayoutRect::zero(),
2041 target_padding: LayoutRect::zero(),
2042 }, task)
2043 }).collect();
2044
2045 let full_subregion = node.subregion
2047 .scale(subregion_to_device_scale_x, subregion_to_device_scale_y)
2048 .translate(LayoutVector2D::new(subregion_to_device_offset_x, subregion_to_device_offset_y))
2049 .round();
2050
2051 used_subregion = used_subregion
2058 .intersection(&full_subregion)
2059 .unwrap_or(LayoutRect::zero())
2060 .round();
2061
2062 match op {
2064 FilterGraphOp::SVGFEBlendColor => {},
2065 FilterGraphOp::SVGFEBlendColorBurn => {},
2066 FilterGraphOp::SVGFEBlendColorDodge => {},
2067 FilterGraphOp::SVGFEBlendDarken => {},
2068 FilterGraphOp::SVGFEBlendDifference => {},
2069 FilterGraphOp::SVGFEBlendExclusion => {},
2070 FilterGraphOp::SVGFEBlendHardLight => {},
2071 FilterGraphOp::SVGFEBlendHue => {},
2072 FilterGraphOp::SVGFEBlendLighten => {},
2073 FilterGraphOp::SVGFEBlendLuminosity => {},
2074 FilterGraphOp::SVGFEBlendMultiply => {},
2075 FilterGraphOp::SVGFEBlendNormal => {},
2076 FilterGraphOp::SVGFEBlendOverlay => {},
2077 FilterGraphOp::SVGFEBlendSaturation => {},
2078 FilterGraphOp::SVGFEBlendScreen => {},
2079 FilterGraphOp::SVGFEBlendSoftLight => {},
2080 FilterGraphOp::SVGFEColorMatrix{values} => {
2081 if values[19] > 0.0 {
2082 used_subregion = full_subregion;
2085 }
2086 },
2087 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
2088 FilterGraphOp::SVGFEComponentTransferInterned{handle: _, creates_pixels} => {
2089 if creates_pixels {
2093 used_subregion = full_subregion;
2094 }
2095 },
2096 FilterGraphOp::SVGFECompositeArithmetic { k1, k2, k3, k4 } => {
2097 if k4 > 0.0 {
2104 used_subregion = full_subregion;
2106 } else if k1 > 0.0 && k2 == 0.0 && k3 == 0.0 {
2107 used_subregion = full_subregion
2109 .intersection(&node_inputs[0].0.subregion)
2110 .unwrap_or(LayoutRect::zero())
2111 .intersection(&node_inputs[1].0.subregion)
2112 .unwrap_or(LayoutRect::zero());
2113 }
2114 else if k2 > 0.0 && k3 == 0.0 {
2115 used_subregion = full_subregion
2117 .intersection(&node_inputs[0].0.subregion)
2118 .unwrap_or(LayoutRect::zero());
2119 }
2120 else if k2 == 0.0 && k3 > 0.0 {
2121 used_subregion = full_subregion
2123 .intersection(&node_inputs[1].0.subregion)
2124 .unwrap_or(LayoutRect::zero());
2125 }
2126 },
2127 FilterGraphOp::SVGFECompositeATop => {
2128 used_subregion = full_subregion
2130 .intersection(&node_inputs[1].0.subregion)
2131 .unwrap_or(LayoutRect::zero());
2132 },
2133 FilterGraphOp::SVGFECompositeIn => {
2134 used_subregion = used_subregion
2136 .intersection(&node_inputs[0].0.subregion)
2137 .unwrap_or(LayoutRect::zero())
2138 .intersection(&node_inputs[1].0.subregion)
2139 .unwrap_or(LayoutRect::zero());
2140 },
2141 FilterGraphOp::SVGFECompositeLighter => {},
2142 FilterGraphOp::SVGFECompositeOut => {
2143 used_subregion = full_subregion
2145 .intersection(&node_inputs[0].0.subregion)
2146 .unwrap_or(LayoutRect::zero());
2147 },
2148 FilterGraphOp::SVGFECompositeOver => {},
2149 FilterGraphOp::SVGFECompositeXOR => {},
2150 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{..} => {},
2151 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{..} => {},
2152 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{..} => {},
2153 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {},
2154 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {},
2155 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {},
2156 FilterGraphOp::SVGFEDisplacementMap{..} => {},
2157 FilterGraphOp::SVGFEDropShadow{..} => {},
2158 FilterGraphOp::SVGFEFlood { color } => {
2159 if color.a > 0.0 {
2164 used_subregion = full_subregion;
2165 }
2166 },
2167 FilterGraphOp::SVGFEIdentity => {},
2168 FilterGraphOp::SVGFEImage { sampling_filter: _sampling_filter, matrix: _matrix } => {
2169 used_subregion = full_subregion;
2171 },
2172 FilterGraphOp::SVGFEGaussianBlur{..} => {},
2173 FilterGraphOp::SVGFEMorphologyDilate{..} => {},
2174 FilterGraphOp::SVGFEMorphologyErode{..} => {},
2175 FilterGraphOp::SVGFEOpacity{valuebinding: _valuebinding, value} => {
2176 if value <= 0.0 {
2178 used_subregion = LayoutRect::zero();
2179 }
2180 },
2181 FilterGraphOp::SVGFESourceAlpha |
2182 FilterGraphOp::SVGFESourceGraphic => {
2183 used_subregion = source_subregion
2184 .intersection(&full_subregion)
2185 .unwrap_or(LayoutRect::zero());
2186 },
2187 FilterGraphOp::SVGFESpecularLightingDistant{..} => {},
2188 FilterGraphOp::SVGFESpecularLightingPoint{..} => {},
2189 FilterGraphOp::SVGFESpecularLightingSpot{..} => {},
2190 FilterGraphOp::SVGFETile => {
2191 if !used_subregion.is_empty() {
2192 used_subregion = full_subregion;
2195 }
2196 },
2197 FilterGraphOp::SVGFEToAlpha => {},
2198 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} |
2199 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} |
2200 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} |
2201 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {
2202 used_subregion = full_subregion;
2205 },
2206 }
2207
2208 add_text_marker(
2209 "SVGFEGraph",
2210 &format!("{}({})", op.kind(), filter_index),
2211 Duration::from_micros((used_subregion.width() * used_subregion.height() / 1000.0) as u64),
2212 );
2213
2214 let mut node_inflate = node.inflate;
2225 if is_output {
2226 used_subregion = target_subregion;
2228 node_inflate = 0;
2229 }
2230
2231 let mut device_to_render_scale = 1.0;
2237 let mut render_to_device_scale = 1.0;
2238 let mut subregion = used_subregion;
2239 let padded_subregion = match op {
2240 FilterGraphOp::SVGFEGaussianBlur{std_deviation_x, std_deviation_y} |
2241 FilterGraphOp::SVGFEDropShadow{std_deviation_x, std_deviation_y, ..} => {
2242 used_subregion
2243 .inflate(
2244 std_deviation_x.ceil() * BLUR_SAMPLE_SCALE,
2245 std_deviation_y.ceil() * BLUR_SAMPLE_SCALE)
2246 }
2247 _ => used_subregion,
2248 }.union(&combined_input_subregion);
2249 while
2250 padded_subregion.scale(device_to_render_scale, device_to_render_scale).round().width() + node_inflate as f32 * 2.0 > MAX_SURFACE_SIZE as f32 ||
2251 padded_subregion.scale(device_to_render_scale, device_to_render_scale).round().height() + node_inflate as f32 * 2.0 > MAX_SURFACE_SIZE as f32 {
2252 device_to_render_scale *= 0.5;
2253 render_to_device_scale *= 2.0;
2254 subregion = used_subregion
2258 .scale(device_to_render_scale, device_to_render_scale)
2259 .round()
2260 .scale(render_to_device_scale, render_to_device_scale);
2261 }
2262
2263 let node_task_rect: DeviceRect =
2268 subregion
2269 .scale(device_to_render_scale, device_to_render_scale)
2270 .round()
2271 .inflate(node_inflate as f32, node_inflate as f32)
2272 .cast_unit();
2273 let node_task_size = node_task_rect.to_i32().size();
2274 let node_task_size =
2275 if node_task_size.width < 1 || node_task_size.height < 1 {
2276 DeviceIntSize::new(1, 1)
2277 } else {
2278 node_task_size
2279 };
2280
2281 let node_uv_rect_kind = uv_rect_kind_for_task_size(
2284 subregion
2285 .scale(device_to_render_scale, device_to_render_scale)
2286 .round()
2287 .inflate(node_inflate as f32, node_inflate as f32)
2288 .cast_unit(),
2289 prim_subregion
2290 .scale(device_to_render_scale, device_to_render_scale)
2291 .round()
2292 .inflate(node_inflate as f32, node_inflate as f32)
2293 .cast_unit(),
2294 );
2295
2296 let task_id;
2298 match op {
2299 FilterGraphOp::SVGFEGaussianBlur { std_deviation_x, std_deviation_y } => {
2300 assert!(node_inputs.len() == 1);
2308 let blur_input = &node_inputs[0].0;
2309 let source_task_id = node_inputs[0].1;
2310
2311 let adjusted_blur_std_deviation = DeviceSize::new(
2315 std_deviation_x.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
2316 std_deviation_y.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
2317 );
2318 let blur_subregion = blur_input.subregion
2319 .scale(device_to_render_scale, device_to_render_scale)
2320 .inflate(
2321 adjusted_blur_std_deviation.width * BLUR_SAMPLE_SCALE,
2322 adjusted_blur_std_deviation.height * BLUR_SAMPLE_SCALE)
2323 .round_out();
2324 let blur_task_size = blur_subregion
2325 .size()
2326 .cast_unit()
2327 .max(DeviceSize::new(1.0, 1.0));
2328 let adjusted_blur_task_size =
2330 BlurTask::adjusted_blur_source_size(
2331 blur_task_size,
2332 adjusted_blur_std_deviation,
2333 ).max(DeviceSize::new(1.0, 1.0));
2334 let corner = LayoutPoint::new(
2337 blur_subregion.min.x.floor() + ((
2338 blur_task_size.width -
2339 adjusted_blur_task_size.width) * 0.5).floor(),
2340 blur_subregion.min.y.floor() + ((
2341 blur_task_size.height -
2342 adjusted_blur_task_size.height) * 0.5).floor(),
2343 );
2344 let blur_subregion =
2348 LayoutRect::new(
2349 corner,
2350 LayoutPoint::new(
2351 corner.x + adjusted_blur_task_size.width,
2352 corner.y + adjusted_blur_task_size.height,
2353 ),
2354 )
2355 .scale(render_to_device_scale, render_to_device_scale);
2356
2357 let input_subregion_task_id = rg_builder.add().init(RenderTask::new_dynamic(
2358 adjusted_blur_task_size.to_i32(),
2359 RenderTaskKind::SVGFENode(
2360 SVGFEFilterTask{
2361 node: FilterGraphNode{
2362 kept_by_optimizer: true,
2363 linear: false,
2364 inflate: 0,
2365 inputs: [blur_input.clone()].to_vec(),
2366 subregion: blur_subregion,
2367 },
2368 op: FilterGraphOp::SVGFEIdentity,
2369 content_origin: DevicePoint::zero(),
2370 extra_gpu_cache_handle: None,
2371 }
2372 ),
2373 ).with_uv_rect_kind(UvRectKind::Rect));
2374 rg_builder.add_dependency(input_subregion_task_id, source_task_id);
2376
2377 let blur_task_id =
2383 RenderTask::new_blur(
2384 adjusted_blur_std_deviation,
2385 input_subregion_task_id,
2386 rg_builder,
2387 RenderTargetKind::Color,
2388 None,
2389 adjusted_blur_task_size.to_i32(),
2390 BlurEdgeMode::Duplicate,
2391 );
2392
2393 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2394 node_task_size,
2395 RenderTaskKind::SVGFENode(
2396 SVGFEFilterTask{
2397 node: FilterGraphNode{
2398 kept_by_optimizer: true,
2399 linear: node.linear,
2400 inflate: node_inflate,
2401 inputs: [
2402 FilterGraphPictureReference{
2403 buffer_id: blur_input.buffer_id,
2404 subregion: blur_subregion,
2405 inflate: 0,
2406 offset: LayoutVector2D::zero(),
2407 source_padding: LayoutRect::zero(),
2408 target_padding: LayoutRect::zero(),
2409 }].to_vec(),
2410 subregion,
2411 },
2412 op: FilterGraphOp::SVGFEIdentity,
2413 content_origin: node_task_rect.min,
2414 extra_gpu_cache_handle: None,
2415 }
2416 ),
2417 ).with_uv_rect_kind(node_uv_rect_kind));
2418 rg_builder.add_dependency(task_id, blur_task_id);
2420 }
2421 FilterGraphOp::SVGFEDropShadow { color, dx, dy, std_deviation_x, std_deviation_y } => {
2422 assert!(node_inputs.len() == 1);
2430 let blur_input = &node_inputs[0].0;
2431 let source_task_id = node_inputs[0].1;
2432
2433 let adjusted_blur_std_deviation = DeviceSize::new(
2437 std_deviation_x.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
2438 std_deviation_y.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
2439 );
2440 let blur_subregion = blur_input.subregion
2441 .scale(device_to_render_scale, device_to_render_scale)
2442 .inflate(
2443 adjusted_blur_std_deviation.width * BLUR_SAMPLE_SCALE,
2444 adjusted_blur_std_deviation.height * BLUR_SAMPLE_SCALE)
2445 .round_out();
2446 let blur_task_size = blur_subregion
2447 .size()
2448 .cast_unit()
2449 .max(DeviceSize::new(1.0, 1.0));
2450 let adjusted_blur_task_size =
2452 BlurTask::adjusted_blur_source_size(
2453 blur_task_size,
2454 adjusted_blur_std_deviation,
2455 ).max(DeviceSize::new(1.0, 1.0));
2456 let corner = LayoutPoint::new(
2459 blur_subregion.min.x.floor() + ((
2460 blur_task_size.width -
2461 adjusted_blur_task_size.width) * 0.5).floor(),
2462 blur_subregion.min.y.floor() + ((
2463 blur_task_size.height -
2464 adjusted_blur_task_size.height) * 0.5).floor(),
2465 );
2466 let blur_subregion =
2470 LayoutRect::new(
2471 corner,
2472 LayoutPoint::new(
2473 corner.x + adjusted_blur_task_size.width,
2474 corner.y + adjusted_blur_task_size.height,
2475 ),
2476 )
2477 .scale(render_to_device_scale, render_to_device_scale);
2478
2479 let input_subregion_task_id = rg_builder.add().init(RenderTask::new_dynamic(
2480 adjusted_blur_task_size.to_i32(),
2481 RenderTaskKind::SVGFENode(
2482 SVGFEFilterTask{
2483 node: FilterGraphNode{
2484 kept_by_optimizer: true,
2485 linear: false,
2486 inputs: [
2487 FilterGraphPictureReference{
2488 buffer_id: blur_input.buffer_id,
2489 subregion: blur_input.subregion,
2490 offset: LayoutVector2D::zero(),
2491 inflate: blur_input.inflate,
2492 source_padding: LayoutRect::zero(),
2493 target_padding: LayoutRect::zero(),
2494 }].to_vec(),
2495 subregion: blur_subregion,
2496 inflate: 0,
2497 },
2498 op: FilterGraphOp::SVGFEIdentity,
2499 content_origin: node_task_rect.min,
2500 extra_gpu_cache_handle: None,
2501 }
2502 ),
2503 ).with_uv_rect_kind(UvRectKind::Rect));
2504 rg_builder.add_dependency(input_subregion_task_id, source_task_id);
2506
2507 let blur_task_id =
2512 RenderTask::new_blur(
2513 adjusted_blur_std_deviation,
2514 input_subregion_task_id,
2515 rg_builder,
2516 RenderTargetKind::Color,
2517 None,
2518 adjusted_blur_task_size.to_i32(),
2519 BlurEdgeMode::Duplicate,
2520 );
2521
2522 let blur_subregion_translated = blur_subregion
2525 .translate(LayoutVector2D::new(dx, dy));
2526 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2527 node_task_size,
2528 RenderTaskKind::SVGFENode(
2529 SVGFEFilterTask{
2530 node: FilterGraphNode{
2531 kept_by_optimizer: true,
2532 linear: node.linear,
2533 inflate: node_inflate,
2534 inputs: [
2535 *blur_input,
2537 FilterGraphPictureReference{
2539 buffer_id: blur_input.buffer_id,
2540 subregion: blur_subregion_translated,
2541 inflate: 0,
2542 offset: LayoutVector2D::zero(),
2543 source_padding: LayoutRect::zero(),
2544 target_padding: LayoutRect::zero(),
2545 }].to_vec(),
2546 subregion,
2547 },
2548 op: FilterGraphOp::SVGFEDropShadow{
2549 color,
2550 dx: 0.0, dy: 0.0,
2552 std_deviation_x: 0.0, std_deviation_y: 0.0,
2553 },
2554 content_origin: node_task_rect.min,
2555 extra_gpu_cache_handle: None,
2556 }
2557 ),
2558 ).with_uv_rect_kind(node_uv_rect_kind));
2559 rg_builder.add_dependency(task_id, source_task_id);
2561 rg_builder.add_dependency(task_id, blur_task_id);
2562 }
2563 FilterGraphOp::SVGFESourceAlpha |
2564 FilterGraphOp::SVGFESourceGraphic => {
2565 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2570 node_task_size,
2571 RenderTaskKind::SVGFENode(
2572 SVGFEFilterTask{
2573 node: FilterGraphNode{
2574 kept_by_optimizer: true,
2575 linear: node.linear,
2576 inflate: node_inflate,
2577 inputs: [
2578 FilterGraphPictureReference{
2579 buffer_id: FilterOpGraphPictureBufferId::None,
2580 subregion: source_subregion.cast_unit(),
2583 offset: LayoutVector2D::zero(),
2584 inflate: 0,
2585 source_padding: LayoutRect::zero(),
2586 target_padding: LayoutRect::zero(),
2587 }
2588 ].to_vec(),
2589 subregion: source_subregion.cast_unit(),
2590 },
2591 op: op.clone(),
2592 content_origin: source_subregion.min.cast_unit(),
2593 extra_gpu_cache_handle: None,
2594 }
2595 ),
2596 ).with_uv_rect_kind(node_uv_rect_kind));
2597 rg_builder.add_dependency(task_id, original_task_id);
2598 made_dependency_on_source = true;
2599 }
2600 FilterGraphOp::SVGFEComponentTransferInterned { handle, creates_pixels: _ } => {
2601 let filter_data = &mut data_stores.filter_data[handle];
2604 filter_data.update(gpu_cache);
2605 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2608 node_task_size,
2609 RenderTaskKind::SVGFENode(
2610 SVGFEFilterTask{
2611 node: FilterGraphNode{
2612 kept_by_optimizer: true,
2613 linear: node.linear,
2614 inputs: node_inputs.iter().map(|input| {input.0}).collect(),
2615 subregion,
2616 inflate: node_inflate,
2617 },
2618 op: op.clone(),
2619 content_origin: node_task_rect.min,
2620 extra_gpu_cache_handle: Some(filter_data.gpu_cache_handle),
2621 }
2622 ),
2623 ).with_uv_rect_kind(node_uv_rect_kind));
2624
2625 for (_input, input_task) in &node_inputs {
2628 if *input_task == original_task_id {
2629 made_dependency_on_source = true;
2630 }
2631 if *input_task != RenderTaskId::INVALID {
2632 rg_builder.add_dependency(task_id, *input_task);
2633 }
2634 }
2635 }
2636 _ => {
2637 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2640 node_task_size,
2641 RenderTaskKind::SVGFENode(
2642 SVGFEFilterTask{
2643 node: FilterGraphNode{
2644 kept_by_optimizer: true,
2645 linear: node.linear,
2646 inputs: node_inputs.iter().map(|input| {input.0}).collect(),
2647 subregion,
2648 inflate: node_inflate,
2649 },
2650 op: op.clone(),
2651 content_origin: node_task_rect.min,
2652 extra_gpu_cache_handle: None,
2653 }
2654 ),
2655 ).with_uv_rect_kind(node_uv_rect_kind));
2656
2657 for (_input, input_task) in &node_inputs {
2660 if *input_task == original_task_id {
2661 made_dependency_on_source = true;
2662 }
2663 if *input_task != RenderTaskId::INVALID {
2664 rg_builder.add_dependency(task_id, *input_task);
2665 }
2666 }
2667 }
2668 }
2669
2670 task_by_buffer_id[filter_index] = task_id;
2674 subregion_by_buffer_id[filter_index] = subregion;
2675
2676 output_task_id = task_id;
2678 }
2679
2680 if !made_dependency_on_source && output_task_id != original_task_id {
2683 rg_builder.add_dependency(output_task_id, original_task_id);
2684 }
2685
2686 output_task_id
2687 }
2688
2689 pub fn uv_rect_kind(&self) -> UvRectKind {
2690 self.uv_rect_kind
2691 }
2692
2693 pub fn get_texture_address(&self, gpu_cache: &GpuCache) -> GpuCacheAddress {
2694 gpu_cache.get_address(&self.uv_rect_handle)
2695 }
2696
2697 pub fn get_target_texture(&self) -> CacheTextureId {
2698 match self.location {
2699 RenderTaskLocation::Dynamic { texture_id, .. } => {
2700 assert_ne!(texture_id, CacheTextureId::INVALID);
2701 texture_id
2702 }
2703 RenderTaskLocation::Static { surface: StaticRenderTaskSurface::TextureCache { texture, .. }, .. } => {
2704 texture
2705 }
2706 _ => {
2707 unreachable!();
2708 }
2709 }
2710 }
2711
2712 pub fn get_texture_source(&self) -> TextureSource {
2713 match self.location {
2714 RenderTaskLocation::Dynamic { texture_id, .. } => {
2715 assert_ne!(texture_id, CacheTextureId::INVALID);
2716 TextureSource::TextureCache(texture_id, Swizzle::default())
2717 }
2718 RenderTaskLocation::Static { surface: StaticRenderTaskSurface::ReadOnly { source }, .. } => {
2719 source
2720 }
2721 RenderTaskLocation::Static { surface: StaticRenderTaskSurface::TextureCache { texture, .. }, .. } => {
2722 TextureSource::TextureCache(texture, Swizzle::default())
2723 }
2724 RenderTaskLocation::Existing { .. } |
2725 RenderTaskLocation::Static { .. } |
2726 RenderTaskLocation::CacheRequest { .. } |
2727 RenderTaskLocation::Unallocated { .. } => {
2728 unreachable!();
2729 }
2730 }
2731 }
2732
2733 pub fn get_target_rect(&self) -> DeviceIntRect {
2734 match self.location {
2735 RenderTaskLocation::Dynamic { rect, .. } => rect,
2750 RenderTaskLocation::Static { rect, .. } => rect,
2751 RenderTaskLocation::Existing { .. } |
2752 RenderTaskLocation::CacheRequest { .. } |
2753 RenderTaskLocation::Unallocated { .. } => {
2754 panic!("bug: get_target_rect called before allocating");
2755 }
2756 }
2757 }
2758
2759 pub fn get_target_size(&self) -> DeviceIntSize {
2760 match self.location {
2761 RenderTaskLocation::Dynamic { rect, .. } => rect.size(),
2762 RenderTaskLocation::Static { rect, .. } => rect.size(),
2763 RenderTaskLocation::Existing { size, .. } => size,
2764 RenderTaskLocation::CacheRequest { size } => size,
2765 RenderTaskLocation::Unallocated { size } => size,
2766 }
2767 }
2768
2769 pub fn target_kind(&self) -> RenderTargetKind {
2770 self.kind.target_kind()
2771 }
2772
2773 pub fn write_gpu_blocks(
2774 &mut self,
2775 target_rect: DeviceIntRect,
2776 gpu_cache: &mut GpuCache,
2777 ) {
2778 profile_scope!("write_gpu_blocks");
2779
2780 self.kind.write_gpu_blocks(gpu_cache);
2781
2782 if self.cache_handle.is_some() {
2783 return;
2786 }
2787
2788 if let Some(mut request) = gpu_cache.request(&mut self.uv_rect_handle) {
2789 let p0 = target_rect.min.to_f32();
2790 let p1 = target_rect.max.to_f32();
2791 let image_source = ImageSource {
2792 p0,
2793 p1,
2794 user_data: [0.0; 4],
2795 uv_rect_kind: self.uv_rect_kind,
2796 };
2797 image_source.write_gpu_blocks(&mut request);
2798 }
2799 }
2800
2801 pub fn mark_cached(&mut self, handle: RenderTaskCacheEntryHandle) {
2806 self.cache_handle = Some(handle);
2807 }
2808}