1use api::units::*;
7use api::{ColorF, LineOrientation, BorderStyle};
8use crate::batch::{AlphaBatchBuilder, AlphaBatchContainer, BatchTextures};
9use crate::batch::{ClipBatcher, BatchBuilder, INVALID_SEGMENT_INDEX, ClipMaskInstanceList};
10use crate::render_task::{SubTask, RectangleClipSubTask, ImageClipSubTask};
11use crate::command_buffer::{CommandBufferList, QuadFlags};
12use crate::pattern::{Pattern, PatternKind, PatternShaderInput};
13use crate::segment::EdgeMask;
14use crate::spatial_tree::SpatialTree;
15use crate::clip::ClipStore;
16use crate::frame_builder::FrameGlobalResources;
17use crate::gpu_types::{BorderInstance, SVGFEFilterInstance, BlurDirection, BlurInstance, PrimitiveHeaders, ScalingInstance};
18use crate::gpu_types::{ZBufferIdGenerator, MaskInstance, BlurEdgeMode};
19use crate::gpu_types::{ZBufferId, PrimitiveInstanceData};
20use crate::internal_types::{CacheTextureId, FastHashMap, FrameAllocator, FrameMemory, FrameVec, TextureSource};
21use crate::svg_filter::FilterGraphOp;
22use crate::picture::{SurfaceInfo, ResolvedSurfaceTexture};
23use crate::tile_cache::{SliceId, TileCacheInstance};
24use crate::transform::TransformPalette;
25use crate::quad;
26use crate::prim_store::{PrimitiveInstance, PrimitiveStore, PrimitiveScratchBuffer};
27use crate::renderer::{BlendMode, GpuBufferAddress, GpuBufferBuilder};
28use crate::render_backend::DataStores;
29use crate::render_task::{RenderTaskKind, RenderTaskAddress};
30use crate::render_task::{RenderTask, ScalingTask, SVGFEFilterTask};
31use crate::render_task_graph::{RenderTaskGraph, RenderTaskId};
32use crate::resource_cache::ResourceCache;
33use crate::spatial_tree::SpatialNodeIndex;
34
35
36const STYLE_SOLID: i32 = ((BorderStyle::Solid as i32) << 8) | ((BorderStyle::Solid as i32) << 16);
37const STYLE_MASK: i32 = 0x00FF_FF00;
38
39#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
41#[cfg_attr(feature = "capture", derive(Serialize))]
42#[cfg_attr(feature = "replay", derive(Deserialize))]
43pub enum RenderTargetKind {
44 Color, Alpha, }
47
48pub struct RenderTargetContext<'a, 'rc> {
49 pub global_device_pixel_scale: DevicePixelScale,
50 pub prim_store: &'a PrimitiveStore,
51 pub resource_cache: &'rc mut ResourceCache,
52 pub use_dual_source_blending: bool,
53 pub use_advanced_blending: bool,
54 pub break_advanced_blend_batches: bool,
55 pub batch_lookback_count: usize,
56 pub spatial_tree: &'a SpatialTree,
57 pub data_stores: &'a DataStores,
58 pub surfaces: &'a [SurfaceInfo],
59 pub scratch: &'a PrimitiveScratchBuffer,
60 pub screen_world_rect: WorldRect,
61 pub globals: &'a FrameGlobalResources,
62 pub tile_caches: &'a FastHashMap<SliceId, Box<TileCacheInstance>>,
63 pub root_spatial_node_index: SpatialNodeIndex,
64 pub frame_memory: &'a mut FrameMemory,
65}
66
67#[cfg_attr(feature = "capture", derive(Serialize))]
93#[cfg_attr(feature = "replay", derive(Deserialize))]
94pub struct RenderTargetList {
95 pub targets: FrameVec<RenderTarget>,
96}
97
98impl RenderTargetList {
99 pub fn new(allocator: FrameAllocator) -> Self {
100 RenderTargetList {
101 targets: allocator.new_vec(),
102 }
103 }
104
105 pub fn build(
106 &mut self,
107 ctx: &mut RenderTargetContext,
108 render_tasks: &RenderTaskGraph,
109 prim_headers: &mut PrimitiveHeaders,
110 transforms: &mut TransformPalette,
111 z_generator: &mut ZBufferIdGenerator,
112 prim_instances: &[PrimitiveInstance],
113 cmd_buffers: &CommandBufferList,
114 gpu_buffer_builder: &mut GpuBufferBuilder,
115 ) {
116 if self.targets.is_empty() {
117 return;
118 }
119
120 for target in &mut self.targets {
121 target.build(
122 ctx,
123 render_tasks,
124 prim_headers,
125 transforms,
126 z_generator,
127 prim_instances,
128 cmd_buffers,
129 gpu_buffer_builder,
130 );
131 }
132 }
133}
134
135const NUM_PATTERNS: usize = crate::pattern::NUM_PATTERNS as usize;
136
137#[cfg_attr(feature = "capture", derive(Serialize))]
148#[cfg_attr(feature = "replay", derive(Deserialize))]
149pub struct RenderTarget {
150 pub target_kind: RenderTargetKind,
151 pub cached: bool,
152 screen_size: DeviceIntSize,
153 pub texture_id: CacheTextureId,
154
155 pub alpha_batch_containers: FrameVec<AlphaBatchContainer>,
156 pub vertical_blurs: FastHashMap<TextureSource, FrameVec<BlurInstance>>,
158 pub horizontal_blurs: FastHashMap<TextureSource, FrameVec<BlurInstance>>,
159 pub scalings: FastHashMap<TextureSource, FrameVec<ScalingInstance>>,
160 pub svg_nodes: FrameVec<(BatchTextures, FrameVec<SVGFEFilterInstance>)>,
161 pub blits: FrameVec<BlitJob>,
162 alpha_tasks: FrameVec<RenderTaskId>,
163 pub resolve_ops: FrameVec<ResolveOp>,
164
165 pub prim_instances: [FastHashMap<TextureSource, FrameVec<PrimitiveInstanceData>>; NUM_PATTERNS],
166 pub prim_instances_with_scissor: FastHashMap<(DeviceIntRect, PatternKind), FastHashMap<TextureSource, FrameVec<PrimitiveInstanceData>>>,
167
168 pub clip_masks: ClipMaskInstanceList,
169
170 pub border_segments_complex: FrameVec<BorderInstance>,
171 pub border_segments_solid: FrameVec<BorderInstance>,
172 pub line_decorations: FrameVec<LineDecorationJob>,
173
174 pub clip_batcher: ClipBatcher,
175
176 pub clears: FrameVec<(DeviceIntRect, ColorF)>,
192
193 pub used_rect: Option<DeviceIntRect>,
199 pub clear_color: Option<ColorF>,
203}
204
205impl RenderTarget {
206 pub fn new(
207 target_kind: RenderTargetKind,
208 cached: bool,
209 texture_id: CacheTextureId,
210 screen_size: DeviceIntSize,
211 gpu_supports_fast_clears: bool,
212 used_rect: Option<DeviceIntRect>,
213 memory: &FrameMemory,
214 ) -> Self {
215 RenderTarget {
216 target_kind,
217 cached,
218 screen_size,
219 texture_id,
220 alpha_batch_containers: memory.new_vec(),
221 vertical_blurs: FastHashMap::default(),
222 horizontal_blurs: FastHashMap::default(),
223 scalings: FastHashMap::default(),
224 svg_nodes: memory.new_vec(),
225 blits: memory.new_vec(),
226 alpha_tasks: memory.new_vec(),
227 used_rect,
228 resolve_ops: memory.new_vec(),
229 clear_color: Some(ColorF::TRANSPARENT),
230 prim_instances: [
231 FastHashMap::default(),
232 FastHashMap::default(),
233 FastHashMap::default(),
234 FastHashMap::default(),
235 FastHashMap::default(),
236 FastHashMap::default(),
237 FastHashMap::default(),
238 FastHashMap::default(),
239 ],
240 prim_instances_with_scissor: FastHashMap::default(),
241 clip_masks: ClipMaskInstanceList::new(memory),
242 clip_batcher: ClipBatcher::new(gpu_supports_fast_clears, memory),
243 border_segments_complex: memory.new_vec(),
244 border_segments_solid: memory.new_vec(),
245 clears: memory.new_vec(),
246 line_decorations: memory.new_vec(),
247 }
248 }
249
250 pub fn build(
251 &mut self,
252 ctx: &mut RenderTargetContext,
253 render_tasks: &RenderTaskGraph,
254 prim_headers: &mut PrimitiveHeaders,
255 transforms: &mut TransformPalette,
256 z_generator: &mut ZBufferIdGenerator,
257 prim_instances: &[PrimitiveInstance],
258 cmd_buffers: &CommandBufferList,
259 gpu_buffer_builder: &mut GpuBufferBuilder,
260 ) {
261 profile_scope!("build");
262 let mut merged_batches = AlphaBatchContainer::new(None, &ctx.frame_memory);
263
264 for task_id in &self.alpha_tasks {
265 profile_scope!("alpha_task");
266 let task = &render_tasks[*task_id];
267
268 match task.kind {
269 RenderTaskKind::Picture(ref pic_task) => {
270 let target_rect = task.get_target_rect();
271
272 let scissor_rect = if pic_task.can_merge {
273 None
274 } else {
275 Some(target_rect)
276 };
277
278 if !pic_task.can_use_shared_surface {
279 self.clear_color = pic_task.clear_color;
280 }
281 if let Some(clear_color) = pic_task.clear_color {
282 self.clears.push((target_rect, clear_color));
283 } else if self.cached {
284 self.clears.push((target_rect, ColorF::TRANSPARENT));
285 }
286
287 let alpha_batch_builder = AlphaBatchBuilder::new(
293 self.screen_size,
294 ctx.break_advanced_blend_batches,
295 ctx.batch_lookback_count,
296 *task_id,
297 (*task_id).into(),
298 &ctx.frame_memory,
299 );
300
301 let mut batch_builder = BatchBuilder::new(alpha_batch_builder);
302 let cmd_buffer = cmd_buffers.get(pic_task.cmd_buffer_index);
303
304 cmd_buffer.iter_prims(&mut |cmd, spatial_node_index, segments| {
305 batch_builder.add_prim_to_batch(
306 cmd,
307 spatial_node_index,
308 ctx,
309 render_tasks,
310 prim_headers,
311 transforms,
312 pic_task.raster_spatial_node_index,
313 pic_task.surface_spatial_node_index,
314 z_generator,
315 prim_instances,
316 gpu_buffer_builder,
317 segments,
318 );
319 });
320
321 let alpha_batch_builder = batch_builder.finalize();
322
323 alpha_batch_builder.build(
324 &mut self.alpha_batch_containers,
325 &mut merged_batches,
326 target_rect,
327 scissor_rect,
328 );
329 }
330 _ => {
331 unreachable!();
332 }
333 }
334 }
335
336 if !merged_batches.is_empty() {
337 self.alpha_batch_containers.push(merged_batches);
338 }
339 }
340
341 pub fn texture_id(&self) -> CacheTextureId {
342 self.texture_id
343 }
344
345 pub fn add_task(
346 &mut self,
347 task_id: RenderTaskId,
348 ctx: &RenderTargetContext,
349 gpu_buffer_builder: &mut GpuBufferBuilder,
350 render_tasks: &RenderTaskGraph,
351 clip_store: &ClipStore,
352 transforms: &mut TransformPalette,
353 ) {
354 profile_scope!("add_task");
355 let task = &render_tasks[task_id];
356 let target_rect = task.get_target_rect();
357
358 match task.kind {
359 RenderTaskKind::Prim(ref info) => {
360 if !info.transform_id.is_2d_axis_aligned() {
363 self.clears.push((target_rect, ColorF::TRANSPARENT));
364 }
365 let render_task_address = task_id.into();
369 quad::add_to_batch(
370 info.pattern,
371 info.pattern_input,
372 render_task_address,
373 info.transform_id,
374 info.prim_address_f,
375 info.quad_flags | QuadFlags::IS_OPAQUE,
376 info.edge_flags,
377 INVALID_SEGMENT_INDEX as u8,
378 info.texture_input,
379 ZBufferId(0),
380 BlendMode::None, render_tasks,
382 gpu_buffer_builder,
383 |key, instance| {
384 if info.prim_needs_scissor_rect {
385 self.prim_instances_with_scissor
386 .entry((target_rect, info.pattern))
387 .or_insert(FastHashMap::default())
388 .entry(key.textures.input.colors[0])
389 .or_insert_with(|| ctx.frame_memory.new_vec())
390 .push(instance);
391 } else {
392 self.prim_instances[info.pattern as usize]
393 .entry(key.textures.input.colors[0])
394 .or_insert_with(|| ctx.frame_memory.new_vec())
395 .push(instance);
396 }
397 }
398 );
399 }
400 RenderTaskKind::VerticalBlur(ref info) => {
401 if self.target_kind == RenderTargetKind::Alpha {
402 self.clears.push((target_rect, ColorF::TRANSPARENT));
403 }
404 add_blur_instances(
405 &mut self.vertical_blurs,
406 BlurDirection::Vertical,
407 info.blur_std_deviation,
408 info.blur_region,
409 info.edge_mode,
410 task_id.into(),
411 task.children[0],
412 render_tasks,
413 &ctx.frame_memory,
414 );
415 }
416 RenderTaskKind::HorizontalBlur(ref info) => {
417 if self.target_kind == RenderTargetKind::Alpha {
418 self.clears.push((target_rect, ColorF::TRANSPARENT));
419 }
420 add_blur_instances(
421 &mut self.horizontal_blurs,
422 BlurDirection::Horizontal,
423 info.blur_std_deviation,
424 info.blur_region,
425 info.edge_mode,
426 task_id.into(),
427 task.children[0],
428 render_tasks,
429 &ctx.frame_memory,
430 );
431 }
432 RenderTaskKind::Picture(ref pic_task) => {
433 if let Some(ref resolve_op) = pic_task.resolve_op {
434 self.resolve_ops.push(resolve_op.clone());
435 }
436 self.alpha_tasks.push(task_id);
437 }
438 RenderTaskKind::SVGFENode(ref task_info) => {
439 add_svg_filter_node_instances(
440 &mut self.svg_nodes,
441 render_tasks,
442 &task_info,
443 task,
444 task.children.get(0).cloned(),
445 task.children.get(1).cloned(),
446 task_info.extra_gpu_data,
447 &ctx.frame_memory,
448 )
449 }
450 RenderTaskKind::Empty(..) => {
451 self.clears.push((target_rect, ColorF::WHITE));
455 }
456 RenderTaskKind::CacheMask(ref task_info) => {
457 let clear_to_one = self.clip_batcher.add(
458 task_info.clip_node_range,
459 task_info.root_spatial_node_index,
460 clip_store,
461 transforms,
462 task_info.actual_rect,
463 task_info.device_pixel_scale,
464 target_rect.min.to_f32(),
465 task_info.actual_rect.min,
466 ctx,
467 );
468 if task_info.clear_to_one || clear_to_one {
469 self.clears.push((target_rect, ColorF::WHITE));
470 }
471 }
472 RenderTaskKind::ClipRegion(ref region_task) => {
473 if region_task.clear_to_one {
474 self.clears.push((target_rect, ColorF::WHITE));
475 }
476 let device_rect = DeviceRect::from_size(
477 target_rect.size().to_f32(),
478 );
479 self.clip_batcher.add_clip_region(
480 region_task.local_pos,
481 device_rect,
482 region_task.clip_data.clone(),
483 target_rect.min.to_f32(),
484 DevicePoint::zero(),
485 region_task.device_pixel_scale.0,
486 );
487 }
488 RenderTaskKind::Scaling(ref info) => {
489 add_scaling_instances(
490 info,
491 &mut self.scalings,
492 task,
493 task.children.first().map(|&child| &render_tasks[child]),
494 &ctx.frame_memory,
495 );
496 }
497 RenderTaskKind::Blit(ref task_info) => {
498 let target_rect = task.get_target_rect();
499 self.blits.push(BlitJob {
500 source: task_info.source,
501 source_rect: task_info.source_rect,
502 target_rect,
503 });
504 }
505 RenderTaskKind::LineDecoration(ref info) => {
506 self.clears.push((target_rect, ColorF::TRANSPARENT));
507
508 self.line_decorations.push(LineDecorationJob {
509 task_rect: target_rect.to_f32(),
510 local_size: info.local_size,
511 style: info.style as i32,
512 axis_select: match info.orientation {
513 LineOrientation::Horizontal => 0.0,
514 LineOrientation::Vertical => 1.0,
515 },
516 wavy_line_thickness: info.wavy_line_thickness,
517 });
518 }
519 RenderTaskKind::Border(ref task_info) => {
520 self.clears.push((target_rect, ColorF::TRANSPARENT));
521
522 let task_origin = target_rect.min.to_f32();
523 let instances = task_info.instances.clone();
528 for mut instance in instances {
529 instance.task_origin = task_origin;
532 if instance.flags & STYLE_MASK == STYLE_SOLID {
533 self.border_segments_solid.push(instance);
534 } else {
535 self.border_segments_complex.push(instance);
536 }
537 }
538 }
539 RenderTaskKind::Image(..) |
540 RenderTaskKind::Cached(..) |
541 RenderTaskKind::TileComposite(..) => {
542 panic!("Should not be added to color target!");
543 }
544 RenderTaskKind::Readback(..) => {}
545 #[cfg(test)]
546 RenderTaskKind::Test(..) => {}
547 }
548
549 let task_address = task_id.into();
550 for sub_task_id in task.sub_tasks.clone() {
551 let sub_task = &render_tasks[sub_task_id];
552 match sub_task {
553 SubTask::RectangleClip(clip_task) => {
554 add_rect_clip_task_to_batch(
555 clip_task,
556 &target_rect,
557 task_address,
558 &ctx.frame_memory,
559 render_tasks,
560 gpu_buffer_builder,
561 &mut self.clip_masks
562 );
563 }
564 SubTask::ImageClip(clip_task) => {
565 add_image_clip_task_to_batch(
566 clip_task,
567 &target_rect,
568 task_address,
569 &ctx.frame_memory,
570 render_tasks,
571 gpu_buffer_builder,
572 &mut self.clip_masks
573 );
574 }
575 }
576 }
577 }
578
579 pub fn needs_depth(&self) -> bool {
580 self.alpha_batch_containers.iter().any(|ab| {
581 !ab.opaque_batches.is_empty()
582 })
583 }
584}
585
586#[cfg_attr(feature = "capture", derive(Serialize))]
587#[cfg_attr(feature = "replay", derive(Deserialize))]
588#[derive(Debug, PartialEq, Clone)]
589pub struct ResolveOp {
590 pub src_task_ids: Vec<RenderTaskId>,
591 pub dest_task_id: RenderTaskId,
592}
593
594#[cfg_attr(feature = "capture", derive(Serialize))]
595#[cfg_attr(feature = "replay", derive(Deserialize))]
596pub enum PictureCacheTargetKind {
597 Draw {
598 alpha_batch_container: AlphaBatchContainer,
599 },
600 Blit {
601 task_id: RenderTaskId,
602 sub_rect_offset: DeviceIntVector2D,
603 },
604}
605
606#[cfg_attr(feature = "capture", derive(Serialize))]
607#[cfg_attr(feature = "replay", derive(Deserialize))]
608pub struct PictureCacheTarget {
609 pub surface: ResolvedSurfaceTexture,
610 pub kind: PictureCacheTargetKind,
611 pub clear_color: Option<ColorF>,
612 pub dirty_rect: DeviceIntRect,
613 pub valid_rect: DeviceIntRect,
614}
615
616fn add_blur_instances(
617 instances: &mut FastHashMap<TextureSource, FrameVec<BlurInstance>>,
618 blur_direction: BlurDirection,
619 blur_std_deviation: f32,
620 blur_region: DeviceIntSize,
621 edge_mode: BlurEdgeMode,
622 task_address: RenderTaskAddress,
623 src_task_id: RenderTaskId,
624 render_tasks: &RenderTaskGraph,
625 memory: &FrameMemory,
626) {
627 let source = render_tasks[src_task_id].get_texture_source();
628
629 let instance = BlurInstance {
630 task_address,
631 src_task_address: src_task_id.into(),
632 blur_direction: blur_direction.as_int(),
633 blur_std_deviation,
634 edge_mode: edge_mode.as_int(),
635 blur_region: blur_region.to_f32(),
636 };
637
638 instances
639 .entry(source)
640 .or_insert_with(|| memory.new_vec())
641 .push(instance);
642}
643
644fn add_scaling_instances(
645 task: &ScalingTask,
646 instances: &mut FastHashMap<TextureSource, FrameVec<ScalingInstance>>,
647 target_task: &RenderTask,
648 source_task: Option<&RenderTask>,
649 memory: &FrameMemory,
650) {
651 let target_rect = target_task
652 .get_target_rect()
653 .inner_box(task.padding)
654 .to_f32();
655
656 let source = source_task.unwrap().get_texture_source();
657
658 let source_rect = source_task.unwrap().get_target_rect().to_f32();
659
660 instances
661 .entry(source)
662 .or_insert_with(|| memory.new_vec())
663 .push(ScalingInstance::new(
664 target_rect,
665 source_rect,
666 source.uses_normalized_uvs(),
667 ));
668}
669
670fn add_svg_filter_node_instances(
679 instances: &mut FrameVec<(BatchTextures, FrameVec<SVGFEFilterInstance>)>,
680 render_tasks: &RenderTaskGraph,
681 task_info: &SVGFEFilterTask,
682 target_task: &RenderTask,
683 input_1_task: Option<RenderTaskId>,
684 input_2_task: Option<RenderTaskId>,
685 extra_data_address: Option<GpuBufferAddress>,
686 memory: &FrameMemory,
687) {
688 let node = &task_info.node;
689 let op = &task_info.op;
690 let mut textures = BatchTextures::empty();
691
692 let target_rect = target_task
695 .get_target_rect()
696 .inner_box(DeviceIntSideOffsets::new(node.inflate as i32, node.inflate as i32, node.inflate as i32, node.inflate as i32))
697 .to_f32();
698
699 let mut instance = SVGFEFilterInstance {
700 target_rect,
701 input_1_content_scale_and_offset: [0.0; 4],
702 input_2_content_scale_and_offset: [0.0; 4],
703 input_1_task_address: RenderTaskId::INVALID.into(),
704 input_2_task_address: RenderTaskId::INVALID.into(),
705 kind: 0,
706 input_count: node.inputs.len() as u16,
707 extra_data_address: extra_data_address.unwrap_or(GpuBufferAddress::INVALID).as_int(),
708 };
709
710 instance.kind = match op {
712 FilterGraphOp::SVGFEIdentity => 0,
714 FilterGraphOp::SVGFESourceGraphic => 0,
716 FilterGraphOp::SVGFESourceAlpha => 4,
718 FilterGraphOp::SVGFEOpacity{..} => 2,
722 FilterGraphOp::SVGFEToAlpha => 4,
723 FilterGraphOp::SVGFEBlendColor => {match node.linear {false => 6, true => 7}},
724 FilterGraphOp::SVGFEBlendColorBurn => {match node.linear {false => 8, true => 9}},
725 FilterGraphOp::SVGFEBlendColorDodge => {match node.linear {false => 10, true => 11}},
726 FilterGraphOp::SVGFEBlendDarken => {match node.linear {false => 12, true => 13}},
727 FilterGraphOp::SVGFEBlendDifference => {match node.linear {false => 14, true => 15}},
728 FilterGraphOp::SVGFEBlendExclusion => {match node.linear {false => 16, true => 17}},
729 FilterGraphOp::SVGFEBlendHardLight => {match node.linear {false => 18, true => 19}},
730 FilterGraphOp::SVGFEBlendHue => {match node.linear {false => 20, true => 21}},
731 FilterGraphOp::SVGFEBlendLighten => {match node.linear {false => 22, true => 23}},
732 FilterGraphOp::SVGFEBlendLuminosity => {match node.linear {false => 24, true => 25}},
733 FilterGraphOp::SVGFEBlendMultiply => {match node.linear {false => 26, true => 27}},
734 FilterGraphOp::SVGFEBlendNormal => {match node.linear {false => 28, true => 29}},
735 FilterGraphOp::SVGFEBlendOverlay => {match node.linear {false => 30, true => 31}},
736 FilterGraphOp::SVGFEBlendSaturation => {match node.linear {false => 32, true => 33}},
737 FilterGraphOp::SVGFEBlendScreen => {match node.linear {false => 34, true => 35}},
738 FilterGraphOp::SVGFEBlendSoftLight => {match node.linear {false => 36, true => 37}},
739 FilterGraphOp::SVGFEColorMatrix{..} => {match node.linear {false => 38, true => 39}},
740 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
741 FilterGraphOp::SVGFEComponentTransferInterned{..} => {match node.linear {false => 40, true => 41}},
742 FilterGraphOp::SVGFECompositeArithmetic{..} => {match node.linear {false => 42, true => 43}},
743 FilterGraphOp::SVGFECompositeATop => {match node.linear {false => 44, true => 45}},
744 FilterGraphOp::SVGFECompositeIn => {match node.linear {false => 46, true => 47}},
745 FilterGraphOp::SVGFECompositeLighter => {match node.linear {false => 48, true => 49}},
746 FilterGraphOp::SVGFECompositeOut => {match node.linear {false => 50, true => 51}},
747 FilterGraphOp::SVGFECompositeOver => {match node.linear {false => 52, true => 53}},
748 FilterGraphOp::SVGFECompositeXOR => {match node.linear {false => 54, true => 55}},
749 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{..} => {match node.linear {false => 56, true => 57}},
750 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{..} => {match node.linear {false => 58, true => 59}},
751 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{..} => {match node.linear {false => 60, true => 61}},
752 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {match node.linear {false => 62, true => 63}},
753 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {match node.linear {false => 64, true => 65}},
754 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {match node.linear {false => 66, true => 67}},
755 FilterGraphOp::SVGFEDisplacementMap{..} => {match node.linear {false => 68, true => 69}},
756 FilterGraphOp::SVGFEDropShadow{..} => {match node.linear {false => 70, true => 71}},
757 FilterGraphOp::SVGFEFlood{..} => 72,
759 FilterGraphOp::SVGFEGaussianBlur{..} => {match node.linear {false => 74, true => 75}},
760 FilterGraphOp::SVGFEImage{..} => 76,
764 FilterGraphOp::SVGFEMorphologyDilate{..} => {match node.linear {false => 80, true => 81}},
765 FilterGraphOp::SVGFEMorphologyErode{..} => {match node.linear {false => 82, true => 83}},
766 FilterGraphOp::SVGFESpecularLightingDistant{..} => {match node.linear {false => 86, true => 87}},
767 FilterGraphOp::SVGFESpecularLightingPoint{..} => {match node.linear {false => 88, true => 89}},
768 FilterGraphOp::SVGFESpecularLightingSpot{..} => {match node.linear {false => 90, true => 91}},
769 FilterGraphOp::SVGFETile => 92,
771 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} => {match node.linear {false => 94, true => 95}},
772 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} => {match node.linear {false => 96, true => 97}},
773 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} => {match node.linear {false => 98, true => 99}},
774 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {match node.linear {false => 100, true => 101}},
775 };
776
777 let mut resolve_input = |index: usize, src_task: Option<RenderTaskId>| -> (RenderTaskAddress, [f32; 4]) {
779 let mut src_task_id = RenderTaskId::INVALID;
780 let mut resolved_scale_and_offset: [f32; 4] = [0.0; 4];
781 if let Some(input) = node.inputs.get(index) {
782 src_task_id = src_task.unwrap();
783 let src_task = &render_tasks[src_task_id];
784
785 textures.input.colors[index] = src_task.get_texture_source();
786 let src_task_size = src_task.location.size();
787 let src_scale_x = (src_task_size.width as f32 - input.inflate as f32 * 2.0) / input.subregion.width();
788 let src_scale_y = (src_task_size.height as f32 - input.inflate as f32 * 2.0) / input.subregion.height();
789 let scale_x = src_scale_x * node.subregion.width();
790 let scale_y = src_scale_y * node.subregion.height();
791 let offset_x = src_scale_x * (node.subregion.min.x - input.subregion.min.x) + input.inflate as f32;
792 let offset_y = src_scale_y * (node.subregion.min.y - input.subregion.min.y) + input.inflate as f32;
793 resolved_scale_and_offset = [
794 scale_x,
795 scale_y,
796 offset_x,
797 offset_y];
798 }
799 let address: RenderTaskAddress = src_task_id.into();
800 (address, resolved_scale_and_offset)
801 };
802 (instance.input_1_task_address, instance.input_1_content_scale_and_offset) = resolve_input(0, input_1_task);
803 (instance.input_2_task_address, instance.input_2_content_scale_and_offset) = resolve_input(1, input_2_task);
804
805 match op {
807 FilterGraphOp::SVGFEOpacity { valuebinding: _, value } => {
808 instance.input_2_content_scale_and_offset = [*value, 0.0, 0.0, 0.0];
811 },
812 FilterGraphOp::SVGFEMorphologyDilate { radius_x, radius_y } |
813 FilterGraphOp::SVGFEMorphologyErode { radius_x, radius_y } => {
814 instance.input_2_content_scale_and_offset = [*radius_x, *radius_y, 0.0, 0.0];
817 },
818 FilterGraphOp::SVGFEFlood { color } => {
819 instance.input_2_content_scale_and_offset = [color.r, color.g, color.b, color.a];
823 },
824 _ => {},
825 }
826
827 for (ref mut batch_textures, ref mut batch) in instances.iter_mut() {
828 if let Some(combined_textures) = batch_textures.combine_textures(textures) {
829 batch.push(instance);
830 *batch_textures = combined_textures;
832 return;
834 }
835 }
836
837 let mut vec = memory.new_vec();
838 vec.push(instance);
839
840 instances.push((textures, vec));
841}
842
843#[cfg_attr(feature = "capture", derive(Serialize))]
845#[cfg_attr(feature = "replay", derive(Deserialize))]
846pub struct BlitJob {
847 pub source: RenderTaskId,
848 pub source_rect: DeviceIntRect,
850 pub target_rect: DeviceIntRect,
851}
852
853#[cfg_attr(feature = "capture", derive(Serialize))]
854#[cfg_attr(feature = "replay", derive(Deserialize))]
855#[repr(C)]
856#[derive(Clone, Debug)]
857pub struct LineDecorationJob {
858 pub task_rect: DeviceRect,
859 pub local_size: LayoutSize,
860 pub wavy_line_thickness: f32,
861 pub style: i32,
862 pub axis_select: f32,
863}
864
865fn add_rect_clip_task_to_batch(
866 task: &RectangleClipSubTask,
867 target_rect: &DeviceIntRect,
868 masked_task_address: RenderTaskAddress,
869 memory: &FrameMemory,
870 render_tasks: &RenderTaskGraph,
871 gpu_buffers: &mut GpuBufferBuilder,
872 results: &mut ClipMaskInstanceList,
873) {
874 quad::add_to_batch(
875 PatternKind::Mask,
876 PatternShaderInput::default(),
877 masked_task_address,
878 task.quad_transform_id,
879 task.quad_address,
880 task.quad_flags,
881 EdgeMask::empty(),
882 INVALID_SEGMENT_INDEX as u8,
883 RenderTaskId::INVALID,
884 ZBufferId(0),
885 BlendMode::None, render_tasks,
887 gpu_buffers,
888 |_, prim| {
889 let instance = MaskInstance {
890 prim,
891 clip_transform_id: task.clip_transform_id,
892 clip_address: task.clip_address.as_int(),
893 clip_space: task.clip_space.as_int(),
894 unused: 0,
895 };
896
897 if task.needs_scissor_rect {
898 if task.rounded_rect_fast_path {
899 results.mask_instances_fast_with_scissor
900 .entry(*target_rect)
901 .or_insert_with(|| memory.new_vec())
902 .push(instance);
903 } else {
904 results.mask_instances_slow_with_scissor
905 .entry(*target_rect)
906 .or_insert_with(|| memory.new_vec())
907 .push(instance);
908 }
909 } else {
910 if task.rounded_rect_fast_path {
911 results.mask_instances_fast.push(instance);
912 } else {
913 results.mask_instances_slow.push(instance);
914 }
915 }
916 }
917 );
918}
919
920fn add_image_clip_task_to_batch(
921 task: &ImageClipSubTask,
922 target_rect: &DeviceIntRect,
923 masked_task_address: RenderTaskAddress,
924 memory: &FrameMemory,
925 render_tasks: &RenderTaskGraph,
926 gpu_buffers: &mut GpuBufferBuilder,
927 results: &mut ClipMaskInstanceList,
928) {
929 let segment_index = 0;
933
934 let pattern = Pattern::texture(task.src_task, false);
935
936 quad::add_to_batch(
937 pattern.kind,
938 pattern.shader_input,
939 masked_task_address,
940 task.quad_transform_id,
941 task.quad_address,
942 task.quad_flags,
943 EdgeMask::empty(),
944 segment_index,
945 task.src_task,
946 ZBufferId(0),
947 BlendMode::None, render_tasks,
949 gpu_buffers,
950 |_, prim| {
951 let texture = render_tasks
952 .resolve_texture(task.src_task)
953 .expect("bug: texture not found for tile");
954
955 if task.needs_scissor_rect {
956 results
957 .image_mask_instances_with_scissor
958 .entry((*target_rect, texture))
959 .or_insert_with(|| memory.new_vec())
960 .push(prim);
961 } else {
962 results
963 .image_mask_instances
964 .entry(texture)
965 .or_insert_with(|| memory.new_vec())
966 .push(prim);
967 }
968 }
969 );
970}