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::command_buffer::{CommandBufferList, QuadFlags};
11use crate::pattern::{Pattern, PatternKind, PatternShaderInput};
12use crate::segment::EdgeAaSegmentMask;
13use crate::spatial_tree::SpatialTree;
14use crate::clip::{ClipStore, ClipItemKind};
15use crate::frame_builder::FrameGlobalResources;
16use crate::gpu_cache::{GpuCache, GpuCacheAddress};
17use crate::gpu_types::{BorderInstance, SvgFilterInstance, SVGFEFilterInstance, BlurDirection, BlurInstance, PrimitiveHeaders, ScalingInstance};
18use crate::gpu_types::{TransformPalette, ZBufferIdGenerator, MaskInstance, ClipSpace};
19use crate::gpu_types::{ZBufferId, QuadSegment, PrimitiveInstanceData, TransformPaletteId};
20use crate::internal_types::{CacheTextureId, FastHashMap, FilterGraphOp, FrameAllocator, FrameMemory, FrameVec, TextureSource};
21use crate::picture::{SliceId, SurfaceInfo, ResolvedSurfaceTexture, TileCacheInstance};
22use crate::quad;
23use crate::prim_store::{PrimitiveInstance, PrimitiveStore, PrimitiveScratchBuffer};
24use crate::prim_store::gradient::{
25 FastLinearGradientInstance, LinearGradientInstance, RadialGradientInstance,
26 ConicGradientInstance,
27};
28use crate::renderer::{GpuBufferAddress, GpuBufferBuilder};
29use crate::render_backend::DataStores;
30use crate::render_task::{RenderTaskKind, RenderTaskAddress, SubPass};
31use crate::render_task::{RenderTask, ScalingTask, SvgFilterInfo, MaskSubPass, SVGFEFilterTask};
32use crate::render_task_graph::{RenderTaskGraph, RenderTaskId};
33use crate::resource_cache::ResourceCache;
34use crate::spatial_tree::SpatialNodeIndex;
35use crate::util::ScaleOffset;
36
37
38const STYLE_SOLID: i32 = ((BorderStyle::Solid as i32) << 8) | ((BorderStyle::Solid as i32) << 16);
39const STYLE_MASK: i32 = 0x00FF_FF00;
40
41#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
43#[cfg_attr(feature = "capture", derive(Serialize))]
44#[cfg_attr(feature = "replay", derive(Deserialize))]
45pub enum RenderTargetKind {
46 Color, Alpha, }
49
50pub struct RenderTargetContext<'a, 'rc> {
51 pub global_device_pixel_scale: DevicePixelScale,
52 pub prim_store: &'a PrimitiveStore,
53 pub clip_store: &'a ClipStore,
54 pub resource_cache: &'rc mut ResourceCache,
55 pub use_dual_source_blending: bool,
56 pub use_advanced_blending: bool,
57 pub break_advanced_blend_batches: bool,
58 pub batch_lookback_count: usize,
59 pub spatial_tree: &'a SpatialTree,
60 pub data_stores: &'a DataStores,
61 pub surfaces: &'a [SurfaceInfo],
62 pub scratch: &'a PrimitiveScratchBuffer,
63 pub screen_world_rect: WorldRect,
64 pub globals: &'a FrameGlobalResources,
65 pub tile_caches: &'a FastHashMap<SliceId, Box<TileCacheInstance>>,
66 pub root_spatial_node_index: SpatialNodeIndex,
67 pub frame_memory: &'a mut FrameMemory,
68}
69
70#[cfg_attr(feature = "capture", derive(Serialize))]
96#[cfg_attr(feature = "replay", derive(Deserialize))]
97pub struct RenderTargetList {
98 pub targets: FrameVec<RenderTarget>,
99}
100
101impl RenderTargetList {
102 pub fn new(allocator: FrameAllocator) -> Self {
103 RenderTargetList {
104 targets: allocator.new_vec(),
105 }
106 }
107
108 pub fn build(
109 &mut self,
110 ctx: &mut RenderTargetContext,
111 gpu_cache: &mut GpuCache,
112 render_tasks: &RenderTaskGraph,
113 prim_headers: &mut PrimitiveHeaders,
114 transforms: &mut TransformPalette,
115 z_generator: &mut ZBufferIdGenerator,
116 prim_instances: &[PrimitiveInstance],
117 cmd_buffers: &CommandBufferList,
118 gpu_buffer_builder: &mut GpuBufferBuilder,
119 ) {
120 if self.targets.is_empty() {
121 return;
122 }
123
124 for target in &mut self.targets {
125 target.build(
126 ctx,
127 gpu_cache,
128 render_tasks,
129 prim_headers,
130 transforms,
131 z_generator,
132 prim_instances,
133 cmd_buffers,
134 gpu_buffer_builder,
135 );
136 }
137 }
138}
139
140const NUM_PATTERNS: usize = crate::pattern::NUM_PATTERNS as usize;
141
142#[cfg_attr(feature = "capture", derive(Serialize))]
153#[cfg_attr(feature = "replay", derive(Deserialize))]
154pub struct RenderTarget {
155 pub target_kind: RenderTargetKind,
156 pub cached: bool,
157 screen_size: DeviceIntSize,
158 pub texture_id: CacheTextureId,
159
160 pub alpha_batch_containers: FrameVec<AlphaBatchContainer>,
161 pub vertical_blurs: FastHashMap<TextureSource, FrameVec<BlurInstance>>,
163 pub horizontal_blurs: FastHashMap<TextureSource, FrameVec<BlurInstance>>,
164 pub scalings: FastHashMap<TextureSource, FrameVec<ScalingInstance>>,
165 pub svg_filters: FrameVec<(BatchTextures, FrameVec<SvgFilterInstance>)>,
166 pub svg_nodes: FrameVec<(BatchTextures, FrameVec<SVGFEFilterInstance>)>,
167 pub blits: FrameVec<BlitJob>,
168 alpha_tasks: FrameVec<RenderTaskId>,
169 pub resolve_ops: FrameVec<ResolveOp>,
170
171 pub prim_instances: [FastHashMap<TextureSource, FrameVec<PrimitiveInstanceData>>; NUM_PATTERNS],
172 pub prim_instances_with_scissor: FastHashMap<(DeviceIntRect, PatternKind), FastHashMap<TextureSource, FrameVec<PrimitiveInstanceData>>>,
173
174 pub clip_masks: ClipMaskInstanceList,
175
176 pub border_segments_complex: FrameVec<BorderInstance>,
177 pub border_segments_solid: FrameVec<BorderInstance>,
178 pub line_decorations: FrameVec<LineDecorationJob>,
179 pub fast_linear_gradients: FrameVec<FastLinearGradientInstance>,
180 pub linear_gradients: FrameVec<LinearGradientInstance>,
181 pub radial_gradients: FrameVec<RadialGradientInstance>,
182 pub conic_gradients: FrameVec<ConicGradientInstance>,
183
184 pub clip_batcher: ClipBatcher,
185
186 pub clears: FrameVec<(DeviceIntRect, ColorF)>,
202
203 pub used_rect: Option<DeviceIntRect>,
209 pub clear_color: Option<ColorF>,
213}
214
215impl RenderTarget {
216 pub fn new(
217 target_kind: RenderTargetKind,
218 cached: bool,
219 texture_id: CacheTextureId,
220 screen_size: DeviceIntSize,
221 gpu_supports_fast_clears: bool,
222 used_rect: Option<DeviceIntRect>,
223 memory: &FrameMemory,
224 ) -> Self {
225 RenderTarget {
226 target_kind,
227 cached,
228 screen_size,
229 texture_id,
230 alpha_batch_containers: memory.new_vec(),
231 vertical_blurs: FastHashMap::default(),
232 horizontal_blurs: FastHashMap::default(),
233 scalings: FastHashMap::default(),
234 svg_filters: memory.new_vec(),
235 svg_nodes: memory.new_vec(),
236 blits: memory.new_vec(),
237 alpha_tasks: memory.new_vec(),
238 used_rect,
239 resolve_ops: memory.new_vec(),
240 clear_color: Some(ColorF::TRANSPARENT),
241 prim_instances: [FastHashMap::default(), FastHashMap::default(), FastHashMap::default(), FastHashMap::default()],
242 prim_instances_with_scissor: FastHashMap::default(),
243 clip_masks: ClipMaskInstanceList::new(memory),
244 clip_batcher: ClipBatcher::new(gpu_supports_fast_clears, memory),
245 border_segments_complex: memory.new_vec(),
246 border_segments_solid: memory.new_vec(),
247 clears: memory.new_vec(),
248 line_decorations: memory.new_vec(),
249 fast_linear_gradients: memory.new_vec(),
250 linear_gradients: memory.new_vec(),
251 radial_gradients: memory.new_vec(),
252 conic_gradients: memory.new_vec(),
253 }
254 }
255
256 pub fn build(
257 &mut self,
258 ctx: &mut RenderTargetContext,
259 gpu_cache: &mut GpuCache,
260 render_tasks: &RenderTaskGraph,
261 prim_headers: &mut PrimitiveHeaders,
262 transforms: &mut TransformPalette,
263 z_generator: &mut ZBufferIdGenerator,
264 prim_instances: &[PrimitiveInstance],
265 cmd_buffers: &CommandBufferList,
266 gpu_buffer_builder: &mut GpuBufferBuilder,
267 ) {
268 profile_scope!("build");
269 let mut merged_batches = AlphaBatchContainer::new(None, &ctx.frame_memory);
270
271 for task_id in &self.alpha_tasks {
272 profile_scope!("alpha_task");
273 let task = &render_tasks[*task_id];
274
275 match task.kind {
276 RenderTaskKind::Picture(ref pic_task) => {
277 let target_rect = task.get_target_rect();
278
279 let scissor_rect = if pic_task.can_merge {
280 None
281 } else {
282 Some(target_rect)
283 };
284
285 if !pic_task.can_use_shared_surface {
286 self.clear_color = pic_task.clear_color;
287 }
288 if let Some(clear_color) = pic_task.clear_color {
289 self.clears.push((target_rect, clear_color));
290 } else if self.cached {
291 self.clears.push((target_rect, ColorF::TRANSPARENT));
292 }
293
294 let alpha_batch_builder = AlphaBatchBuilder::new(
300 self.screen_size,
301 ctx.break_advanced_blend_batches,
302 ctx.batch_lookback_count,
303 *task_id,
304 (*task_id).into(),
305 &ctx.frame_memory,
306 );
307
308 let mut batch_builder = BatchBuilder::new(alpha_batch_builder);
309 let cmd_buffer = cmd_buffers.get(pic_task.cmd_buffer_index);
310
311 cmd_buffer.iter_prims(&mut |cmd, spatial_node_index, segments| {
312 batch_builder.add_prim_to_batch(
313 cmd,
314 spatial_node_index,
315 ctx,
316 gpu_cache,
317 render_tasks,
318 prim_headers,
319 transforms,
320 pic_task.raster_spatial_node_index,
321 pic_task.surface_spatial_node_index,
322 z_generator,
323 prim_instances,
324 gpu_buffer_builder,
325 segments,
326 );
327 });
328
329 let alpha_batch_builder = batch_builder.finalize();
330
331 alpha_batch_builder.build(
332 &mut self.alpha_batch_containers,
333 &mut merged_batches,
334 target_rect,
335 scissor_rect,
336 );
337 }
338 _ => {
339 unreachable!();
340 }
341 }
342 }
343
344 if !merged_batches.is_empty() {
345 self.alpha_batch_containers.push(merged_batches);
346 }
347 }
348
349 pub fn texture_id(&self) -> CacheTextureId {
350 self.texture_id
351 }
352
353 pub fn add_task(
354 &mut self,
355 task_id: RenderTaskId,
356 ctx: &RenderTargetContext,
357 gpu_cache: &mut GpuCache,
358 gpu_buffer_builder: &mut GpuBufferBuilder,
359 render_tasks: &RenderTaskGraph,
360 clip_store: &ClipStore,
361 transforms: &mut TransformPalette,
362 ) {
363 profile_scope!("add_task");
364 let task = &render_tasks[task_id];
365 let target_rect = task.get_target_rect();
366
367 match task.kind {
368 RenderTaskKind::Prim(ref info) => {
369 let render_task_address = task_id.into();
370
371 quad::add_to_batch(
372 info.pattern,
373 info.pattern_input,
374 render_task_address,
375 info.transform_id,
376 info.prim_address_f,
377 info.quad_flags,
378 info.edge_flags,
379 INVALID_SEGMENT_INDEX as u8,
380 info.texture_input,
381 ZBufferId(0),
382 render_tasks,
383 gpu_buffer_builder,
384 |key, instance| {
385 if info.prim_needs_scissor_rect {
386 self.prim_instances_with_scissor
387 .entry((target_rect, info.pattern))
388 .or_insert(FastHashMap::default())
389 .entry(key.textures.input.colors[0])
390 .or_insert_with(|| ctx.frame_memory.new_vec())
391 .push(instance);
392 } else {
393 self.prim_instances[info.pattern as usize]
394 .entry(key.textures.input.colors[0])
395 .or_insert_with(|| ctx.frame_memory.new_vec())
396 .push(instance);
397 }
398 }
399 );
400 }
401 RenderTaskKind::VerticalBlur(ref info) => {
402 if self.target_kind == RenderTargetKind::Alpha {
403 self.clears.push((target_rect, ColorF::TRANSPARENT));
404 }
405 add_blur_instances(
406 &mut self.vertical_blurs,
407 BlurDirection::Vertical,
408 info.blur_std_deviation,
409 info.blur_region,
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 task_id.into(),
426 task.children[0],
427 render_tasks,
428 &ctx.frame_memory,
429 );
430 }
431 RenderTaskKind::Picture(ref pic_task) => {
432 if let Some(ref resolve_op) = pic_task.resolve_op {
433 self.resolve_ops.push(resolve_op.clone());
434 }
435 self.alpha_tasks.push(task_id);
436 }
437 RenderTaskKind::SvgFilter(ref task_info) => {
438 add_svg_filter_instances(
439 &mut self.svg_filters,
440 render_tasks,
441 &task_info.info,
442 task_id,
443 task.children.get(0).cloned(),
444 task.children.get(1).cloned(),
445 task_info.extra_gpu_cache_handle.map(|handle| gpu_cache.get_address(&handle)),
446 &ctx.frame_memory,
447 )
448 }
449 RenderTaskKind::SVGFENode(ref task_info) => {
450 add_svg_filter_node_instances(
451 &mut self.svg_nodes,
452 render_tasks,
453 &task_info,
454 task,
455 task.children.get(0).cloned(),
456 task.children.get(1).cloned(),
457 task_info.extra_gpu_cache_handle.map(|handle| gpu_cache.get_address(&handle)),
458 &ctx.frame_memory,
459 )
460 }
461 RenderTaskKind::Empty(..) => {
462 self.clears.push((target_rect, ColorF::WHITE));
466 }
467 RenderTaskKind::CacheMask(ref task_info) => {
468 let clear_to_one = self.clip_batcher.add(
469 task_info.clip_node_range,
470 task_info.root_spatial_node_index,
471 render_tasks,
472 gpu_cache,
473 clip_store,
474 transforms,
475 task_info.actual_rect,
476 task_info.device_pixel_scale,
477 target_rect.min.to_f32(),
478 task_info.actual_rect.min,
479 ctx,
480 );
481 if task_info.clear_to_one || clear_to_one {
482 self.clears.push((target_rect, ColorF::WHITE));
483 }
484 }
485 RenderTaskKind::ClipRegion(ref region_task) => {
486 if region_task.clear_to_one {
487 self.clears.push((target_rect, ColorF::WHITE));
488 }
489 let device_rect = DeviceRect::from_size(
490 target_rect.size().to_f32(),
491 );
492 self.clip_batcher.add_clip_region(
493 region_task.local_pos,
494 device_rect,
495 region_task.clip_data.clone(),
496 target_rect.min.to_f32(),
497 DevicePoint::zero(),
498 region_task.device_pixel_scale.0,
499 );
500 }
501 RenderTaskKind::Scaling(ref info) => {
502 add_scaling_instances(
503 info,
504 &mut self.scalings,
505 task,
506 task.children.first().map(|&child| &render_tasks[child]),
507 &ctx.frame_memory,
508 );
509 }
510 RenderTaskKind::Blit(ref task_info) => {
511 let target_rect = task.get_target_rect();
512 self.blits.push(BlitJob {
513 source: task_info.source,
514 source_rect: task_info.source_rect,
515 target_rect,
516 });
517 }
518 RenderTaskKind::LineDecoration(ref info) => {
519 self.clears.push((target_rect, ColorF::TRANSPARENT));
520
521 self.line_decorations.push(LineDecorationJob {
522 task_rect: target_rect.to_f32(),
523 local_size: info.local_size,
524 style: info.style as i32,
525 axis_select: match info.orientation {
526 LineOrientation::Horizontal => 0.0,
527 LineOrientation::Vertical => 1.0,
528 },
529 wavy_line_thickness: info.wavy_line_thickness,
530 });
531 }
532 RenderTaskKind::Border(ref task_info) => {
533 self.clears.push((target_rect, ColorF::TRANSPARENT));
534
535 let task_origin = target_rect.min.to_f32();
536 let instances = task_info.instances.clone();
541 for mut instance in instances {
542 instance.task_origin = task_origin;
545 if instance.flags & STYLE_MASK == STYLE_SOLID {
546 self.border_segments_solid.push(instance);
547 } else {
548 self.border_segments_complex.push(instance);
549 }
550 }
551 }
552 RenderTaskKind::FastLinearGradient(ref task_info) => {
553 self.fast_linear_gradients.push(task_info.to_instance(&target_rect));
554 }
555 RenderTaskKind::LinearGradient(ref task_info) => {
556 self.linear_gradients.push(task_info.to_instance(&target_rect));
557 }
558 RenderTaskKind::RadialGradient(ref task_info) => {
559 self.radial_gradients.push(task_info.to_instance(&target_rect));
560 }
561 RenderTaskKind::ConicGradient(ref task_info) => {
562 self.conic_gradients.push(task_info.to_instance(&target_rect));
563 }
564 RenderTaskKind::Image(..) |
565 RenderTaskKind::Cached(..) |
566 RenderTaskKind::TileComposite(..) => {
567 panic!("Should not be added to color target!");
568 }
569 RenderTaskKind::Readback(..) => {}
570 #[cfg(test)]
571 RenderTaskKind::Test(..) => {}
572 }
573
574 build_sub_pass(
575 task_id,
576 task,
577 gpu_buffer_builder,
578 render_tasks,
579 transforms,
580 ctx,
581 &mut self.clip_masks,
582 );
583 }
584
585 pub fn needs_depth(&self) -> bool {
586 self.alpha_batch_containers.iter().any(|ab| {
587 !ab.opaque_batches.is_empty()
588 })
589 }
590}
591
592#[cfg_attr(feature = "capture", derive(Serialize))]
593#[cfg_attr(feature = "replay", derive(Deserialize))]
594#[derive(Debug, PartialEq, Clone)]
595pub struct ResolveOp {
596 pub src_task_ids: Vec<RenderTaskId>,
597 pub dest_task_id: RenderTaskId,
598}
599
600#[cfg_attr(feature = "capture", derive(Serialize))]
601#[cfg_attr(feature = "replay", derive(Deserialize))]
602pub enum PictureCacheTargetKind {
603 Draw {
604 alpha_batch_container: AlphaBatchContainer,
605 },
606 Blit {
607 task_id: RenderTaskId,
608 sub_rect_offset: DeviceIntVector2D,
609 },
610}
611
612#[cfg_attr(feature = "capture", derive(Serialize))]
613#[cfg_attr(feature = "replay", derive(Deserialize))]
614pub struct PictureCacheTarget {
615 pub surface: ResolvedSurfaceTexture,
616 pub kind: PictureCacheTargetKind,
617 pub clear_color: Option<ColorF>,
618 pub dirty_rect: DeviceIntRect,
619 pub valid_rect: DeviceIntRect,
620}
621
622fn add_blur_instances(
623 instances: &mut FastHashMap<TextureSource, FrameVec<BlurInstance>>,
624 blur_direction: BlurDirection,
625 blur_std_deviation: f32,
626 blur_region: DeviceIntSize,
627 task_address: RenderTaskAddress,
628 src_task_id: RenderTaskId,
629 render_tasks: &RenderTaskGraph,
630 memory: &FrameMemory,
631) {
632 let source = render_tasks[src_task_id].get_texture_source();
633
634 let instance = BlurInstance {
635 task_address,
636 src_task_address: src_task_id.into(),
637 blur_direction: blur_direction.as_int(),
638 blur_std_deviation,
639 blur_region: blur_region.to_f32(),
640 };
641
642 instances
643 .entry(source)
644 .or_insert_with(|| memory.new_vec())
645 .push(instance);
646}
647
648fn add_scaling_instances(
649 task: &ScalingTask,
650 instances: &mut FastHashMap<TextureSource, FrameVec<ScalingInstance>>,
651 target_task: &RenderTask,
652 source_task: Option<&RenderTask>,
653 memory: &FrameMemory,
654) {
655 let target_rect = target_task
656 .get_target_rect()
657 .inner_box(task.padding)
658 .to_f32();
659
660 let source = source_task.unwrap().get_texture_source();
661
662 let source_rect = source_task.unwrap().get_target_rect().to_f32();
663
664 instances
665 .entry(source)
666 .or_insert_with(|| memory.new_vec())
667 .push(ScalingInstance::new(
668 target_rect,
669 source_rect,
670 source.uses_normalized_uvs(),
671 ));
672}
673
674fn add_svg_filter_instances(
675 instances: &mut FrameVec<(BatchTextures, FrameVec<SvgFilterInstance>)>,
676 render_tasks: &RenderTaskGraph,
677 filter: &SvgFilterInfo,
678 task_id: RenderTaskId,
679 input_1_task: Option<RenderTaskId>,
680 input_2_task: Option<RenderTaskId>,
681 extra_data_address: Option<GpuCacheAddress>,
682 memory: &FrameMemory,
683) {
684 let mut textures = BatchTextures::empty();
685
686 if let Some(id) = input_1_task {
687 textures.input.colors[0] = render_tasks[id].get_texture_source();
688 }
689
690 if let Some(id) = input_2_task {
691 textures.input.colors[1] = render_tasks[id].get_texture_source();
692 }
693
694 let kind = match filter {
695 SvgFilterInfo::Blend(..) => 0,
696 SvgFilterInfo::Flood(..) => 1,
697 SvgFilterInfo::LinearToSrgb => 2,
698 SvgFilterInfo::SrgbToLinear => 3,
699 SvgFilterInfo::Opacity(..) => 4,
700 SvgFilterInfo::ColorMatrix(..) => 5,
701 SvgFilterInfo::DropShadow(..) => 6,
702 SvgFilterInfo::Offset(..) => 7,
703 SvgFilterInfo::ComponentTransfer(..) => 8,
704 SvgFilterInfo::Identity => 9,
705 SvgFilterInfo::Composite(..) => 10,
706 };
707
708 let input_count = match filter {
709 SvgFilterInfo::Flood(..) => 0,
710
711 SvgFilterInfo::LinearToSrgb |
712 SvgFilterInfo::SrgbToLinear |
713 SvgFilterInfo::Opacity(..) |
714 SvgFilterInfo::ColorMatrix(..) |
715 SvgFilterInfo::Offset(..) |
716 SvgFilterInfo::ComponentTransfer(..) |
717 SvgFilterInfo::Identity => 1,
718
719 SvgFilterInfo::DropShadow(..) |
721 SvgFilterInfo::Blend(..) |
722 SvgFilterInfo::Composite(..) => 2,
723 };
724
725 let generic_int = match filter {
726 SvgFilterInfo::Blend(mode) => *mode as u16,
727 SvgFilterInfo::ComponentTransfer(data) =>
728 (data.r_func.to_int() << 12 |
729 data.g_func.to_int() << 8 |
730 data.b_func.to_int() << 4 |
731 data.a_func.to_int()) as u16,
732 SvgFilterInfo::Composite(operator) =>
733 operator.as_int() as u16,
734 SvgFilterInfo::LinearToSrgb |
735 SvgFilterInfo::SrgbToLinear |
736 SvgFilterInfo::Flood(..) |
737 SvgFilterInfo::Opacity(..) |
738 SvgFilterInfo::ColorMatrix(..) |
739 SvgFilterInfo::DropShadow(..) |
740 SvgFilterInfo::Offset(..) |
741 SvgFilterInfo::Identity => 0,
742 };
743
744 let instance = SvgFilterInstance {
745 task_address: task_id.into(),
746 input_1_task_address: input_1_task.map(|id| id.into()).unwrap_or(RenderTaskAddress(0)),
747 input_2_task_address: input_2_task.map(|id| id.into()).unwrap_or(RenderTaskAddress(0)),
748 kind,
749 input_count,
750 generic_int,
751 padding: 0,
752 extra_data_address: extra_data_address.unwrap_or(GpuCacheAddress::INVALID),
753 };
754
755 for (ref mut batch_textures, ref mut batch) in instances.iter_mut() {
756 if let Some(combined_textures) = batch_textures.combine_textures(textures) {
757 batch.push(instance);
758 *batch_textures = combined_textures;
760 return;
761 }
762 }
763
764 let mut vec = memory.new_vec();
765 vec.push(instance);
766
767 instances.push((textures, vec));
768}
769
770fn add_svg_filter_node_instances(
779 instances: &mut FrameVec<(BatchTextures, FrameVec<SVGFEFilterInstance>)>,
780 render_tasks: &RenderTaskGraph,
781 task_info: &SVGFEFilterTask,
782 target_task: &RenderTask,
783 input_1_task: Option<RenderTaskId>,
784 input_2_task: Option<RenderTaskId>,
785 extra_data_address: Option<GpuCacheAddress>,
786 memory: &FrameMemory,
787) {
788 let node = &task_info.node;
789 let op = &task_info.op;
790 let mut textures = BatchTextures::empty();
791
792 let target_rect = target_task
795 .get_target_rect()
796 .inner_box(DeviceIntSideOffsets::new(node.inflate as i32, node.inflate as i32, node.inflate as i32, node.inflate as i32))
797 .to_f32();
798
799 let mut instance = SVGFEFilterInstance {
800 target_rect,
801 input_1_content_scale_and_offset: [0.0; 4],
802 input_2_content_scale_and_offset: [0.0; 4],
803 input_1_task_address: RenderTaskId::INVALID.into(),
804 input_2_task_address: RenderTaskId::INVALID.into(),
805 kind: 0,
806 input_count: node.inputs.len() as u16,
807 extra_data_address: extra_data_address.unwrap_or(GpuCacheAddress::INVALID),
808 };
809
810 instance.kind = match op {
812 FilterGraphOp::SVGFEIdentity => 0,
814 FilterGraphOp::SVGFESourceGraphic => 0,
816 FilterGraphOp::SVGFESourceAlpha => 4,
818 FilterGraphOp::SVGFEOpacity{..} => 2,
822 FilterGraphOp::SVGFEToAlpha => 4,
823 FilterGraphOp::SVGFEBlendColor => {match node.linear {false => 6, true => 7}},
824 FilterGraphOp::SVGFEBlendColorBurn => {match node.linear {false => 8, true => 9}},
825 FilterGraphOp::SVGFEBlendColorDodge => {match node.linear {false => 10, true => 11}},
826 FilterGraphOp::SVGFEBlendDarken => {match node.linear {false => 12, true => 13}},
827 FilterGraphOp::SVGFEBlendDifference => {match node.linear {false => 14, true => 15}},
828 FilterGraphOp::SVGFEBlendExclusion => {match node.linear {false => 16, true => 17}},
829 FilterGraphOp::SVGFEBlendHardLight => {match node.linear {false => 18, true => 19}},
830 FilterGraphOp::SVGFEBlendHue => {match node.linear {false => 20, true => 21}},
831 FilterGraphOp::SVGFEBlendLighten => {match node.linear {false => 22, true => 23}},
832 FilterGraphOp::SVGFEBlendLuminosity => {match node.linear {false => 24, true => 25}},
833 FilterGraphOp::SVGFEBlendMultiply => {match node.linear {false => 26, true => 27}},
834 FilterGraphOp::SVGFEBlendNormal => {match node.linear {false => 28, true => 29}},
835 FilterGraphOp::SVGFEBlendOverlay => {match node.linear {false => 30, true => 31}},
836 FilterGraphOp::SVGFEBlendSaturation => {match node.linear {false => 32, true => 33}},
837 FilterGraphOp::SVGFEBlendScreen => {match node.linear {false => 34, true => 35}},
838 FilterGraphOp::SVGFEBlendSoftLight => {match node.linear {false => 36, true => 37}},
839 FilterGraphOp::SVGFEColorMatrix{..} => {match node.linear {false => 38, true => 39}},
840 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
841 FilterGraphOp::SVGFEComponentTransferInterned{..} => {match node.linear {false => 40, true => 41}},
842 FilterGraphOp::SVGFECompositeArithmetic{..} => {match node.linear {false => 42, true => 43}},
843 FilterGraphOp::SVGFECompositeATop => {match node.linear {false => 44, true => 45}},
844 FilterGraphOp::SVGFECompositeIn => {match node.linear {false => 46, true => 47}},
845 FilterGraphOp::SVGFECompositeLighter => {match node.linear {false => 48, true => 49}},
846 FilterGraphOp::SVGFECompositeOut => {match node.linear {false => 50, true => 51}},
847 FilterGraphOp::SVGFECompositeOver => {match node.linear {false => 52, true => 53}},
848 FilterGraphOp::SVGFECompositeXOR => {match node.linear {false => 54, true => 55}},
849 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{..} => {match node.linear {false => 56, true => 57}},
850 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{..} => {match node.linear {false => 58, true => 59}},
851 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{..} => {match node.linear {false => 60, true => 61}},
852 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {match node.linear {false => 62, true => 63}},
853 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {match node.linear {false => 64, true => 65}},
854 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {match node.linear {false => 66, true => 67}},
855 FilterGraphOp::SVGFEDisplacementMap{..} => {match node.linear {false => 68, true => 69}},
856 FilterGraphOp::SVGFEDropShadow{..} => {match node.linear {false => 70, true => 71}},
857 FilterGraphOp::SVGFEFlood{..} => 72,
859 FilterGraphOp::SVGFEGaussianBlur{..} => {match node.linear {false => 74, true => 75}},
860 FilterGraphOp::SVGFEImage{..} => 76,
864 FilterGraphOp::SVGFEMorphologyDilate{..} => {match node.linear {false => 80, true => 81}},
865 FilterGraphOp::SVGFEMorphologyErode{..} => {match node.linear {false => 82, true => 83}},
866 FilterGraphOp::SVGFESpecularLightingDistant{..} => {match node.linear {false => 86, true => 87}},
867 FilterGraphOp::SVGFESpecularLightingPoint{..} => {match node.linear {false => 88, true => 89}},
868 FilterGraphOp::SVGFESpecularLightingSpot{..} => {match node.linear {false => 90, true => 91}},
869 FilterGraphOp::SVGFETile => 92,
871 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} => {match node.linear {false => 94, true => 95}},
872 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} => {match node.linear {false => 96, true => 97}},
873 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} => {match node.linear {false => 98, true => 99}},
874 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {match node.linear {false => 100, true => 101}},
875 };
876
877 let mut resolve_input = |index: usize, src_task: Option<RenderTaskId>| -> (RenderTaskAddress, [f32; 4]) {
879 let mut src_task_id = RenderTaskId::INVALID;
880 let mut resolved_scale_and_offset: [f32; 4] = [0.0; 4];
881 if let Some(input) = node.inputs.get(index) {
882 src_task_id = src_task.unwrap();
883 let src_task = &render_tasks[src_task_id];
884
885 textures.input.colors[index] = src_task.get_texture_source();
886 let src_task_size = src_task.location.size();
887 let src_scale_x = (src_task_size.width as f32 - input.inflate as f32 * 2.0) / input.subregion.width();
888 let src_scale_y = (src_task_size.height as f32 - input.inflate as f32 * 2.0) / input.subregion.height();
889 let scale_x = src_scale_x * node.subregion.width();
890 let scale_y = src_scale_y * node.subregion.height();
891 let offset_x = src_scale_x * (node.subregion.min.x - input.subregion.min.x) + input.inflate as f32;
892 let offset_y = src_scale_y * (node.subregion.min.y - input.subregion.min.y) + input.inflate as f32;
893 resolved_scale_and_offset = [
894 scale_x,
895 scale_y,
896 offset_x,
897 offset_y];
898 }
899 let address: RenderTaskAddress = src_task_id.into();
900 (address, resolved_scale_and_offset)
901 };
902 (instance.input_1_task_address, instance.input_1_content_scale_and_offset) = resolve_input(0, input_1_task);
903 (instance.input_2_task_address, instance.input_2_content_scale_and_offset) = resolve_input(1, input_2_task);
904
905 match op {
907 FilterGraphOp::SVGFEOpacity { valuebinding: _, value } => {
908 instance.input_2_content_scale_and_offset = [*value, 0.0, 0.0, 0.0];
911 },
912 FilterGraphOp::SVGFEMorphologyDilate { radius_x, radius_y } |
913 FilterGraphOp::SVGFEMorphologyErode { radius_x, radius_y } => {
914 instance.input_2_content_scale_and_offset = [*radius_x, *radius_y, 0.0, 0.0];
917 },
918 FilterGraphOp::SVGFEFlood { color } => {
919 instance.input_2_content_scale_and_offset = [color.r, color.g, color.b, color.a];
923 },
924 _ => {},
925 }
926
927 for (ref mut batch_textures, ref mut batch) in instances.iter_mut() {
928 if let Some(combined_textures) = batch_textures.combine_textures(textures) {
929 batch.push(instance);
930 *batch_textures = combined_textures;
932 return;
934 }
935 }
936
937 let mut vec = memory.new_vec();
938 vec.push(instance);
939
940 instances.push((textures, vec));
941}
942
943#[cfg_attr(feature = "capture", derive(Serialize))]
945#[cfg_attr(feature = "replay", derive(Deserialize))]
946pub struct BlitJob {
947 pub source: RenderTaskId,
948 pub source_rect: DeviceIntRect,
950 pub target_rect: DeviceIntRect,
951}
952
953#[cfg_attr(feature = "capture", derive(Serialize))]
954#[cfg_attr(feature = "replay", derive(Deserialize))]
955#[repr(C)]
956#[derive(Clone, Debug)]
957pub struct LineDecorationJob {
958 pub task_rect: DeviceRect,
959 pub local_size: LayoutSize,
960 pub wavy_line_thickness: f32,
961 pub style: i32,
962 pub axis_select: f32,
963}
964
965fn build_mask_tasks(
966 info: &MaskSubPass,
967 render_task_address: RenderTaskAddress,
968 task_world_rect: WorldRect,
969 target_rect: DeviceIntRect,
970 main_prim_address: GpuBufferAddress,
971 prim_spatial_node_index: SpatialNodeIndex,
972 raster_spatial_node_index: SpatialNodeIndex,
973 clip_store: &ClipStore,
974 data_stores: &DataStores,
975 spatial_tree: &SpatialTree,
976 gpu_buffer_builder: &mut GpuBufferBuilder,
977 transforms: &mut TransformPalette,
978 render_tasks: &RenderTaskGraph,
979 results: &mut ClipMaskInstanceList,
980 memory: &FrameMemory,
981) {
982 for i in 0 .. info.clip_node_range.count {
983 let clip_instance = clip_store.get_instance_from_range(&info.clip_node_range, i);
984 let clip_node = &data_stores.clip[clip_instance.handle];
985
986 let (clip_address, fast_path) = match clip_node.item.kind {
987 ClipItemKind::RoundedRectangle { rect, radius, mode } => {
988 let (fast_path, clip_address) = if radius.can_use_fast_path_in(&rect) {
989 let mut writer = gpu_buffer_builder.f32.write_blocks(3);
990 writer.push_one(rect);
991 writer.push_one([
992 radius.bottom_right.width,
993 radius.top_right.width,
994 radius.bottom_left.width,
995 radius.top_left.width,
996 ]);
997 writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
998 let clip_address = writer.finish();
999
1000 (true, clip_address)
1001 } else {
1002 let mut writer = gpu_buffer_builder.f32.write_blocks(4);
1003 writer.push_one(rect);
1004 writer.push_one([
1005 radius.top_left.width,
1006 radius.top_left.height,
1007 radius.top_right.width,
1008 radius.top_right.height,
1009 ]);
1010 writer.push_one([
1011 radius.bottom_left.width,
1012 radius.bottom_left.height,
1013 radius.bottom_right.width,
1014 radius.bottom_right.height,
1015 ]);
1016 writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
1017 let clip_address = writer.finish();
1018
1019 (false, clip_address)
1020 };
1021
1022 (clip_address, fast_path)
1023 }
1024 ClipItemKind::Rectangle { rect, mode, .. } => {
1025 let mut writer = gpu_buffer_builder.f32.write_blocks(3);
1026 writer.push_one(rect);
1027 writer.push_one([0.0, 0.0, 0.0, 0.0]);
1028 writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
1029 let clip_address = writer.finish();
1030
1031 (clip_address, true)
1032 }
1033 ClipItemKind::BoxShadow { .. } => {
1034 panic!("bug: box-shadow clips not expected on non-legacy rect/quads");
1035 }
1036 ClipItemKind::Image { rect, .. } => {
1037 let clip_transform_id = transforms.get_id(
1038 clip_node.item.spatial_node_index,
1039 raster_spatial_node_index,
1040 spatial_tree,
1041 );
1042
1043 let is_same_coord_system = spatial_tree.is_matching_coord_system(
1044 prim_spatial_node_index,
1045 raster_spatial_node_index,
1046 );
1047
1048 let pattern = Pattern::color(ColorF::WHITE);
1049 let clip_needs_scissor_rect = !is_same_coord_system;
1050 let mut quad_flags = QuadFlags::IS_MASK;
1051
1052 if is_same_coord_system {
1053 quad_flags |= QuadFlags::APPLY_RENDER_TASK_CLIP;
1054 }
1055
1056 for tile in clip_store.visible_mask_tiles(&clip_instance) {
1057 let clip_prim_address = quad::write_prim_blocks(
1058 &mut gpu_buffer_builder.f32,
1059 rect,
1060 rect,
1061 pattern.base_color,
1062 pattern.texture_input.task_id,
1063 &[QuadSegment {
1064 rect: tile.tile_rect,
1065 task_id: tile.task_id,
1066 }],
1067 ScaleOffset::identity(),
1068 );
1069
1070 let texture = render_tasks
1071 .resolve_texture(tile.task_id)
1072 .expect("bug: texture not found for tile");
1073
1074 quad::add_to_batch(
1075 PatternKind::ColorOrTexture,
1076 PatternShaderInput::default(),
1077 render_task_address,
1078 clip_transform_id,
1079 clip_prim_address,
1080 quad_flags,
1081 EdgeAaSegmentMask::empty(),
1082 0,
1083 tile.task_id,
1084 ZBufferId(0),
1085 render_tasks,
1086 gpu_buffer_builder,
1087 |_, prim| {
1088 if clip_needs_scissor_rect {
1089 results
1090 .image_mask_instances_with_scissor
1091 .entry((target_rect, texture))
1092 .or_insert_with(|| memory.new_vec())
1093 .push(prim);
1094 } else {
1095 results
1096 .image_mask_instances
1097 .entry(texture)
1098 .or_insert_with(|| memory.new_vec())
1099 .push(prim);
1100 }
1101 }
1102 );
1103 }
1104
1105 continue;
1109 }
1110 };
1111
1112 let prim_spatial_node = spatial_tree.get_spatial_node(prim_spatial_node_index);
1113 let clip_spatial_node = spatial_tree.get_spatial_node(clip_node.item.spatial_node_index);
1114 let raster_spatial_node = spatial_tree.get_spatial_node(raster_spatial_node_index);
1115 let raster_clip = raster_spatial_node.coordinate_system_id == clip_spatial_node.coordinate_system_id;
1116
1117 let (clip_space, clip_transform_id, main_prim_address, prim_transform_id, is_same_coord_system) = if raster_clip {
1118 let prim_transform_id = TransformPaletteId::IDENTITY;
1119 let pattern = Pattern::color(ColorF::WHITE);
1120
1121 let clip_transform_id = transforms.get_id(
1122 raster_spatial_node_index,
1123 clip_node.item.spatial_node_index,
1124 spatial_tree,
1125 );
1126
1127 let main_prim_address = quad::write_prim_blocks(
1128 &mut gpu_buffer_builder.f32,
1129 task_world_rect.cast_unit(),
1130 task_world_rect.cast_unit(),
1131 pattern.base_color,
1132 pattern.texture_input.task_id,
1133 &[],
1134 ScaleOffset::identity(),
1135 );
1136
1137 (ClipSpace::Raster, clip_transform_id, main_prim_address, prim_transform_id, true)
1138 } else {
1139 let prim_transform_id = transforms.get_id(
1140 prim_spatial_node_index,
1141 raster_spatial_node_index,
1142 spatial_tree,
1143 );
1144
1145 let clip_transform_id = if prim_spatial_node.coordinate_system_id < clip_spatial_node.coordinate_system_id {
1146 transforms.get_id(
1147 clip_node.item.spatial_node_index,
1148 prim_spatial_node_index,
1149 spatial_tree,
1150 )
1151 } else {
1152 transforms.get_id(
1153 prim_spatial_node_index,
1154 clip_node.item.spatial_node_index,
1155 spatial_tree,
1156 )
1157 };
1158
1159 let is_same_coord_system = spatial_tree.is_matching_coord_system(
1160 prim_spatial_node_index,
1161 raster_spatial_node_index,
1162 );
1163
1164 (ClipSpace::Primitive, clip_transform_id, main_prim_address, prim_transform_id, is_same_coord_system)
1165 };
1166
1167 let clip_needs_scissor_rect = !is_same_coord_system;
1168
1169 let quad_flags = if is_same_coord_system {
1170 QuadFlags::APPLY_RENDER_TASK_CLIP
1171 } else {
1172 QuadFlags::empty()
1173 };
1174
1175 quad::add_to_batch(
1176 PatternKind::Mask,
1177 PatternShaderInput::default(),
1178 render_task_address,
1179 prim_transform_id,
1180 main_prim_address,
1181 quad_flags,
1182 EdgeAaSegmentMask::all(),
1183 INVALID_SEGMENT_INDEX as u8,
1184 RenderTaskId::INVALID,
1185 ZBufferId(0),
1186 render_tasks,
1187 gpu_buffer_builder,
1188 |_, prim| {
1189 let instance = MaskInstance {
1190 prim,
1191 clip_transform_id,
1192 clip_address: clip_address.as_int(),
1193 clip_space: clip_space.as_int(),
1194 unused: 0,
1195 };
1196
1197 if clip_needs_scissor_rect {
1198 if fast_path {
1199 results.mask_instances_fast_with_scissor
1200 .entry(target_rect)
1201 .or_insert_with(|| memory.new_vec())
1202 .push(instance);
1203 } else {
1204 results.mask_instances_slow_with_scissor
1205 .entry(target_rect)
1206 .or_insert_with(|| memory.new_vec())
1207 .push(instance);
1208 }
1209 } else {
1210 if fast_path {
1211 results.mask_instances_fast.push(instance);
1212 } else {
1213 results.mask_instances_slow.push(instance);
1214 }
1215 }
1216 }
1217 );
1218 }
1219}
1220
1221fn build_sub_pass(
1222 task_id: RenderTaskId,
1223 task: &RenderTask,
1224 gpu_buffer_builder: &mut GpuBufferBuilder,
1225 render_tasks: &RenderTaskGraph,
1226 transforms: &mut TransformPalette,
1227 ctx: &RenderTargetContext,
1228 output: &mut ClipMaskInstanceList,
1229) {
1230 if let Some(ref sub_pass) = task.sub_pass {
1231 match sub_pass {
1232 SubPass::Masks { ref masks } => {
1233 let render_task_address = task_id.into();
1234 let target_rect = task.get_target_rect();
1235
1236 let (device_pixel_scale, content_origin, raster_spatial_node_index) = match task.kind {
1237 RenderTaskKind::Picture(ref info) => {
1238 (info.device_pixel_scale, info.content_origin, info.raster_spatial_node_index)
1239 }
1240 RenderTaskKind::Empty(ref info) => {
1241 (info.device_pixel_scale, info.content_origin, info.raster_spatial_node_index)
1242 }
1243 RenderTaskKind::Prim(ref info) => {
1244 (info.device_pixel_scale, info.content_origin, info.raster_spatial_node_index)
1245 }
1246 _ => panic!("unexpected: {}", task.kind.as_str()),
1247 };
1248
1249 let content_rect = DeviceRect::new(
1250 content_origin,
1251 content_origin + target_rect.size().to_f32(),
1252 );
1253
1254 build_mask_tasks(
1255 masks,
1256 render_task_address,
1257 content_rect / device_pixel_scale,
1258 target_rect,
1259 masks.prim_address_f,
1260 masks.prim_spatial_node_index,
1261 raster_spatial_node_index,
1262 ctx.clip_store,
1263 ctx.data_stores,
1264 ctx.spatial_tree,
1265 gpu_buffer_builder,
1266 transforms,
1267 render_tasks,
1268 output,
1269 &ctx.frame_memory,
1270 );
1271 }
1272 }
1273 }
1274}