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 crate::box_shadow::BLUR_SAMPLE_SCALE;
10use crate::clip::{ClipDataStore, ClipItemKind, ClipStore, ClipNodeRange};
11use crate::command_buffer::{CommandBufferIndex, QuadFlags};
12use crate::pattern::{PatternKind, PatternShaderInput};
13use crate::spatial_tree::SpatialNodeIndex;
14use crate::filterdata::SFilterData;
15use crate::frame_builder::FrameBuilderConfig;
16use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
17use crate::gpu_types::{BorderInstance, ImageSource, UvRectKind, TransformPaletteId};
18use crate::internal_types::{CacheTextureId, FastHashMap, FilterGraphNode, FilterGraphOp, FilterGraphPictureReference, SVGFE_CONVOLVE_VALUES_LIMIT, TextureSource, Swizzle};
19use crate::picture::{ResolvedSurfaceTexture, MAX_SURFACE_SIZE};
20use crate::prim_store::ClipData;
21use crate::prim_store::gradient::{
22 FastLinearGradientTask, RadialGradientTask,
23 ConicGradientTask, LinearGradientTask,
24};
25use crate::resource_cache::{ResourceCache, ImageRequest};
26use std::{usize, f32, i32, u32};
27use crate::renderer::{GpuBufferAddress, GpuBufferBuilderF};
28use crate::render_backend::DataStores;
29use crate::render_target::{ResolveOp, RenderTargetKind};
30use crate::render_task_graph::{PassId, RenderTaskId, RenderTaskGraphBuilder};
31use crate::render_task_cache::{RenderTaskCacheEntryHandle, RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskParent};
32use crate::segment::EdgeAaSegmentMask;
33use crate::surface::SurfaceBuilder;
34use smallvec::SmallVec;
35
36const FLOATS_PER_RENDER_TASK_INFO: usize = 8;
37pub const MAX_BLUR_STD_DEVIATION: f32 = 4.0;
38pub const MIN_DOWNSCALING_RT_SIZE: i32 = 8;
39
40fn render_task_sanity_check(size: &DeviceIntSize) {
41 if size.width > MAX_RENDER_TASK_SIZE ||
42 size.height > MAX_RENDER_TASK_SIZE {
43 error!("Attempting to create a render task of size {}x{}", size.width, size.height);
44 panic!();
45 }
46}
47
48#[derive(Debug, Copy, Clone, PartialEq)]
49#[repr(C)]
50#[cfg_attr(feature = "capture", derive(Serialize))]
51#[cfg_attr(feature = "replay", derive(Deserialize))]
52pub struct RenderTaskAddress(pub i32);
53
54impl Into<RenderTaskAddress> for RenderTaskId {
55 fn into(self) -> RenderTaskAddress {
56 RenderTaskAddress(self.index as i32)
57 }
58}
59
60#[derive(Clone, Debug, Eq, PartialEq, Hash)]
63#[cfg_attr(feature = "capture", derive(Serialize))]
64#[cfg_attr(feature = "replay", derive(Deserialize))]
65pub enum StaticRenderTaskSurface {
66 TextureCache {
69 texture: CacheTextureId,
71 target_kind: RenderTargetKind,
73 },
74 ReadOnly {
77 source: TextureSource,
78 },
79 PictureCache {
82 surface: ResolvedSurfaceTexture,
84 },
85}
86
87#[derive(Clone, Debug)]
89#[cfg_attr(feature = "capture", derive(Serialize))]
90#[cfg_attr(feature = "replay", derive(Deserialize))]
91pub enum RenderTaskLocation {
92 Unallocated {
97 size: DeviceIntSize,
99 },
100 CacheRequest {
102 size: DeviceIntSize,
103 },
104 Existing {
106 parent_task_id: RenderTaskId,
107 size: DeviceIntSize,
109 },
110
111 Dynamic {
117 texture_id: CacheTextureId,
119 rect: DeviceIntRect,
121 },
122 Static {
124 surface: StaticRenderTaskSurface,
126 rect: DeviceIntRect,
128 },
129}
130
131impl RenderTaskLocation {
132 pub fn is_dynamic(&self) -> bool {
134 match *self {
135 RenderTaskLocation::Dynamic { .. } => true,
136 _ => false,
137 }
138 }
139
140 pub fn size(&self) -> DeviceIntSize {
141 match self {
142 RenderTaskLocation::Unallocated { size } => *size,
143 RenderTaskLocation::Dynamic { rect, .. } => rect.size(),
144 RenderTaskLocation::Static { rect, .. } => rect.size(),
145 RenderTaskLocation::CacheRequest { size } => *size,
146 RenderTaskLocation::Existing { size, .. } => *size,
147 }
148 }
149}
150
151#[derive(Debug)]
152#[cfg_attr(feature = "capture", derive(Serialize))]
153#[cfg_attr(feature = "replay", derive(Deserialize))]
154pub struct CachedTask {
155 pub target_kind: RenderTargetKind,
156}
157
158#[derive(Debug)]
159#[cfg_attr(feature = "capture", derive(Serialize))]
160#[cfg_attr(feature = "replay", derive(Deserialize))]
161pub struct CacheMaskTask {
162 pub actual_rect: DeviceRect,
163 pub root_spatial_node_index: SpatialNodeIndex,
164 pub clip_node_range: ClipNodeRange,
165 pub device_pixel_scale: DevicePixelScale,
166 pub clear_to_one: bool,
167}
168
169#[derive(Debug)]
170#[cfg_attr(feature = "capture", derive(Serialize))]
171#[cfg_attr(feature = "replay", derive(Deserialize))]
172pub struct ClipRegionTask {
173 pub local_pos: LayoutPoint,
174 pub device_pixel_scale: DevicePixelScale,
175 pub clip_data: ClipData,
176 pub clear_to_one: bool,
177}
178
179#[cfg_attr(feature = "capture", derive(Serialize))]
180#[cfg_attr(feature = "replay", derive(Deserialize))]
181pub struct EmptyTask {
182 pub content_origin: DevicePoint,
183 pub device_pixel_scale: DevicePixelScale,
184 pub raster_spatial_node_index: SpatialNodeIndex,
185}
186
187#[cfg_attr(feature = "capture", derive(Serialize))]
188#[cfg_attr(feature = "replay", derive(Deserialize))]
189pub struct PrimTask {
190 pub pattern: PatternKind,
191 pub pattern_input: PatternShaderInput,
192 pub device_pixel_scale: DevicePixelScale,
193 pub content_origin: DevicePoint,
194 pub prim_address_f: GpuBufferAddress,
195 pub raster_spatial_node_index: SpatialNodeIndex,
196 pub transform_id: TransformPaletteId,
197 pub edge_flags: EdgeAaSegmentMask,
198 pub quad_flags: QuadFlags,
199 pub prim_needs_scissor_rect: bool,
200 pub texture_input: RenderTaskId,
201}
202
203#[cfg_attr(feature = "capture", derive(Serialize))]
204#[cfg_attr(feature = "replay", derive(Deserialize))]
205pub struct TileCompositeTask {
206 pub clear_color: ColorF,
207 pub scissor_rect: DeviceIntRect,
208 pub valid_rect: DeviceIntRect,
209 pub task_id: Option<RenderTaskId>,
210 pub sub_rect_offset: DeviceIntVector2D,
211}
212
213#[cfg_attr(feature = "capture", derive(Serialize))]
214#[cfg_attr(feature = "replay", derive(Deserialize))]
215pub struct PictureTask {
216 pub can_merge: bool,
217 pub content_origin: DevicePoint,
218 pub surface_spatial_node_index: SpatialNodeIndex,
219 pub raster_spatial_node_index: SpatialNodeIndex,
220 pub device_pixel_scale: DevicePixelScale,
221 pub clear_color: Option<ColorF>,
222 pub scissor_rect: Option<DeviceIntRect>,
223 pub valid_rect: Option<DeviceIntRect>,
224 pub cmd_buffer_index: CommandBufferIndex,
225 pub resolve_op: Option<ResolveOp>,
226
227 pub can_use_shared_surface: bool,
228}
229
230impl PictureTask {
231 pub fn duplicate(
236 &self,
237 cmd_buffer_index: CommandBufferIndex,
238 ) -> Self {
239 assert_eq!(self.resolve_op, None);
240
241 PictureTask {
242 clear_color: None,
243 cmd_buffer_index,
244 resolve_op: None,
245 can_use_shared_surface: false,
246 ..*self
247 }
248 }
249}
250
251#[derive(Debug)]
252#[cfg_attr(feature = "capture", derive(Serialize))]
253#[cfg_attr(feature = "replay", derive(Deserialize))]
254pub struct BlurTask {
255 pub blur_std_deviation: f32,
256 pub target_kind: RenderTargetKind,
257 pub blur_region: DeviceIntSize,
258}
259
260impl BlurTask {
261 pub fn adjusted_blur_source_size(original_size: DeviceSize, mut std_dev: DeviceSize) -> DeviceIntSize {
265 let mut adjusted_size = original_size;
266 let mut scale_factor = 1.0;
267 while std_dev.width > MAX_BLUR_STD_DEVIATION && std_dev.height > MAX_BLUR_STD_DEVIATION {
268 if adjusted_size.width < MIN_DOWNSCALING_RT_SIZE as f32 ||
269 adjusted_size.height < MIN_DOWNSCALING_RT_SIZE as f32 {
270 break;
271 }
272 std_dev = std_dev * 0.5;
273 scale_factor *= 2.0;
274 adjusted_size = (original_size.to_f32() / scale_factor).ceil();
275 }
276
277 (adjusted_size * scale_factor).round().to_i32()
278 }
279}
280
281#[derive(Debug)]
282#[cfg_attr(feature = "capture", derive(Serialize))]
283#[cfg_attr(feature = "replay", derive(Deserialize))]
284pub struct ScalingTask {
285 pub target_kind: RenderTargetKind,
286 pub padding: DeviceIntSideOffsets,
287}
288
289#[derive(Debug)]
290#[cfg_attr(feature = "capture", derive(Serialize))]
291#[cfg_attr(feature = "replay", derive(Deserialize))]
292pub struct BorderTask {
293 pub instances: Vec<BorderInstance>,
294}
295
296#[derive(Debug)]
297#[cfg_attr(feature = "capture", derive(Serialize))]
298#[cfg_attr(feature = "replay", derive(Deserialize))]
299pub struct BlitTask {
300 pub source: RenderTaskId,
301 pub source_rect: DeviceIntRect,
303}
304
305#[derive(Debug)]
306#[cfg_attr(feature = "capture", derive(Serialize))]
307#[cfg_attr(feature = "replay", derive(Deserialize))]
308pub struct LineDecorationTask {
309 pub wavy_line_thickness: f32,
310 pub style: LineStyle,
311 pub orientation: LineOrientation,
312 pub local_size: LayoutSize,
313}
314
315#[derive(Debug)]
316#[cfg_attr(feature = "capture", derive(Serialize))]
317#[cfg_attr(feature = "replay", derive(Deserialize))]
318pub enum SvgFilterInfo {
319 Blend(MixBlendMode),
320 Flood(ColorF),
321 LinearToSrgb,
322 SrgbToLinear,
323 Opacity(f32),
324 ColorMatrix(Box<[f32; 20]>),
325 DropShadow(ColorF),
326 Offset(DeviceVector2D),
327 ComponentTransfer(SFilterData),
328 Composite(CompositeOperator),
329 Identity,
331}
332
333#[derive(Debug)]
334#[cfg_attr(feature = "capture", derive(Serialize))]
335#[cfg_attr(feature = "replay", derive(Deserialize))]
336pub struct SvgFilterTask {
337 pub info: SvgFilterInfo,
338 pub extra_gpu_cache_handle: Option<GpuCacheHandle>,
339}
340
341#[derive(Debug)]
342#[cfg_attr(feature = "capture", derive(Serialize))]
343#[cfg_attr(feature = "replay", derive(Deserialize))]
344pub struct SVGFEFilterTask {
345 pub node: FilterGraphNode,
346 pub op: FilterGraphOp,
347 pub content_origin: DevicePoint,
348 pub extra_gpu_cache_handle: Option<GpuCacheHandle>,
349}
350
351#[cfg_attr(feature = "capture", derive(Serialize))]
352#[cfg_attr(feature = "replay", derive(Deserialize))]
353pub struct ReadbackTask {
354 pub readback_origin: Option<DevicePoint>,
359}
360
361#[derive(Debug)]
362#[cfg_attr(feature = "capture", derive(Serialize))]
363#[cfg_attr(feature = "replay", derive(Deserialize))]
364pub struct RenderTaskData {
365 pub data: [f32; FLOATS_PER_RENDER_TASK_INFO],
366}
367
368#[cfg_attr(feature = "capture", derive(Serialize))]
369#[cfg_attr(feature = "replay", derive(Deserialize))]
370pub enum RenderTaskKind {
371 Image(ImageRequest),
372 Cached(CachedTask),
373 Picture(PictureTask),
374 CacheMask(CacheMaskTask),
375 ClipRegion(ClipRegionTask),
376 VerticalBlur(BlurTask),
377 HorizontalBlur(BlurTask),
378 Readback(ReadbackTask),
379 Scaling(ScalingTask),
380 Blit(BlitTask),
381 Border(BorderTask),
382 LineDecoration(LineDecorationTask),
383 FastLinearGradient(FastLinearGradientTask),
384 LinearGradient(LinearGradientTask),
385 RadialGradient(RadialGradientTask),
386 ConicGradient(ConicGradientTask),
387 SvgFilter(SvgFilterTask),
388 SVGFENode(SVGFEFilterTask),
389 TileComposite(TileCompositeTask),
390 Prim(PrimTask),
391 Empty(EmptyTask),
392 #[cfg(test)]
393 Test(RenderTargetKind),
394}
395
396impl RenderTaskKind {
397 pub fn is_a_rendering_operation(&self) -> bool {
398 match self {
399 &RenderTaskKind::Image(..) => false,
400 &RenderTaskKind::Cached(..) => false,
401 _ => true,
402 }
403 }
404
405 pub fn can_use_shared_surface(&self) -> bool {
407 match self {
408 &RenderTaskKind::Picture(ref info) => info.can_use_shared_surface,
409 _ => true,
410 }
411 }
412
413 pub fn should_advance_pass(&self) -> bool {
414 match self {
415 &RenderTaskKind::Image(..) => false,
416 &RenderTaskKind::Cached(..) => false,
417 _ => true,
418 }
419 }
420
421 pub fn as_str(&self) -> &'static str {
422 match *self {
423 RenderTaskKind::Image(..) => "Image",
424 RenderTaskKind::Cached(..) => "Cached",
425 RenderTaskKind::Picture(..) => "Picture",
426 RenderTaskKind::CacheMask(..) => "CacheMask",
427 RenderTaskKind::ClipRegion(..) => "ClipRegion",
428 RenderTaskKind::VerticalBlur(..) => "VerticalBlur",
429 RenderTaskKind::HorizontalBlur(..) => "HorizontalBlur",
430 RenderTaskKind::Readback(..) => "Readback",
431 RenderTaskKind::Scaling(..) => "Scaling",
432 RenderTaskKind::Blit(..) => "Blit",
433 RenderTaskKind::Border(..) => "Border",
434 RenderTaskKind::LineDecoration(..) => "LineDecoration",
435 RenderTaskKind::FastLinearGradient(..) => "FastLinearGradient",
436 RenderTaskKind::LinearGradient(..) => "LinearGradient",
437 RenderTaskKind::RadialGradient(..) => "RadialGradient",
438 RenderTaskKind::ConicGradient(..) => "ConicGradient",
439 RenderTaskKind::SvgFilter(..) => "SvgFilter",
440 RenderTaskKind::SVGFENode(..) => "SVGFENode",
441 RenderTaskKind::TileComposite(..) => "TileComposite",
442 RenderTaskKind::Prim(..) => "Prim",
443 RenderTaskKind::Empty(..) => "Empty",
444 #[cfg(test)]
445 RenderTaskKind::Test(..) => "Test",
446 }
447 }
448
449 pub fn target_kind(&self) -> RenderTargetKind {
450 match *self {
451 RenderTaskKind::Image(..) |
452 RenderTaskKind::LineDecoration(..) |
453 RenderTaskKind::Readback(..) |
454 RenderTaskKind::Border(..) |
455 RenderTaskKind::FastLinearGradient(..) |
456 RenderTaskKind::LinearGradient(..) |
457 RenderTaskKind::RadialGradient(..) |
458 RenderTaskKind::ConicGradient(..) |
459 RenderTaskKind::Picture(..) |
460 RenderTaskKind::Blit(..) |
461 RenderTaskKind::TileComposite(..) |
462 RenderTaskKind::Prim(..) |
463 RenderTaskKind::SvgFilter(..) => {
464 RenderTargetKind::Color
465 }
466 RenderTaskKind::SVGFENode(..) => {
467 RenderTargetKind::Color
468 }
469
470 RenderTaskKind::ClipRegion(..) |
471 RenderTaskKind::CacheMask(..) |
472 RenderTaskKind::Empty(..) => {
473 RenderTargetKind::Alpha
474 }
475
476 RenderTaskKind::VerticalBlur(ref task_info) |
477 RenderTaskKind::HorizontalBlur(ref task_info) => {
478 task_info.target_kind
479 }
480
481 RenderTaskKind::Scaling(ref task_info) => {
482 task_info.target_kind
483 }
484
485 RenderTaskKind::Cached(ref task_info) => {
486 task_info.target_kind
487 }
488
489 #[cfg(test)]
490 RenderTaskKind::Test(kind) => kind,
491 }
492 }
493
494 pub fn new_tile_composite(
495 sub_rect_offset: DeviceIntVector2D,
496 scissor_rect: DeviceIntRect,
497 valid_rect: DeviceIntRect,
498 clear_color: ColorF,
499 ) -> Self {
500 RenderTaskKind::TileComposite(TileCompositeTask {
501 task_id: None,
502 sub_rect_offset,
503 scissor_rect,
504 valid_rect,
505 clear_color,
506 })
507 }
508
509 pub fn new_picture(
510 size: DeviceIntSize,
511 needs_scissor_rect: bool,
512 content_origin: DevicePoint,
513 surface_spatial_node_index: SpatialNodeIndex,
514 raster_spatial_node_index: SpatialNodeIndex,
515 device_pixel_scale: DevicePixelScale,
516 scissor_rect: Option<DeviceIntRect>,
517 valid_rect: Option<DeviceIntRect>,
518 clear_color: Option<ColorF>,
519 cmd_buffer_index: CommandBufferIndex,
520 can_use_shared_surface: bool,
521 ) -> Self {
522 render_task_sanity_check(&size);
523
524 RenderTaskKind::Picture(PictureTask {
525 content_origin,
526 can_merge: !needs_scissor_rect,
527 surface_spatial_node_index,
528 raster_spatial_node_index,
529 device_pixel_scale,
530 scissor_rect,
531 valid_rect,
532 clear_color,
533 cmd_buffer_index,
534 resolve_op: None,
535 can_use_shared_surface,
536 })
537 }
538
539 pub fn new_prim(
540 pattern: PatternKind,
541 pattern_input: PatternShaderInput,
542 raster_spatial_node_index: SpatialNodeIndex,
543 device_pixel_scale: DevicePixelScale,
544 content_origin: DevicePoint,
545 prim_address_f: GpuBufferAddress,
546 transform_id: TransformPaletteId,
547 edge_flags: EdgeAaSegmentMask,
548 quad_flags: QuadFlags,
549 prim_needs_scissor_rect: bool,
550 texture_input: RenderTaskId,
551 ) -> Self {
552 RenderTaskKind::Prim(PrimTask {
553 pattern,
554 pattern_input,
555 raster_spatial_node_index,
556 device_pixel_scale,
557 content_origin,
558 prim_address_f,
559 transform_id,
560 edge_flags,
561 quad_flags,
562 prim_needs_scissor_rect,
563 texture_input,
564 })
565 }
566
567 pub fn new_readback(
568 readback_origin: Option<DevicePoint>,
569 ) -> Self {
570 RenderTaskKind::Readback(
571 ReadbackTask {
572 readback_origin,
573 }
574 )
575 }
576
577 pub fn new_line_decoration(
578 style: LineStyle,
579 orientation: LineOrientation,
580 wavy_line_thickness: f32,
581 local_size: LayoutSize,
582 ) -> Self {
583 RenderTaskKind::LineDecoration(LineDecorationTask {
584 style,
585 orientation,
586 wavy_line_thickness,
587 local_size,
588 })
589 }
590
591 pub fn new_border_segment(
592 instances: Vec<BorderInstance>,
593 ) -> Self {
594 RenderTaskKind::Border(BorderTask {
595 instances,
596 })
597 }
598
599 pub fn new_rounded_rect_mask(
600 local_pos: LayoutPoint,
601 clip_data: ClipData,
602 device_pixel_scale: DevicePixelScale,
603 fb_config: &FrameBuilderConfig,
604 ) -> Self {
605 RenderTaskKind::ClipRegion(ClipRegionTask {
606 local_pos,
607 device_pixel_scale,
608 clip_data,
609 clear_to_one: fb_config.gpu_supports_fast_clears,
610 })
611 }
612
613 pub fn new_mask(
614 outer_rect: DeviceIntRect,
615 clip_node_range: ClipNodeRange,
616 root_spatial_node_index: SpatialNodeIndex,
617 clip_store: &mut ClipStore,
618 gpu_cache: &mut GpuCache,
619 gpu_buffer_builder: &mut GpuBufferBuilderF,
620 resource_cache: &mut ResourceCache,
621 rg_builder: &mut RenderTaskGraphBuilder,
622 clip_data_store: &mut ClipDataStore,
623 device_pixel_scale: DevicePixelScale,
624 fb_config: &FrameBuilderConfig,
625 surface_builder: &mut SurfaceBuilder,
626 ) -> RenderTaskId {
627 let task_size = outer_rect.size();
637
638 let clip_task_id = rg_builder.add().init(
643 RenderTask::new_dynamic(
644 task_size,
645 RenderTaskKind::CacheMask(CacheMaskTask {
646 actual_rect: outer_rect.to_f32(),
647 clip_node_range,
648 root_spatial_node_index,
649 device_pixel_scale,
650 clear_to_one: fb_config.gpu_supports_fast_clears,
651 }),
652 )
653 );
654
655 for i in 0 .. clip_node_range.count {
656 let clip_instance = clip_store.get_instance_from_range(&clip_node_range, i);
657 let clip_node = &mut clip_data_store[clip_instance.handle];
658 match clip_node.item.kind {
659 ClipItemKind::BoxShadow { ref mut source } => {
660 let (cache_size, cache_key) = source.cache_key
661 .as_ref()
662 .expect("bug: no cache key set")
663 .clone();
664 let blur_radius_dp = cache_key.blur_radius_dp as f32;
665 let device_pixel_scale = DevicePixelScale::new(cache_key.device_pixel_scale.to_f32_px());
666
667 source.render_task = Some(resource_cache.request_render_task(
670 Some(RenderTaskCacheKey {
671 size: cache_size,
672 kind: RenderTaskCacheKeyKind::BoxShadow(cache_key),
673 }),
674 false,
675 RenderTaskParent::RenderTask(clip_task_id),
676 gpu_cache,
677 gpu_buffer_builder,
678 rg_builder,
679 surface_builder,
680 &mut |rg_builder, _, _| {
681 let clip_data = ClipData::rounded_rect(
682 source.minimal_shadow_rect.size(),
683 &source.shadow_radius,
684 ClipMode::Clip,
685 );
686
687 let mask_task_id = rg_builder.add().init(RenderTask::new_dynamic(
689 cache_size,
690 RenderTaskKind::new_rounded_rect_mask(
691 source.minimal_shadow_rect.min,
692 clip_data,
693 device_pixel_scale,
694 fb_config,
695 ),
696 ));
697
698 RenderTask::new_blur(
700 DeviceSize::new(blur_radius_dp, blur_radius_dp),
701 mask_task_id,
702 rg_builder,
703 RenderTargetKind::Alpha,
704 None,
705 cache_size,
706 )
707 }
708 ));
709 }
710 ClipItemKind::Rectangle { .. } |
711 ClipItemKind::RoundedRectangle { .. } |
712 ClipItemKind::Image { .. } => {}
713 }
714 }
715
716 clip_task_id
717 }
718
719 pub fn write_task_data(
723 &self,
724 target_rect: DeviceIntRect,
725 ) -> RenderTaskData {
726 let data = match self {
735 RenderTaskKind::Picture(ref task) => {
736 [
738 task.device_pixel_scale.0,
739 task.content_origin.x,
740 task.content_origin.y,
741 0.0,
742 ]
743 }
744 RenderTaskKind::Prim(ref task) => {
745 [
746 task.device_pixel_scale.0,
748 task.content_origin.x,
749 task.content_origin.y,
750 0.0,
751 ]
752 }
753 RenderTaskKind::Empty(ref task) => {
754 [
755 task.device_pixel_scale.0,
757 task.content_origin.x,
758 task.content_origin.y,
759 0.0,
760 ]
761 }
762 RenderTaskKind::CacheMask(ref task) => {
763 [
764 task.device_pixel_scale.0,
765 task.actual_rect.min.x,
766 task.actual_rect.min.y,
767 0.0,
768 ]
769 }
770 RenderTaskKind::ClipRegion(ref task) => {
771 [
772 task.device_pixel_scale.0,
773 0.0,
774 0.0,
775 0.0,
776 ]
777 }
778 RenderTaskKind::VerticalBlur(_) |
779 RenderTaskKind::HorizontalBlur(_) => {
780 [
783 0.0,
784 0.0,
785 0.0,
786 0.0,
787 ]
788 }
789 RenderTaskKind::Image(..) |
790 RenderTaskKind::Cached(..) |
791 RenderTaskKind::Readback(..) |
792 RenderTaskKind::Scaling(..) |
793 RenderTaskKind::Border(..) |
794 RenderTaskKind::LineDecoration(..) |
795 RenderTaskKind::FastLinearGradient(..) |
796 RenderTaskKind::LinearGradient(..) |
797 RenderTaskKind::RadialGradient(..) |
798 RenderTaskKind::ConicGradient(..) |
799 RenderTaskKind::TileComposite(..) |
800 RenderTaskKind::Blit(..) => {
801 [0.0; 4]
802 }
803
804 RenderTaskKind::SvgFilter(ref task) => {
805 match task.info {
806 SvgFilterInfo::Opacity(opacity) => [opacity, 0.0, 0.0, 0.0],
807 SvgFilterInfo::Offset(offset) => [offset.x, offset.y, 0.0, 0.0],
808 _ => [0.0; 4]
809 }
810 }
811 RenderTaskKind::SVGFENode(_task) => {
812 [0.0; 4]
815 }
816
817 #[cfg(test)]
818 RenderTaskKind::Test(..) => {
819 [0.0; 4]
820 }
821 };
822
823 RenderTaskData {
824 data: [
825 target_rect.min.x as f32,
826 target_rect.min.y as f32,
827 target_rect.max.x as f32,
828 target_rect.max.y as f32,
829 data[0],
830 data[1],
831 data[2],
832 data[3],
833 ]
834 }
835 }
836
837 pub fn write_gpu_blocks(
838 &mut self,
839 gpu_cache: &mut GpuCache,
840 ) {
841 match self {
842 RenderTaskKind::SvgFilter(ref mut filter_task) => {
843 match filter_task.info {
844 SvgFilterInfo::ColorMatrix(ref matrix) => {
845 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
846 if let Some(mut request) = gpu_cache.request(handle) {
847 for i in 0..5 {
848 request.push([matrix[i*4], matrix[i*4+1], matrix[i*4+2], matrix[i*4+3]]);
849 }
850 }
851 }
852 SvgFilterInfo::DropShadow(color) |
853 SvgFilterInfo::Flood(color) => {
854 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
855 if let Some(mut request) = gpu_cache.request(handle) {
856 request.push(color.to_array());
857 }
858 }
859 SvgFilterInfo::ComponentTransfer(ref data) => {
860 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
861 if let Some(request) = gpu_cache.request(handle) {
862 data.update(request);
863 }
864 }
865 SvgFilterInfo::Composite(ref operator) => {
866 if let CompositeOperator::Arithmetic(k_vals) = operator {
867 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
868 if let Some(mut request) = gpu_cache.request(handle) {
869 request.push(*k_vals);
870 }
871 }
872 }
873 _ => {},
874 }
875 }
876 RenderTaskKind::SVGFENode(ref mut filter_task) => {
877 match filter_task.op {
878 FilterGraphOp::SVGFEBlendDarken => {}
879 FilterGraphOp::SVGFEBlendLighten => {}
880 FilterGraphOp::SVGFEBlendMultiply => {}
881 FilterGraphOp::SVGFEBlendNormal => {}
882 FilterGraphOp::SVGFEBlendScreen => {}
883 FilterGraphOp::SVGFEBlendOverlay => {}
884 FilterGraphOp::SVGFEBlendColorDodge => {}
885 FilterGraphOp::SVGFEBlendColorBurn => {}
886 FilterGraphOp::SVGFEBlendHardLight => {}
887 FilterGraphOp::SVGFEBlendSoftLight => {}
888 FilterGraphOp::SVGFEBlendDifference => {}
889 FilterGraphOp::SVGFEBlendExclusion => {}
890 FilterGraphOp::SVGFEBlendHue => {}
891 FilterGraphOp::SVGFEBlendSaturation => {}
892 FilterGraphOp::SVGFEBlendColor => {}
893 FilterGraphOp::SVGFEBlendLuminosity => {}
894 FilterGraphOp::SVGFEColorMatrix{values: matrix} => {
895 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
896 if let Some(mut request) = gpu_cache.request(handle) {
897 for i in 0..5 {
898 request.push([matrix[i*4], matrix[i*4+1], matrix[i*4+2], matrix[i*4+3]]);
899 }
900 }
901 }
902 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
903 FilterGraphOp::SVGFEComponentTransferInterned{..} => {}
904 FilterGraphOp::SVGFECompositeArithmetic{k1, k2, k3, k4} => {
905 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
906 if let Some(mut request) = gpu_cache.request(handle) {
907 request.push([k1, k2, k3, k4]);
908 }
909 }
910 FilterGraphOp::SVGFECompositeATop => {}
911 FilterGraphOp::SVGFECompositeIn => {}
912 FilterGraphOp::SVGFECompositeLighter => {}
913 FilterGraphOp::SVGFECompositeOut => {}
914 FilterGraphOp::SVGFECompositeOver => {}
915 FilterGraphOp::SVGFECompositeXOR => {}
916 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} |
917 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} |
918 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{order_x, order_y, kernel, divisor, bias, target_x, target_y, kernel_unit_length_x, kernel_unit_length_y, preserve_alpha} => {
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([-target_x as f32, -target_y as f32, order_x as f32, order_y as f32]);
922 request.push([kernel_unit_length_x as f32, kernel_unit_length_y as f32, 1.0 / divisor, bias]);
923 assert!(SVGFE_CONVOLVE_VALUES_LIMIT == 25);
924 request.push([kernel[0], kernel[1], kernel[2], kernel[3]]);
925 request.push([kernel[4], kernel[5], kernel[6], kernel[7]]);
926 request.push([kernel[8], kernel[9], kernel[10], kernel[11]]);
927 request.push([kernel[12], kernel[13], kernel[14], kernel[15]]);
928 request.push([kernel[16], kernel[17], kernel[18], kernel[19]]);
929 request.push([kernel[20], 0.0, 0.0, preserve_alpha as f32]);
930 }
931 }
932 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {}
933 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {}
934 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {}
935 FilterGraphOp::SVGFEDisplacementMap{scale, x_channel_selector, y_channel_selector} => {
936 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
937 if let Some(mut request) = gpu_cache.request(handle) {
938 request.push([x_channel_selector as f32, y_channel_selector as f32, scale, 0.0]);
939 }
940 }
941 FilterGraphOp::SVGFEDropShadow{color, ..} |
942 FilterGraphOp::SVGFEFlood{color} => {
943 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
944 if let Some(mut request) = gpu_cache.request(handle) {
945 request.push(color.to_array());
946 }
947 }
948 FilterGraphOp::SVGFEGaussianBlur{..} => {}
949 FilterGraphOp::SVGFEIdentity => {}
950 FilterGraphOp::SVGFEImage{..} => {}
951 FilterGraphOp::SVGFEMorphologyDilate{radius_x, radius_y} |
952 FilterGraphOp::SVGFEMorphologyErode{radius_x, radius_y} => {
953 let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(GpuCacheHandle::new);
954 if let Some(mut request) = gpu_cache.request(handle) {
955 request.push([radius_x, radius_y, 0.0, 0.0]);
956 }
957 }
958 FilterGraphOp::SVGFEOpacity{..} => {}
959 FilterGraphOp::SVGFESourceAlpha => {}
960 FilterGraphOp::SVGFESourceGraphic => {}
961 FilterGraphOp::SVGFESpecularLightingDistant{..} => {}
962 FilterGraphOp::SVGFESpecularLightingPoint{..} => {}
963 FilterGraphOp::SVGFESpecularLightingSpot{..} => {}
964 FilterGraphOp::SVGFETile => {}
965 FilterGraphOp::SVGFEToAlpha{..} => {}
966 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} => {}
967 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} => {}
968 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} => {}
969 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {}
970 }
971 }
972 _ => {}
973 }
974 }
975}
976
977pub type BlurTaskCache = FastHashMap<BlurTaskKey, RenderTaskId>;
981
982#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
985pub enum BlurTaskKey {
986 DownScale(u32),
987 Blur { downscale_level: u32, stddev_x: u32, stddev_y: u32 },
988}
989
990impl BlurTaskKey {
991 fn downscale_and_blur(downscale_level: u32, blur_stddev: DeviceSize) -> Self {
992 const QUANTIZATION_FACTOR: f32 = 1024.0;
997 let stddev_x = (blur_stddev.width * QUANTIZATION_FACTOR) as u32;
998 let stddev_y = (blur_stddev.height * QUANTIZATION_FACTOR) as u32;
999 BlurTaskKey::Blur { downscale_level, stddev_x, stddev_y }
1000 }
1001}
1002
1003pub type TaskDependencies = SmallVec<[RenderTaskId;2]>;
1008
1009#[cfg_attr(feature = "capture", derive(Serialize))]
1010#[cfg_attr(feature = "replay", derive(Deserialize))]
1011pub struct MaskSubPass {
1012 pub clip_node_range: ClipNodeRange,
1013 pub prim_spatial_node_index: SpatialNodeIndex,
1014 pub prim_address_f: GpuBufferAddress,
1015}
1016
1017#[cfg_attr(feature = "capture", derive(Serialize))]
1018#[cfg_attr(feature = "replay", derive(Deserialize))]
1019pub enum SubPass {
1020 Masks {
1021 masks: MaskSubPass,
1022 },
1023}
1024
1025#[cfg_attr(feature = "capture", derive(Serialize))]
1026#[cfg_attr(feature = "replay", derive(Deserialize))]
1027pub struct RenderTask {
1028 pub location: RenderTaskLocation,
1029 pub children: TaskDependencies,
1030 pub kind: RenderTaskKind,
1031 pub sub_pass: Option<SubPass>,
1032
1033 pub free_after: PassId,
1036 pub render_on: PassId,
1037
1038 pub uv_rect_handle: GpuCacheHandle,
1043 pub cache_handle: Option<RenderTaskCacheEntryHandle>,
1044 uv_rect_kind: UvRectKind,
1045}
1046
1047impl RenderTask {
1048 pub fn new(
1049 location: RenderTaskLocation,
1050 kind: RenderTaskKind,
1051 ) -> Self {
1052 render_task_sanity_check(&location.size());
1053
1054 RenderTask {
1055 location,
1056 children: TaskDependencies::new(),
1057 kind,
1058 free_after: PassId::MAX,
1059 render_on: PassId::MIN,
1060 uv_rect_handle: GpuCacheHandle::new(),
1061 uv_rect_kind: UvRectKind::Rect,
1062 cache_handle: None,
1063 sub_pass: None,
1064 }
1065 }
1066
1067 pub fn new_dynamic(
1068 size: DeviceIntSize,
1069 kind: RenderTaskKind,
1070 ) -> Self {
1071 assert!(!size.is_empty(), "Bad {} render task size: {:?}", kind.as_str(), size);
1072 RenderTask::new(
1073 RenderTaskLocation::Unallocated { size },
1074 kind,
1075 )
1076 }
1077
1078 pub fn with_uv_rect_kind(mut self, uv_rect_kind: UvRectKind) -> Self {
1079 self.uv_rect_kind = uv_rect_kind;
1080 self
1081 }
1082
1083 pub fn new_image(
1084 size: DeviceIntSize,
1085 request: ImageRequest,
1086 ) -> Self {
1087 RenderTask {
1096 location: RenderTaskLocation::CacheRequest { size, },
1097 children: TaskDependencies::new(),
1098 kind: RenderTaskKind::Image(request),
1099 free_after: PassId::MAX,
1100 render_on: PassId::MIN,
1101 uv_rect_handle: GpuCacheHandle::new(),
1102 uv_rect_kind: UvRectKind::Rect,
1103 cache_handle: None,
1104 sub_pass: None,
1105 }
1106 }
1107
1108
1109 #[cfg(test)]
1110 pub fn new_test(
1111 location: RenderTaskLocation,
1112 target: RenderTargetKind,
1113 ) -> Self {
1114 RenderTask {
1115 location,
1116 children: TaskDependencies::new(),
1117 kind: RenderTaskKind::Test(target),
1118 free_after: PassId::MAX,
1119 render_on: PassId::MIN,
1120 uv_rect_handle: GpuCacheHandle::new(),
1121 uv_rect_kind: UvRectKind::Rect,
1122 cache_handle: None,
1123 sub_pass: None,
1124 }
1125 }
1126
1127 pub fn new_blit(
1128 size: DeviceIntSize,
1129 source: RenderTaskId,
1130 source_rect: DeviceIntRect,
1131 rg_builder: &mut RenderTaskGraphBuilder,
1132 ) -> RenderTaskId {
1133 let blit_task_id = rg_builder.add().init(RenderTask::new_dynamic(
1140 size,
1141 RenderTaskKind::Blit(BlitTask { source, source_rect }),
1142 ));
1143
1144 rg_builder.add_dependency(blit_task_id, source);
1145
1146 blit_task_id
1147 }
1148
1149 pub fn new_blur(
1168 blur_std_deviation: DeviceSize,
1169 src_task_id: RenderTaskId,
1170 rg_builder: &mut RenderTaskGraphBuilder,
1171 target_kind: RenderTargetKind,
1172 mut blur_cache: Option<&mut BlurTaskCache>,
1173 blur_region: DeviceIntSize,
1174 ) -> RenderTaskId {
1175 let mut adjusted_blur_std_deviation = blur_std_deviation;
1177 let (blur_target_size, uv_rect_kind) = {
1178 let src_task = rg_builder.get_task(src_task_id);
1179 (src_task.location.size(), src_task.uv_rect_kind())
1180 };
1181 let mut adjusted_blur_target_size = blur_target_size;
1182 let mut downscaling_src_task_id = src_task_id;
1183 let mut scale_factor = 1.0;
1184 let mut n_downscales = 1;
1185 while adjusted_blur_std_deviation.width > MAX_BLUR_STD_DEVIATION &&
1186 adjusted_blur_std_deviation.height > MAX_BLUR_STD_DEVIATION {
1187 if adjusted_blur_target_size.width < MIN_DOWNSCALING_RT_SIZE ||
1188 adjusted_blur_target_size.height < MIN_DOWNSCALING_RT_SIZE {
1189 break;
1190 }
1191 adjusted_blur_std_deviation = adjusted_blur_std_deviation * 0.5;
1192 scale_factor *= 2.0;
1193 adjusted_blur_target_size = (blur_target_size.to_f32() / scale_factor).to_i32();
1194
1195 let cached_task = match blur_cache {
1196 Some(ref mut cache) => cache.get(&BlurTaskKey::DownScale(n_downscales)).cloned(),
1197 None => None,
1198 };
1199
1200 downscaling_src_task_id = cached_task.unwrap_or_else(|| {
1201 RenderTask::new_scaling(
1202 downscaling_src_task_id,
1203 rg_builder,
1204 target_kind,
1205 adjusted_blur_target_size,
1206 )
1207 });
1208
1209 if let Some(ref mut cache) = blur_cache {
1210 cache.insert(BlurTaskKey::DownScale(n_downscales), downscaling_src_task_id);
1211 }
1212
1213 n_downscales += 1;
1214 }
1215
1216
1217 let blur_key = BlurTaskKey::downscale_and_blur(n_downscales, adjusted_blur_std_deviation);
1218
1219 let cached_task = match blur_cache {
1220 Some(ref mut cache) => cache.get(&blur_key).cloned(),
1221 None => None,
1222 };
1223
1224 let blur_region = blur_region / (scale_factor as i32);
1225
1226 let blur_task_id = cached_task.unwrap_or_else(|| {
1227 let blur_task_v = rg_builder.add().init(RenderTask::new_dynamic(
1228 adjusted_blur_target_size,
1229 RenderTaskKind::VerticalBlur(BlurTask {
1230 blur_std_deviation: adjusted_blur_std_deviation.height,
1231 target_kind,
1232 blur_region,
1233 }),
1234 ).with_uv_rect_kind(uv_rect_kind));
1235 rg_builder.add_dependency(blur_task_v, downscaling_src_task_id);
1236
1237 let task_id = rg_builder.add().init(RenderTask::new_dynamic(
1238 adjusted_blur_target_size,
1239 RenderTaskKind::HorizontalBlur(BlurTask {
1240 blur_std_deviation: adjusted_blur_std_deviation.width,
1241 target_kind,
1242 blur_region,
1243 }),
1244 ).with_uv_rect_kind(uv_rect_kind));
1245 rg_builder.add_dependency(task_id, blur_task_v);
1246
1247 task_id
1248 });
1249
1250 if let Some(ref mut cache) = blur_cache {
1251 cache.insert(blur_key, blur_task_id);
1252 }
1253
1254 blur_task_id
1255 }
1256
1257 pub fn new_scaling(
1258 src_task_id: RenderTaskId,
1259 rg_builder: &mut RenderTaskGraphBuilder,
1260 target_kind: RenderTargetKind,
1261 size: DeviceIntSize,
1262 ) -> RenderTaskId {
1263 Self::new_scaling_with_padding(
1264 src_task_id,
1265 rg_builder,
1266 target_kind,
1267 size,
1268 DeviceIntSideOffsets::zero(),
1269 )
1270 }
1271
1272 pub fn new_scaling_with_padding(
1273 source: RenderTaskId,
1274 rg_builder: &mut RenderTaskGraphBuilder,
1275 target_kind: RenderTargetKind,
1276 padded_size: DeviceIntSize,
1277 padding: DeviceIntSideOffsets,
1278 ) -> RenderTaskId {
1279 let uv_rect_kind = rg_builder.get_task(source).uv_rect_kind();
1280
1281 let task_id = rg_builder.add().init(
1282 RenderTask::new_dynamic(
1283 padded_size,
1284 RenderTaskKind::Scaling(ScalingTask {
1285 target_kind,
1286 padding,
1287 }),
1288 ).with_uv_rect_kind(uv_rect_kind)
1289 );
1290
1291 rg_builder.add_dependency(task_id, source);
1292
1293 task_id
1294 }
1295
1296 pub fn new_svg_filter(
1297 filter_primitives: &[FilterPrimitive],
1298 filter_datas: &[SFilterData],
1299 rg_builder: &mut RenderTaskGraphBuilder,
1300 content_size: DeviceIntSize,
1301 uv_rect_kind: UvRectKind,
1302 original_task_id: RenderTaskId,
1303 device_pixel_scale: DevicePixelScale,
1304 ) -> RenderTaskId {
1305
1306 if filter_primitives.is_empty() {
1307 return original_task_id;
1308 }
1309
1310 let get_task_input = |
1312 input: &FilterPrimitiveInput,
1313 filter_primitives: &[FilterPrimitive],
1314 rg_builder: &mut RenderTaskGraphBuilder,
1315 cur_index: usize,
1316 outputs: &[RenderTaskId],
1317 original: RenderTaskId,
1318 color_space: ColorSpace,
1319 | {
1320 let (mut task_id, input_color_space) = match input.to_index(cur_index) {
1322 Some(index) => (outputs[index], filter_primitives[index].color_space),
1323 None => (original, ColorSpace::Srgb),
1324 };
1325
1326 match (input_color_space, color_space) {
1327 (ColorSpace::Srgb, ColorSpace::LinearRgb) => {
1328 task_id = RenderTask::new_svg_filter_primitive(
1329 smallvec![task_id],
1330 content_size,
1331 uv_rect_kind,
1332 SvgFilterInfo::SrgbToLinear,
1333 rg_builder,
1334 );
1335 },
1336 (ColorSpace::LinearRgb, ColorSpace::Srgb) => {
1337 task_id = RenderTask::new_svg_filter_primitive(
1338 smallvec![task_id],
1339 content_size,
1340 uv_rect_kind,
1341 SvgFilterInfo::LinearToSrgb,
1342 rg_builder,
1343 );
1344 },
1345 _ => {},
1346 }
1347
1348 task_id
1349 };
1350
1351 let mut outputs = vec![];
1352 let mut cur_filter_data = 0;
1353 for (cur_index, primitive) in filter_primitives.iter().enumerate() {
1354 let render_task_id = match primitive.kind {
1355 FilterPrimitiveKind::Identity(ref identity) => {
1356 get_task_input(
1358 &identity.input,
1359 filter_primitives,
1360 rg_builder,
1361 cur_index,
1362 &outputs,
1363 original_task_id,
1364 primitive.color_space
1365 )
1366 }
1367 FilterPrimitiveKind::Blend(ref blend) => {
1368 let input_1_task_id = get_task_input(
1369 &blend.input1,
1370 filter_primitives,
1371 rg_builder,
1372 cur_index,
1373 &outputs,
1374 original_task_id,
1375 primitive.color_space
1376 );
1377 let input_2_task_id = get_task_input(
1378 &blend.input2,
1379 filter_primitives,
1380 rg_builder,
1381 cur_index,
1382 &outputs,
1383 original_task_id,
1384 primitive.color_space
1385 );
1386
1387 RenderTask::new_svg_filter_primitive(
1388 smallvec![input_1_task_id, input_2_task_id],
1389 content_size,
1390 uv_rect_kind,
1391 SvgFilterInfo::Blend(blend.mode),
1392 rg_builder,
1393 )
1394 },
1395 FilterPrimitiveKind::Flood(ref flood) => {
1396 RenderTask::new_svg_filter_primitive(
1397 smallvec![],
1398 content_size,
1399 uv_rect_kind,
1400 SvgFilterInfo::Flood(flood.color),
1401 rg_builder,
1402 )
1403 }
1404 FilterPrimitiveKind::Blur(ref blur) => {
1405 let width_std_deviation = blur.width * device_pixel_scale.0;
1406 let height_std_deviation = blur.height * device_pixel_scale.0;
1407 let input_task_id = get_task_input(
1408 &blur.input,
1409 filter_primitives,
1410 rg_builder,
1411 cur_index,
1412 &outputs,
1413 original_task_id,
1414 primitive.color_space
1415 );
1416
1417 RenderTask::new_blur(
1418 DeviceSize::new(width_std_deviation, height_std_deviation),
1419 RenderTask::new_svg_filter_primitive(
1422 smallvec![input_task_id],
1423 content_size,
1424 uv_rect_kind,
1425 SvgFilterInfo::Identity,
1426 rg_builder,
1427 ),
1428 rg_builder,
1429 RenderTargetKind::Color,
1430 None,
1431 content_size,
1432 )
1433 }
1434 FilterPrimitiveKind::Opacity(ref opacity) => {
1435 let input_task_id = get_task_input(
1436 &opacity.input,
1437 filter_primitives,
1438 rg_builder,
1439 cur_index,
1440 &outputs,
1441 original_task_id,
1442 primitive.color_space
1443 );
1444
1445 RenderTask::new_svg_filter_primitive(
1446 smallvec![input_task_id],
1447 content_size,
1448 uv_rect_kind,
1449 SvgFilterInfo::Opacity(opacity.opacity),
1450 rg_builder,
1451 )
1452 }
1453 FilterPrimitiveKind::ColorMatrix(ref color_matrix) => {
1454 let input_task_id = get_task_input(
1455 &color_matrix.input,
1456 filter_primitives,
1457 rg_builder,
1458 cur_index,
1459 &outputs,
1460 original_task_id,
1461 primitive.color_space
1462 );
1463
1464 RenderTask::new_svg_filter_primitive(
1465 smallvec![input_task_id],
1466 content_size,
1467 uv_rect_kind,
1468 SvgFilterInfo::ColorMatrix(Box::new(color_matrix.matrix)),
1469 rg_builder,
1470 )
1471 }
1472 FilterPrimitiveKind::DropShadow(ref drop_shadow) => {
1473 let input_task_id = get_task_input(
1474 &drop_shadow.input,
1475 filter_primitives,
1476 rg_builder,
1477 cur_index,
1478 &outputs,
1479 original_task_id,
1480 primitive.color_space
1481 );
1482
1483 let blur_std_deviation = drop_shadow.shadow.blur_radius * device_pixel_scale.0;
1484 let offset = drop_shadow.shadow.offset * LayoutToWorldScale::new(1.0) * device_pixel_scale;
1485
1486 let offset_task_id = RenderTask::new_svg_filter_primitive(
1487 smallvec![input_task_id],
1488 content_size,
1489 uv_rect_kind,
1490 SvgFilterInfo::Offset(offset),
1491 rg_builder,
1492 );
1493
1494 let blur_task_id = RenderTask::new_blur(
1495 DeviceSize::new(blur_std_deviation, blur_std_deviation),
1496 offset_task_id,
1497 rg_builder,
1498 RenderTargetKind::Color,
1499 None,
1500 content_size,
1501 );
1502
1503 RenderTask::new_svg_filter_primitive(
1504 smallvec![input_task_id, blur_task_id],
1505 content_size,
1506 uv_rect_kind,
1507 SvgFilterInfo::DropShadow(drop_shadow.shadow.color),
1508 rg_builder,
1509 )
1510 }
1511 FilterPrimitiveKind::ComponentTransfer(ref component_transfer) => {
1512 let input_task_id = get_task_input(
1513 &component_transfer.input,
1514 filter_primitives,
1515 rg_builder,
1516 cur_index,
1517 &outputs,
1518 original_task_id,
1519 primitive.color_space
1520 );
1521
1522 let filter_data = &filter_datas[cur_filter_data];
1523 cur_filter_data += 1;
1524 if filter_data.is_identity() {
1525 input_task_id
1526 } else {
1527 RenderTask::new_svg_filter_primitive(
1528 smallvec![input_task_id],
1529 content_size,
1530 uv_rect_kind,
1531 SvgFilterInfo::ComponentTransfer(filter_data.clone()),
1532 rg_builder,
1533 )
1534 }
1535 }
1536 FilterPrimitiveKind::Offset(ref info) => {
1537 let input_task_id = get_task_input(
1538 &info.input,
1539 filter_primitives,
1540 rg_builder,
1541 cur_index,
1542 &outputs,
1543 original_task_id,
1544 primitive.color_space
1545 );
1546
1547 let offset = info.offset * LayoutToWorldScale::new(1.0) * device_pixel_scale;
1548 RenderTask::new_svg_filter_primitive(
1549 smallvec![input_task_id],
1550 content_size,
1551 uv_rect_kind,
1552 SvgFilterInfo::Offset(offset),
1553 rg_builder,
1554 )
1555 }
1556 FilterPrimitiveKind::Composite(info) => {
1557 let input_1_task_id = get_task_input(
1558 &info.input1,
1559 filter_primitives,
1560 rg_builder,
1561 cur_index,
1562 &outputs,
1563 original_task_id,
1564 primitive.color_space
1565 );
1566 let input_2_task_id = get_task_input(
1567 &info.input2,
1568 filter_primitives,
1569 rg_builder,
1570 cur_index,
1571 &outputs,
1572 original_task_id,
1573 primitive.color_space
1574 );
1575
1576 RenderTask::new_svg_filter_primitive(
1577 smallvec![input_1_task_id, input_2_task_id],
1578 content_size,
1579 uv_rect_kind,
1580 SvgFilterInfo::Composite(info.operator),
1581 rg_builder,
1582 )
1583 }
1584 };
1585 outputs.push(render_task_id);
1586 }
1587
1588 let mut render_task_id = *outputs.last().unwrap();
1590
1591 if filter_primitives.last().unwrap().color_space == ColorSpace::LinearRgb {
1593 render_task_id = RenderTask::new_svg_filter_primitive(
1594 smallvec![render_task_id],
1595 content_size,
1596 uv_rect_kind,
1597 SvgFilterInfo::LinearToSrgb,
1598 rg_builder,
1599 );
1600 }
1601
1602 render_task_id
1603 }
1604
1605 pub fn new_svg_filter_primitive(
1606 tasks: TaskDependencies,
1607 target_size: DeviceIntSize,
1608 uv_rect_kind: UvRectKind,
1609 info: SvgFilterInfo,
1610 rg_builder: &mut RenderTaskGraphBuilder,
1611 ) -> RenderTaskId {
1612 let task_id = rg_builder.add().init(RenderTask::new_dynamic(
1613 target_size,
1614 RenderTaskKind::SvgFilter(SvgFilterTask {
1615 extra_gpu_cache_handle: None,
1616 info,
1617 }),
1618 ).with_uv_rect_kind(uv_rect_kind));
1619
1620 for child_id in tasks {
1621 rg_builder.add_dependency(task_id, child_id);
1622 }
1623
1624 task_id
1625 }
1626
1627 pub fn add_sub_pass(
1628 &mut self,
1629 sub_pass: SubPass,
1630 ) {
1631 assert!(self.sub_pass.is_none(), "multiple sub-passes are not supported for now");
1632 self.sub_pass = Some(sub_pass);
1633 }
1634
1635 pub fn new_svg_filter_graph(
1643 filter_nodes: &[(FilterGraphNode, FilterGraphOp)],
1644 rg_builder: &mut RenderTaskGraphBuilder,
1645 gpu_cache: &mut GpuCache,
1646 data_stores: &mut DataStores,
1647 _uv_rect_kind: UvRectKind,
1648 original_task_id: RenderTaskId,
1649 source_subregion: LayoutRect,
1650 target_subregion: LayoutRect,
1651 prim_subregion: LayoutRect,
1652 subregion_to_device_scale_x: f32,
1653 subregion_to_device_scale_y: f32,
1654 subregion_to_device_offset_x: f32,
1655 subregion_to_device_offset_y: f32,
1656 ) -> RenderTaskId {
1657 const BUFFER_LIMIT: usize = SVGFE_GRAPH_MAX;
1658 let mut task_by_buffer_id: [RenderTaskId; BUFFER_LIMIT] = [RenderTaskId::INVALID; BUFFER_LIMIT];
1659 let mut subregion_by_buffer_id: [LayoutRect; BUFFER_LIMIT] = [LayoutRect::zero(); BUFFER_LIMIT];
1660 let mut output_task_id = original_task_id;
1663
1664 fn uv_rect_kind_for_task_size(clipped: DeviceRect, unclipped: DeviceRect) -> UvRectKind {
1682 let scale_x = 1.0 / clipped.width();
1683 let scale_y = 1.0 / clipped.height();
1684 UvRectKind::Quad{
1685 top_left: DeviceHomogeneousVector::new(
1686 (unclipped.min.x - clipped.min.x) * scale_x,
1687 (unclipped.min.y - clipped.min.y) * scale_y,
1688 0.0, 1.0),
1689 top_right: DeviceHomogeneousVector::new(
1690 (unclipped.max.x - clipped.min.x) * scale_x,
1691 (unclipped.min.y - clipped.min.y) * scale_y,
1692 0.0, 1.0),
1693 bottom_left: DeviceHomogeneousVector::new(
1694 (unclipped.min.x - clipped.min.x) * scale_x,
1695 (unclipped.max.y - clipped.min.y) * scale_y,
1696 0.0, 1.0),
1697 bottom_right: DeviceHomogeneousVector::new(
1698 (unclipped.max.x - clipped.min.x) * scale_x,
1699 (unclipped.max.y - clipped.min.y) * scale_y,
1700 0.0, 1.0),
1701 }
1702 }
1703
1704 let mut made_dependency_on_source = false;
1706 for (filter_index, (filter_node, op)) in filter_nodes.iter().enumerate() {
1707 let node = &filter_node;
1708 let is_output = filter_index == filter_nodes.len() - 1;
1709
1710 if !node.kept_by_optimizer {
1712 continue;
1713 }
1714
1715 let op = match op {
1718 FilterGraphOp::SVGFEBlendColor => op.clone(),
1719 FilterGraphOp::SVGFEBlendColorBurn => op.clone(),
1720 FilterGraphOp::SVGFEBlendColorDodge => op.clone(),
1721 FilterGraphOp::SVGFEBlendDarken => op.clone(),
1722 FilterGraphOp::SVGFEBlendDifference => op.clone(),
1723 FilterGraphOp::SVGFEBlendExclusion => op.clone(),
1724 FilterGraphOp::SVGFEBlendHardLight => op.clone(),
1725 FilterGraphOp::SVGFEBlendHue => op.clone(),
1726 FilterGraphOp::SVGFEBlendLighten => op.clone(),
1727 FilterGraphOp::SVGFEBlendLuminosity => op.clone(),
1728 FilterGraphOp::SVGFEBlendMultiply => op.clone(),
1729 FilterGraphOp::SVGFEBlendNormal => op.clone(),
1730 FilterGraphOp::SVGFEBlendOverlay => op.clone(),
1731 FilterGraphOp::SVGFEBlendSaturation => op.clone(),
1732 FilterGraphOp::SVGFEBlendScreen => op.clone(),
1733 FilterGraphOp::SVGFEBlendSoftLight => op.clone(),
1734 FilterGraphOp::SVGFEColorMatrix{..} => op.clone(),
1735 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
1736 FilterGraphOp::SVGFEComponentTransferInterned{..} => op.clone(),
1737 FilterGraphOp::SVGFECompositeArithmetic{..} => op.clone(),
1738 FilterGraphOp::SVGFECompositeATop => op.clone(),
1739 FilterGraphOp::SVGFECompositeIn => op.clone(),
1740 FilterGraphOp::SVGFECompositeLighter => op.clone(),
1741 FilterGraphOp::SVGFECompositeOut => op.clone(),
1742 FilterGraphOp::SVGFECompositeOver => op.clone(),
1743 FilterGraphOp::SVGFECompositeXOR => op.clone(),
1744 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{
1745 kernel_unit_length_x, kernel_unit_length_y, order_x,
1746 order_y, kernel, divisor, bias, target_x, target_y,
1747 preserve_alpha} => {
1748 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{
1749 kernel_unit_length_x:
1750 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1751 kernel_unit_length_y:
1752 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1753 order_x: *order_x, order_y: *order_y, kernel: *kernel,
1754 divisor: *divisor, bias: *bias, target_x: *target_x,
1755 target_y: *target_y, preserve_alpha: *preserve_alpha}
1756 },
1757 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{
1758 kernel_unit_length_x, kernel_unit_length_y, order_x,
1759 order_y, kernel, divisor, bias, target_x, target_y,
1760 preserve_alpha} => {
1761 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{
1762 kernel_unit_length_x:
1763 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1764 kernel_unit_length_y:
1765 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1766 order_x: *order_x, order_y: *order_y, kernel: *kernel,
1767 divisor: *divisor, bias: *bias, target_x: *target_x,
1768 target_y: *target_y, preserve_alpha: *preserve_alpha}
1769 },
1770 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{
1771 kernel_unit_length_x, kernel_unit_length_y, order_x,
1772 order_y, kernel, divisor, bias, target_x, target_y,
1773 preserve_alpha} => {
1774 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{
1775 kernel_unit_length_x:
1776 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1777 kernel_unit_length_y:
1778 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1779 order_x: *order_x, order_y: *order_y, kernel: *kernel,
1780 divisor: *divisor, bias: *bias, target_x: *target_x,
1781 target_y: *target_y, preserve_alpha: *preserve_alpha}
1782 },
1783 FilterGraphOp::SVGFEDiffuseLightingDistant{
1784 surface_scale, diffuse_constant, kernel_unit_length_x,
1785 kernel_unit_length_y, azimuth, elevation} => {
1786 FilterGraphOp::SVGFEDiffuseLightingDistant{
1787 surface_scale: *surface_scale,
1788 diffuse_constant: *diffuse_constant,
1789 kernel_unit_length_x:
1790 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1791 kernel_unit_length_y:
1792 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1793 azimuth: *azimuth, elevation: *elevation}
1794 },
1795 FilterGraphOp::SVGFEDiffuseLightingPoint{
1796 surface_scale, diffuse_constant, kernel_unit_length_x,
1797 kernel_unit_length_y, x, y, z} => {
1798 FilterGraphOp::SVGFEDiffuseLightingPoint{
1799 surface_scale: *surface_scale,
1800 diffuse_constant: *diffuse_constant,
1801 kernel_unit_length_x:
1802 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1803 kernel_unit_length_y:
1804 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1805 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1806 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1807 z: *z}
1808 },
1809 FilterGraphOp::SVGFEDiffuseLightingSpot{
1810 surface_scale, diffuse_constant, kernel_unit_length_x,
1811 kernel_unit_length_y, x, y, z, points_at_x, points_at_y,
1812 points_at_z, cone_exponent, limiting_cone_angle} => {
1813 FilterGraphOp::SVGFEDiffuseLightingSpot{
1814 surface_scale: *surface_scale,
1815 diffuse_constant: *diffuse_constant,
1816 kernel_unit_length_x:
1817 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1818 kernel_unit_length_y:
1819 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1820 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1821 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1822 z: *z,
1823 points_at_x: points_at_x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1824 points_at_y: points_at_y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1825 points_at_z: *points_at_z,
1826 cone_exponent: *cone_exponent,
1827 limiting_cone_angle: *limiting_cone_angle}
1828 },
1829 FilterGraphOp::SVGFEFlood{..} => op.clone(),
1830 FilterGraphOp::SVGFEDisplacementMap{
1831 scale, x_channel_selector, y_channel_selector} => {
1832 FilterGraphOp::SVGFEDisplacementMap{
1833 scale: scale * subregion_to_device_scale_x,
1834 x_channel_selector: *x_channel_selector,
1835 y_channel_selector: *y_channel_selector}
1836 },
1837 FilterGraphOp::SVGFEDropShadow{
1838 color, dx, dy, std_deviation_x, std_deviation_y} => {
1839 FilterGraphOp::SVGFEDropShadow{
1840 color: *color,
1841 dx: dx * subregion_to_device_scale_x,
1842 dy: dy * subregion_to_device_scale_y,
1843 std_deviation_x: std_deviation_x * subregion_to_device_scale_x,
1844 std_deviation_y: std_deviation_y * subregion_to_device_scale_y}
1845 },
1846 FilterGraphOp::SVGFEGaussianBlur{std_deviation_x, std_deviation_y} => {
1847 let std_deviation_x = std_deviation_x * subregion_to_device_scale_x;
1848 let std_deviation_y = std_deviation_y * subregion_to_device_scale_y;
1849 if std_deviation_x + std_deviation_y >= 0.125 {
1852 FilterGraphOp::SVGFEGaussianBlur{
1853 std_deviation_x,
1854 std_deviation_y}
1855 } else {
1856 FilterGraphOp::SVGFEIdentity
1857 }
1858 },
1859 FilterGraphOp::SVGFEIdentity => op.clone(),
1860 FilterGraphOp::SVGFEImage{..} => op.clone(),
1861 FilterGraphOp::SVGFEMorphologyDilate{radius_x, radius_y} => {
1862 FilterGraphOp::SVGFEMorphologyDilate{
1863 radius_x: (radius_x * subregion_to_device_scale_x).round(),
1864 radius_y: (radius_y * subregion_to_device_scale_y).round()}
1865 },
1866 FilterGraphOp::SVGFEMorphologyErode{radius_x, radius_y} => {
1867 FilterGraphOp::SVGFEMorphologyErode{
1868 radius_x: (radius_x * subregion_to_device_scale_x).round(),
1869 radius_y: (radius_y * subregion_to_device_scale_y).round()}
1870 },
1871 FilterGraphOp::SVGFEOpacity{..} => op.clone(),
1872 FilterGraphOp::SVGFESourceAlpha => op.clone(),
1873 FilterGraphOp::SVGFESourceGraphic => op.clone(),
1874 FilterGraphOp::SVGFESpecularLightingDistant{
1875 surface_scale, specular_constant, specular_exponent,
1876 kernel_unit_length_x, kernel_unit_length_y, azimuth,
1877 elevation} => {
1878 FilterGraphOp::SVGFESpecularLightingDistant{
1879 surface_scale: *surface_scale,
1880 specular_constant: *specular_constant,
1881 specular_exponent: *specular_exponent,
1882 kernel_unit_length_x:
1883 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1884 kernel_unit_length_y:
1885 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1886 azimuth: *azimuth, elevation: *elevation}
1887 },
1888 FilterGraphOp::SVGFESpecularLightingPoint{
1889 surface_scale, specular_constant, specular_exponent,
1890 kernel_unit_length_x, kernel_unit_length_y, x, y, z } => {
1891 FilterGraphOp::SVGFESpecularLightingPoint{
1892 surface_scale: *surface_scale,
1893 specular_constant: *specular_constant,
1894 specular_exponent: *specular_exponent,
1895 kernel_unit_length_x:
1896 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1897 kernel_unit_length_y:
1898 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1899 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1900 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1901 z: *z }
1902 },
1903 FilterGraphOp::SVGFESpecularLightingSpot{
1904 surface_scale, specular_constant, specular_exponent,
1905 kernel_unit_length_x, kernel_unit_length_y, x, y, z,
1906 points_at_x, points_at_y, points_at_z, cone_exponent,
1907 limiting_cone_angle} => {
1908 FilterGraphOp::SVGFESpecularLightingSpot{
1909 surface_scale: *surface_scale,
1910 specular_constant: *specular_constant,
1911 specular_exponent: *specular_exponent,
1912 kernel_unit_length_x:
1913 (kernel_unit_length_x * subregion_to_device_scale_x).round(),
1914 kernel_unit_length_y:
1915 (kernel_unit_length_y * subregion_to_device_scale_y).round(),
1916 x: x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1917 y: y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1918 z: *z,
1919 points_at_x: points_at_x * subregion_to_device_scale_x + subregion_to_device_offset_x,
1920 points_at_y: points_at_y * subregion_to_device_scale_y + subregion_to_device_offset_y,
1921 points_at_z: *points_at_z,
1922 cone_exponent: *cone_exponent,
1923 limiting_cone_angle: *limiting_cone_angle}
1924 },
1925 FilterGraphOp::SVGFETile => op.clone(),
1926 FilterGraphOp::SVGFEToAlpha => op.clone(),
1927 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1928 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1929 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1930 base_frequency_x:
1931 base_frequency_x * subregion_to_device_scale_x,
1932 base_frequency_y:
1933 base_frequency_y * subregion_to_device_scale_y,
1934 num_octaves: *num_octaves, seed: *seed}
1935 },
1936 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{
1937 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1938 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1939 base_frequency_x:
1940 base_frequency_x * subregion_to_device_scale_x,
1941 base_frequency_y:
1942 base_frequency_y * subregion_to_device_scale_y,
1943 num_octaves: *num_octaves, seed: *seed}
1944 },
1945 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{
1946 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1947 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1948 base_frequency_x:
1949 base_frequency_x * subregion_to_device_scale_x,
1950 base_frequency_y:
1951 base_frequency_y * subregion_to_device_scale_y,
1952 num_octaves: *num_octaves, seed: *seed}
1953 },
1954 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{
1955 base_frequency_x, base_frequency_y, num_octaves, seed} => {
1956 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{
1957 base_frequency_x:
1958 base_frequency_x * subregion_to_device_scale_x,
1959 base_frequency_y:
1960 base_frequency_y * subregion_to_device_scale_y,
1961 num_octaves: *num_octaves, seed: *seed}
1962 },
1963 };
1964
1965 let mut used_subregion = LayoutRect::zero();
1971 let node_inputs: Vec<(FilterGraphPictureReference, RenderTaskId)> = node.inputs.iter().map(|input| {
1972 let (subregion, task) =
1973 match input.buffer_id {
1974 FilterOpGraphPictureBufferId::BufferId(id) => {
1975 (subregion_by_buffer_id[id as usize], task_by_buffer_id[id as usize])
1976 }
1977 FilterOpGraphPictureBufferId::None => {
1978 (LayoutRect::zero(), original_task_id)
1982 }
1983 };
1984 let offset = LayoutVector2D::new(
1986 (input.offset.x * subregion_to_device_scale_x).round(),
1987 (input.offset.y * subregion_to_device_scale_y).round(),
1988 );
1989 let target_padding = input.target_padding
1994 .scale(subregion_to_device_scale_x, subregion_to_device_scale_y)
1995 .round();
1996 let target_subregion =
1997 LayoutRect::new(
1998 LayoutPoint::new(
1999 subregion.min.x + target_padding.min.x,
2000 subregion.min.y + target_padding.min.y,
2001 ),
2002 LayoutPoint::new(
2003 subregion.max.x + target_padding.max.x,
2004 subregion.max.y + target_padding.max.y,
2005 ),
2006 );
2007 used_subregion = used_subregion.union(&target_subregion);
2008 (FilterGraphPictureReference{
2009 buffer_id: input.buffer_id,
2010 subregion: subregion.translate(offset),
2012 offset: LayoutVector2D::zero(),
2013 inflate: input.inflate,
2014 source_padding: LayoutRect::zero(),
2016 target_padding: LayoutRect::zero(),
2017 }, task)
2018 }).collect();
2019
2020 let full_subregion = node.subregion
2022 .scale(subregion_to_device_scale_x, subregion_to_device_scale_y)
2023 .translate(LayoutVector2D::new(subregion_to_device_offset_x, subregion_to_device_offset_y))
2024 .round();
2025
2026 used_subregion = used_subregion
2033 .intersection(&full_subregion)
2034 .unwrap_or(LayoutRect::zero())
2035 .round();
2036
2037 match op {
2039 FilterGraphOp::SVGFEBlendColor => {},
2040 FilterGraphOp::SVGFEBlendColorBurn => {},
2041 FilterGraphOp::SVGFEBlendColorDodge => {},
2042 FilterGraphOp::SVGFEBlendDarken => {},
2043 FilterGraphOp::SVGFEBlendDifference => {},
2044 FilterGraphOp::SVGFEBlendExclusion => {},
2045 FilterGraphOp::SVGFEBlendHardLight => {},
2046 FilterGraphOp::SVGFEBlendHue => {},
2047 FilterGraphOp::SVGFEBlendLighten => {},
2048 FilterGraphOp::SVGFEBlendLuminosity => {},
2049 FilterGraphOp::SVGFEBlendMultiply => {},
2050 FilterGraphOp::SVGFEBlendNormal => {},
2051 FilterGraphOp::SVGFEBlendOverlay => {},
2052 FilterGraphOp::SVGFEBlendSaturation => {},
2053 FilterGraphOp::SVGFEBlendScreen => {},
2054 FilterGraphOp::SVGFEBlendSoftLight => {},
2055 FilterGraphOp::SVGFEColorMatrix{values} => {
2056 if values[3] != 0.0 ||
2057 values[7] != 0.0 ||
2058 values[11] != 0.0 ||
2059 values[15] != 1.0 ||
2060 values[19] != 0.0 {
2061 used_subregion = full_subregion;
2064 }
2065 },
2066 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
2067 FilterGraphOp::SVGFEComponentTransferInterned{handle: _, creates_pixels} => {
2068 if creates_pixels {
2072 used_subregion = full_subregion;
2073 }
2074 },
2075 FilterGraphOp::SVGFECompositeArithmetic { k1, k2, k3, k4 } => {
2076 if k4 > 0.0 {
2083 used_subregion = full_subregion;
2085 } else if k1 > 0.0 && k2 == 0.0 && k3 == 0.0 {
2086 used_subregion = full_subregion
2088 .intersection(&node_inputs[0].0.subregion)
2089 .unwrap_or(LayoutRect::zero())
2090 .intersection(&node_inputs[1].0.subregion)
2091 .unwrap_or(LayoutRect::zero());
2092 }
2093 else if k2 > 0.0 && k3 == 0.0 {
2094 used_subregion = full_subregion
2096 .intersection(&node_inputs[0].0.subregion)
2097 .unwrap_or(LayoutRect::zero());
2098 }
2099 else if k2 == 0.0 && k3 > 0.0 {
2100 used_subregion = full_subregion
2102 .intersection(&node_inputs[1].0.subregion)
2103 .unwrap_or(LayoutRect::zero());
2104 }
2105 },
2106 FilterGraphOp::SVGFECompositeATop => {
2107 used_subregion = full_subregion
2109 .intersection(&node_inputs[1].0.subregion)
2110 .unwrap_or(LayoutRect::zero());
2111 },
2112 FilterGraphOp::SVGFECompositeIn => {
2113 used_subregion = used_subregion
2115 .intersection(&node_inputs[0].0.subregion)
2116 .unwrap_or(LayoutRect::zero())
2117 .intersection(&node_inputs[1].0.subregion)
2118 .unwrap_or(LayoutRect::zero());
2119 },
2120 FilterGraphOp::SVGFECompositeLighter => {},
2121 FilterGraphOp::SVGFECompositeOut => {
2122 used_subregion = full_subregion
2124 .intersection(&node_inputs[0].0.subregion)
2125 .unwrap_or(LayoutRect::zero());
2126 },
2127 FilterGraphOp::SVGFECompositeOver => {},
2128 FilterGraphOp::SVGFECompositeXOR => {},
2129 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{..} => {},
2130 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{..} => {},
2131 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{..} => {},
2132 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {},
2133 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {},
2134 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {},
2135 FilterGraphOp::SVGFEDisplacementMap{..} => {},
2136 FilterGraphOp::SVGFEDropShadow{..} => {},
2137 FilterGraphOp::SVGFEFlood { color } => {
2138 if color.a > 0.0 {
2143 used_subregion = full_subregion;
2144 }
2145 },
2146 FilterGraphOp::SVGFEIdentity => {},
2147 FilterGraphOp::SVGFEImage { sampling_filter: _sampling_filter, matrix: _matrix } => {
2148 used_subregion = full_subregion;
2150 },
2151 FilterGraphOp::SVGFEGaussianBlur{..} => {},
2152 FilterGraphOp::SVGFEMorphologyDilate{..} => {},
2153 FilterGraphOp::SVGFEMorphologyErode{..} => {},
2154 FilterGraphOp::SVGFEOpacity{valuebinding: _valuebinding, value} => {
2155 if value <= 0.0 {
2157 used_subregion = LayoutRect::zero();
2158 }
2159 },
2160 FilterGraphOp::SVGFESourceAlpha |
2161 FilterGraphOp::SVGFESourceGraphic => {
2162 used_subregion = source_subregion
2163 .intersection(&full_subregion)
2164 .unwrap_or(LayoutRect::zero());
2165 },
2166 FilterGraphOp::SVGFESpecularLightingDistant{..} => {},
2167 FilterGraphOp::SVGFESpecularLightingPoint{..} => {},
2168 FilterGraphOp::SVGFESpecularLightingSpot{..} => {},
2169 FilterGraphOp::SVGFETile => {
2170 if !used_subregion.is_empty() {
2171 used_subregion = full_subregion;
2174 }
2175 },
2176 FilterGraphOp::SVGFEToAlpha => {},
2177 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} |
2178 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} |
2179 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} |
2180 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {
2181 used_subregion = full_subregion;
2184 },
2185 }
2186
2187 let mut node_inflate = node.inflate;
2198 if is_output {
2199 used_subregion = target_subregion;
2201 node_inflate = 0;
2202 }
2203
2204 let mut device_to_render_scale = 1.0;
2210 let mut render_to_device_scale = 1.0;
2211 let mut subregion = used_subregion;
2212 let padded_subregion = match op {
2213 FilterGraphOp::SVGFEGaussianBlur{std_deviation_x, std_deviation_y} |
2214 FilterGraphOp::SVGFEDropShadow{std_deviation_x, std_deviation_y, ..} => {
2215 used_subregion
2216 .inflate(
2217 std_deviation_x.ceil() * BLUR_SAMPLE_SCALE,
2218 std_deviation_y.ceil() * BLUR_SAMPLE_SCALE)
2219 }
2220 _ => used_subregion,
2221 };
2222 while
2223 padded_subregion.scale(device_to_render_scale, device_to_render_scale).round().width() + node_inflate as f32 * 2.0 > MAX_SURFACE_SIZE as f32 ||
2224 padded_subregion.scale(device_to_render_scale, device_to_render_scale).round().height() + node_inflate as f32 * 2.0 > MAX_SURFACE_SIZE as f32 {
2225 device_to_render_scale *= 0.5;
2226 render_to_device_scale *= 2.0;
2227 subregion = used_subregion
2231 .scale(device_to_render_scale, device_to_render_scale)
2232 .round()
2233 .scale(render_to_device_scale, render_to_device_scale);
2234 }
2235
2236 let node_task_rect: DeviceRect =
2241 subregion
2242 .scale(device_to_render_scale, device_to_render_scale)
2243 .round()
2244 .inflate(node_inflate as f32, node_inflate as f32)
2245 .cast_unit();
2246 let node_task_size = node_task_rect.to_i32().size();
2247 let node_task_size =
2248 if node_task_size.width < 1 || node_task_size.height < 1 {
2249 DeviceIntSize::new(1, 1)
2250 } else {
2251 node_task_size
2252 };
2253
2254 let node_uv_rect_kind = uv_rect_kind_for_task_size(
2257 subregion
2258 .scale(device_to_render_scale, device_to_render_scale)
2259 .round()
2260 .inflate(node_inflate as f32, node_inflate as f32)
2261 .cast_unit(),
2262 prim_subregion
2263 .scale(device_to_render_scale, device_to_render_scale)
2264 .round()
2265 .inflate(node_inflate as f32, node_inflate as f32)
2266 .cast_unit(),
2267 );
2268
2269 let task_id;
2271 match op {
2272 FilterGraphOp::SVGFEGaussianBlur { std_deviation_x, std_deviation_y } => {
2273 assert!(node_inputs.len() == 1);
2281 let blur_input = &node_inputs[0].0;
2282 let source_task_id = node_inputs[0].1;
2283
2284 let adjusted_blur_std_deviation = DeviceSize::new(
2288 std_deviation_x.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
2289 std_deviation_y.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
2290 );
2291 let blur_subregion = blur_input.subregion
2292 .scale(device_to_render_scale, device_to_render_scale)
2293 .inflate(
2294 adjusted_blur_std_deviation.width * BLUR_SAMPLE_SCALE,
2295 adjusted_blur_std_deviation.height * BLUR_SAMPLE_SCALE)
2296 .round_out();
2297 let blur_task_size = blur_subregion
2298 .size()
2299 .cast_unit()
2300 .max(DeviceSize::new(1.0, 1.0));
2301 let adjusted_blur_task_size =
2303 BlurTask::adjusted_blur_source_size(
2304 blur_task_size,
2305 adjusted_blur_std_deviation,
2306 ).to_f32().max(DeviceSize::new(1.0, 1.0));
2307 let corner = LayoutPoint::new(
2310 blur_subregion.min.x.floor() + ((
2311 blur_task_size.width -
2312 adjusted_blur_task_size.width) * 0.5).floor(),
2313 blur_subregion.min.y.floor() + ((
2314 blur_task_size.height -
2315 adjusted_blur_task_size.height) * 0.5).floor(),
2316 );
2317 let blur_subregion =
2321 LayoutRect::new(
2322 corner,
2323 LayoutPoint::new(
2324 corner.x + adjusted_blur_task_size.width,
2325 corner.y + adjusted_blur_task_size.height,
2326 ),
2327 )
2328 .scale(render_to_device_scale, render_to_device_scale);
2329
2330 let input_subregion_task_id = rg_builder.add().init(RenderTask::new_dynamic(
2331 adjusted_blur_task_size.to_i32(),
2332 RenderTaskKind::SVGFENode(
2333 SVGFEFilterTask{
2334 node: FilterGraphNode{
2335 kept_by_optimizer: true,
2336 linear: false,
2337 inflate: 0,
2338 inputs: [blur_input.clone()].to_vec(),
2339 subregion: blur_subregion,
2340 },
2341 op: FilterGraphOp::SVGFEIdentity,
2342 content_origin: DevicePoint::zero(),
2343 extra_gpu_cache_handle: None,
2344 }
2345 ),
2346 ).with_uv_rect_kind(UvRectKind::Rect));
2347 rg_builder.add_dependency(input_subregion_task_id, source_task_id);
2349
2350 let blur_task_id =
2356 RenderTask::new_blur(
2357 adjusted_blur_std_deviation,
2358 input_subregion_task_id,
2359 rg_builder,
2360 RenderTargetKind::Color,
2361 None,
2362 adjusted_blur_task_size.to_i32(),
2363 );
2364
2365 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2366 node_task_size,
2367 RenderTaskKind::SVGFENode(
2368 SVGFEFilterTask{
2369 node: FilterGraphNode{
2370 kept_by_optimizer: true,
2371 linear: node.linear,
2372 inflate: node_inflate,
2373 inputs: [
2374 FilterGraphPictureReference{
2375 buffer_id: blur_input.buffer_id,
2376 subregion: blur_subregion,
2377 inflate: 0,
2378 offset: LayoutVector2D::zero(),
2379 source_padding: LayoutRect::zero(),
2380 target_padding: LayoutRect::zero(),
2381 }].to_vec(),
2382 subregion,
2383 },
2384 op: FilterGraphOp::SVGFEIdentity,
2385 content_origin: node_task_rect.min,
2386 extra_gpu_cache_handle: None,
2387 }
2388 ),
2389 ).with_uv_rect_kind(node_uv_rect_kind));
2390 rg_builder.add_dependency(task_id, blur_task_id);
2392 }
2393 FilterGraphOp::SVGFEDropShadow { color, dx, dy, std_deviation_x, std_deviation_y } => {
2394 assert!(node_inputs.len() == 1);
2402 let blur_input = &node_inputs[0].0;
2403 let source_task_id = node_inputs[0].1;
2404
2405 let adjusted_blur_std_deviation = DeviceSize::new(
2409 std_deviation_x.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
2410 std_deviation_y.clamp(0.0, (i32::MAX / 2) as f32) * device_to_render_scale,
2411 );
2412 let blur_subregion = blur_input.subregion
2413 .scale(device_to_render_scale, device_to_render_scale)
2414 .inflate(
2415 adjusted_blur_std_deviation.width * BLUR_SAMPLE_SCALE,
2416 adjusted_blur_std_deviation.height * BLUR_SAMPLE_SCALE)
2417 .round_out();
2418 let blur_task_size = blur_subregion
2419 .size()
2420 .cast_unit()
2421 .max(DeviceSize::new(1.0, 1.0));
2422 let adjusted_blur_task_size =
2424 BlurTask::adjusted_blur_source_size(
2425 blur_task_size,
2426 adjusted_blur_std_deviation,
2427 ).to_f32().max(DeviceSize::new(1.0, 1.0));
2428 let corner = LayoutPoint::new(
2431 blur_subregion.min.x.floor() + ((
2432 blur_task_size.width -
2433 adjusted_blur_task_size.width) * 0.5).floor(),
2434 blur_subregion.min.y.floor() + ((
2435 blur_task_size.height -
2436 adjusted_blur_task_size.height) * 0.5).floor(),
2437 );
2438 let blur_subregion =
2442 LayoutRect::new(
2443 corner,
2444 LayoutPoint::new(
2445 corner.x + adjusted_blur_task_size.width,
2446 corner.y + adjusted_blur_task_size.height,
2447 ),
2448 )
2449 .scale(render_to_device_scale, render_to_device_scale);
2450
2451 let input_subregion_task_id = rg_builder.add().init(RenderTask::new_dynamic(
2452 adjusted_blur_task_size.to_i32(),
2453 RenderTaskKind::SVGFENode(
2454 SVGFEFilterTask{
2455 node: FilterGraphNode{
2456 kept_by_optimizer: true,
2457 linear: false,
2458 inputs: [
2459 FilterGraphPictureReference{
2460 buffer_id: blur_input.buffer_id,
2461 subregion: blur_input.subregion,
2462 offset: LayoutVector2D::zero(),
2463 inflate: blur_input.inflate,
2464 source_padding: LayoutRect::zero(),
2465 target_padding: LayoutRect::zero(),
2466 }].to_vec(),
2467 subregion: blur_subregion,
2468 inflate: 0,
2469 },
2470 op: FilterGraphOp::SVGFEIdentity,
2471 content_origin: node_task_rect.min,
2472 extra_gpu_cache_handle: None,
2473 }
2474 ),
2475 ).with_uv_rect_kind(UvRectKind::Rect));
2476 rg_builder.add_dependency(input_subregion_task_id, source_task_id);
2478
2479 let blur_task_id =
2484 RenderTask::new_blur(
2485 adjusted_blur_std_deviation,
2486 input_subregion_task_id,
2487 rg_builder,
2488 RenderTargetKind::Color,
2489 None,
2490 adjusted_blur_task_size.to_i32(),
2491 );
2492
2493 let blur_subregion_translated = blur_subregion
2496 .translate(LayoutVector2D::new(dx, dy));
2497 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2498 node_task_size,
2499 RenderTaskKind::SVGFENode(
2500 SVGFEFilterTask{
2501 node: FilterGraphNode{
2502 kept_by_optimizer: true,
2503 linear: node.linear,
2504 inflate: node_inflate,
2505 inputs: [
2506 *blur_input,
2508 FilterGraphPictureReference{
2510 buffer_id: blur_input.buffer_id,
2511 subregion: blur_subregion_translated,
2512 inflate: 0,
2513 offset: LayoutVector2D::zero(),
2514 source_padding: LayoutRect::zero(),
2515 target_padding: LayoutRect::zero(),
2516 }].to_vec(),
2517 subregion,
2518 },
2519 op: FilterGraphOp::SVGFEDropShadow{
2520 color,
2521 dx: 0.0, dy: 0.0,
2523 std_deviation_x: 0.0, std_deviation_y: 0.0,
2524 },
2525 content_origin: node_task_rect.min,
2526 extra_gpu_cache_handle: None,
2527 }
2528 ),
2529 ).with_uv_rect_kind(node_uv_rect_kind));
2530 rg_builder.add_dependency(task_id, source_task_id);
2532 rg_builder.add_dependency(task_id, blur_task_id);
2533 }
2534 FilterGraphOp::SVGFESourceAlpha |
2535 FilterGraphOp::SVGFESourceGraphic => {
2536 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2541 node_task_size,
2542 RenderTaskKind::SVGFENode(
2543 SVGFEFilterTask{
2544 node: FilterGraphNode{
2545 kept_by_optimizer: true,
2546 linear: node.linear,
2547 inflate: node_inflate,
2548 inputs: [
2549 FilterGraphPictureReference{
2550 buffer_id: FilterOpGraphPictureBufferId::None,
2551 subregion: source_subregion.cast_unit(),
2554 offset: LayoutVector2D::zero(),
2555 inflate: 0,
2556 source_padding: LayoutRect::zero(),
2557 target_padding: LayoutRect::zero(),
2558 }
2559 ].to_vec(),
2560 subregion: source_subregion.cast_unit(),
2561 },
2562 op: op.clone(),
2563 content_origin: source_subregion.min.cast_unit(),
2564 extra_gpu_cache_handle: None,
2565 }
2566 ),
2567 ).with_uv_rect_kind(node_uv_rect_kind));
2568 rg_builder.add_dependency(task_id, original_task_id);
2569 made_dependency_on_source = true;
2570 }
2571 FilterGraphOp::SVGFEComponentTransferInterned { handle, creates_pixels: _ } => {
2572 let filter_data = &mut data_stores.filter_data[handle];
2575 filter_data.update(gpu_cache);
2576 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2579 node_task_size,
2580 RenderTaskKind::SVGFENode(
2581 SVGFEFilterTask{
2582 node: FilterGraphNode{
2583 kept_by_optimizer: true,
2584 linear: node.linear,
2585 inputs: node_inputs.iter().map(|input| {input.0}).collect(),
2586 subregion,
2587 inflate: node_inflate,
2588 },
2589 op: op.clone(),
2590 content_origin: node_task_rect.min,
2591 extra_gpu_cache_handle: Some(filter_data.gpu_cache_handle),
2592 }
2593 ),
2594 ).with_uv_rect_kind(node_uv_rect_kind));
2595
2596 for (_input, input_task) in &node_inputs {
2599 if *input_task == original_task_id {
2600 made_dependency_on_source = true;
2601 }
2602 if *input_task != RenderTaskId::INVALID {
2603 rg_builder.add_dependency(task_id, *input_task);
2604 }
2605 }
2606 }
2607 _ => {
2608 task_id = rg_builder.add().init(RenderTask::new_dynamic(
2611 node_task_size,
2612 RenderTaskKind::SVGFENode(
2613 SVGFEFilterTask{
2614 node: FilterGraphNode{
2615 kept_by_optimizer: true,
2616 linear: node.linear,
2617 inputs: node_inputs.iter().map(|input| {input.0}).collect(),
2618 subregion,
2619 inflate: node_inflate,
2620 },
2621 op: op.clone(),
2622 content_origin: node_task_rect.min,
2623 extra_gpu_cache_handle: None,
2624 }
2625 ),
2626 ).with_uv_rect_kind(node_uv_rect_kind));
2627
2628 for (_input, input_task) in &node_inputs {
2631 if *input_task == original_task_id {
2632 made_dependency_on_source = true;
2633 }
2634 if *input_task != RenderTaskId::INVALID {
2635 rg_builder.add_dependency(task_id, *input_task);
2636 }
2637 }
2638 }
2639 }
2640
2641 task_by_buffer_id[filter_index] = task_id;
2645 subregion_by_buffer_id[filter_index] = subregion;
2646
2647 output_task_id = task_id;
2649 }
2650
2651 if !made_dependency_on_source && output_task_id != original_task_id {
2654 rg_builder.add_dependency(output_task_id, original_task_id);
2655 }
2656
2657 output_task_id
2658 }
2659
2660 pub fn uv_rect_kind(&self) -> UvRectKind {
2661 self.uv_rect_kind
2662 }
2663
2664 pub fn get_texture_address(&self, gpu_cache: &GpuCache) -> GpuCacheAddress {
2665 gpu_cache.get_address(&self.uv_rect_handle)
2666 }
2667
2668 pub fn get_target_texture(&self) -> CacheTextureId {
2669 match self.location {
2670 RenderTaskLocation::Dynamic { texture_id, .. } => {
2671 assert_ne!(texture_id, CacheTextureId::INVALID);
2672 texture_id
2673 }
2674 RenderTaskLocation::Static { surface: StaticRenderTaskSurface::TextureCache { texture, .. }, .. } => {
2675 texture
2676 }
2677 _ => {
2678 unreachable!();
2679 }
2680 }
2681 }
2682
2683 pub fn get_texture_source(&self) -> TextureSource {
2684 match self.location {
2685 RenderTaskLocation::Dynamic { texture_id, .. } => {
2686 assert_ne!(texture_id, CacheTextureId::INVALID);
2687 TextureSource::TextureCache(texture_id, Swizzle::default())
2688 }
2689 RenderTaskLocation::Static { surface: StaticRenderTaskSurface::ReadOnly { source }, .. } => {
2690 source
2691 }
2692 RenderTaskLocation::Static { surface: StaticRenderTaskSurface::TextureCache { texture, .. }, .. } => {
2693 TextureSource::TextureCache(texture, Swizzle::default())
2694 }
2695 RenderTaskLocation::Existing { .. } |
2696 RenderTaskLocation::Static { .. } |
2697 RenderTaskLocation::CacheRequest { .. } |
2698 RenderTaskLocation::Unallocated { .. } => {
2699 unreachable!();
2700 }
2701 }
2702 }
2703
2704 pub fn get_target_rect(&self) -> DeviceIntRect {
2705 match self.location {
2706 RenderTaskLocation::Dynamic { rect, .. } => rect,
2721 RenderTaskLocation::Static { rect, .. } => rect,
2722 RenderTaskLocation::Existing { .. } |
2723 RenderTaskLocation::CacheRequest { .. } |
2724 RenderTaskLocation::Unallocated { .. } => {
2725 panic!("bug: get_target_rect called before allocating");
2726 }
2727 }
2728 }
2729
2730 pub fn get_target_size(&self) -> DeviceIntSize {
2731 match self.location {
2732 RenderTaskLocation::Dynamic { rect, .. } => rect.size(),
2733 RenderTaskLocation::Static { rect, .. } => rect.size(),
2734 RenderTaskLocation::Existing { size, .. } => size,
2735 RenderTaskLocation::CacheRequest { size } => size,
2736 RenderTaskLocation::Unallocated { size } => size,
2737 }
2738 }
2739
2740 pub fn target_kind(&self) -> RenderTargetKind {
2741 self.kind.target_kind()
2742 }
2743
2744 pub fn write_gpu_blocks(
2745 &mut self,
2746 target_rect: DeviceIntRect,
2747 gpu_cache: &mut GpuCache,
2748 ) {
2749 profile_scope!("write_gpu_blocks");
2750
2751 self.kind.write_gpu_blocks(gpu_cache);
2752
2753 if self.cache_handle.is_some() {
2754 return;
2757 }
2758
2759 if let Some(mut request) = gpu_cache.request(&mut self.uv_rect_handle) {
2760 let p0 = target_rect.min.to_f32();
2761 let p1 = target_rect.max.to_f32();
2762 let image_source = ImageSource {
2763 p0,
2764 p1,
2765 user_data: [0.0; 4],
2766 uv_rect_kind: self.uv_rect_kind,
2767 };
2768 image_source.write_gpu_blocks(&mut request);
2769 }
2770 }
2771
2772 pub fn mark_cached(&mut self, handle: RenderTaskCacheEntryHandle) {
2777 self.cache_handle = Some(handle);
2778 }
2779}