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, BlurEdgeMode};
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(), 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 info.edge_mode,
411 task_id.into(),
412 task.children[0],
413 render_tasks,
414 &ctx.frame_memory,
415 );
416 }
417 RenderTaskKind::HorizontalBlur(ref info) => {
418 if self.target_kind == RenderTargetKind::Alpha {
419 self.clears.push((target_rect, ColorF::TRANSPARENT));
420 }
421 add_blur_instances(
422 &mut self.horizontal_blurs,
423 BlurDirection::Horizontal,
424 info.blur_std_deviation,
425 info.blur_region,
426 info.edge_mode,
427 task_id.into(),
428 task.children[0],
429 render_tasks,
430 &ctx.frame_memory,
431 );
432 }
433 RenderTaskKind::Picture(ref pic_task) => {
434 if let Some(ref resolve_op) = pic_task.resolve_op {
435 self.resolve_ops.push(resolve_op.clone());
436 }
437 self.alpha_tasks.push(task_id);
438 }
439 RenderTaskKind::SvgFilter(ref task_info) => {
440 add_svg_filter_instances(
441 &mut self.svg_filters,
442 render_tasks,
443 &task_info.info,
444 task_id,
445 task.children.get(0).cloned(),
446 task.children.get(1).cloned(),
447 task_info.extra_gpu_cache_handle.map(|handle| gpu_cache.get_address(&handle)),
448 &ctx.frame_memory,
449 )
450 }
451 RenderTaskKind::SVGFENode(ref task_info) => {
452 add_svg_filter_node_instances(
453 &mut self.svg_nodes,
454 render_tasks,
455 &task_info,
456 task,
457 task.children.get(0).cloned(),
458 task.children.get(1).cloned(),
459 task_info.extra_gpu_cache_handle.map(|handle| gpu_cache.get_address(&handle)),
460 &ctx.frame_memory,
461 )
462 }
463 RenderTaskKind::Empty(..) => {
464 self.clears.push((target_rect, ColorF::WHITE));
468 }
469 RenderTaskKind::CacheMask(ref task_info) => {
470 let clear_to_one = self.clip_batcher.add(
471 task_info.clip_node_range,
472 task_info.root_spatial_node_index,
473 render_tasks,
474 gpu_cache,
475 clip_store,
476 transforms,
477 task_info.actual_rect,
478 task_info.device_pixel_scale,
479 target_rect.min.to_f32(),
480 task_info.actual_rect.min,
481 ctx,
482 );
483 if task_info.clear_to_one || clear_to_one {
484 self.clears.push((target_rect, ColorF::WHITE));
485 }
486 }
487 RenderTaskKind::ClipRegion(ref region_task) => {
488 if region_task.clear_to_one {
489 self.clears.push((target_rect, ColorF::WHITE));
490 }
491 let device_rect = DeviceRect::from_size(
492 target_rect.size().to_f32(),
493 );
494 self.clip_batcher.add_clip_region(
495 region_task.local_pos,
496 device_rect,
497 region_task.clip_data.clone(),
498 target_rect.min.to_f32(),
499 DevicePoint::zero(),
500 region_task.device_pixel_scale.0,
501 );
502 }
503 RenderTaskKind::Scaling(ref info) => {
504 add_scaling_instances(
505 info,
506 &mut self.scalings,
507 task,
508 task.children.first().map(|&child| &render_tasks[child]),
509 &ctx.frame_memory,
510 );
511 }
512 RenderTaskKind::Blit(ref task_info) => {
513 let target_rect = task.get_target_rect();
514 self.blits.push(BlitJob {
515 source: task_info.source,
516 source_rect: task_info.source_rect,
517 target_rect,
518 });
519 }
520 RenderTaskKind::LineDecoration(ref info) => {
521 self.clears.push((target_rect, ColorF::TRANSPARENT));
522
523 self.line_decorations.push(LineDecorationJob {
524 task_rect: target_rect.to_f32(),
525 local_size: info.local_size,
526 style: info.style as i32,
527 axis_select: match info.orientation {
528 LineOrientation::Horizontal => 0.0,
529 LineOrientation::Vertical => 1.0,
530 },
531 wavy_line_thickness: info.wavy_line_thickness,
532 });
533 }
534 RenderTaskKind::Border(ref task_info) => {
535 self.clears.push((target_rect, ColorF::TRANSPARENT));
536
537 let task_origin = target_rect.min.to_f32();
538 let instances = task_info.instances.clone();
543 for mut instance in instances {
544 instance.task_origin = task_origin;
547 if instance.flags & STYLE_MASK == STYLE_SOLID {
548 self.border_segments_solid.push(instance);
549 } else {
550 self.border_segments_complex.push(instance);
551 }
552 }
553 }
554 RenderTaskKind::FastLinearGradient(ref task_info) => {
555 self.fast_linear_gradients.push(task_info.to_instance(&target_rect));
556 }
557 RenderTaskKind::LinearGradient(ref task_info) => {
558 self.linear_gradients.push(task_info.to_instance(&target_rect));
559 }
560 RenderTaskKind::RadialGradient(ref task_info) => {
561 self.radial_gradients.push(task_info.to_instance(&target_rect));
562 }
563 RenderTaskKind::ConicGradient(ref task_info) => {
564 self.conic_gradients.push(task_info.to_instance(&target_rect));
565 }
566 RenderTaskKind::Image(..) |
567 RenderTaskKind::Cached(..) |
568 RenderTaskKind::TileComposite(..) => {
569 panic!("Should not be added to color target!");
570 }
571 RenderTaskKind::Readback(..) => {}
572 #[cfg(test)]
573 RenderTaskKind::Test(..) => {}
574 }
575
576 build_sub_pass(
577 task_id,
578 task,
579 gpu_buffer_builder,
580 render_tasks,
581 transforms,
582 ctx,
583 &mut self.clip_masks,
584 );
585 }
586
587 pub fn needs_depth(&self) -> bool {
588 self.alpha_batch_containers.iter().any(|ab| {
589 !ab.opaque_batches.is_empty()
590 })
591 }
592}
593
594#[cfg_attr(feature = "capture", derive(Serialize))]
595#[cfg_attr(feature = "replay", derive(Deserialize))]
596#[derive(Debug, PartialEq, Clone)]
597pub struct ResolveOp {
598 pub src_task_ids: Vec<RenderTaskId>,
599 pub dest_task_id: RenderTaskId,
600}
601
602#[cfg_attr(feature = "capture", derive(Serialize))]
603#[cfg_attr(feature = "replay", derive(Deserialize))]
604pub enum PictureCacheTargetKind {
605 Draw {
606 alpha_batch_container: AlphaBatchContainer,
607 },
608 Blit {
609 task_id: RenderTaskId,
610 sub_rect_offset: DeviceIntVector2D,
611 },
612}
613
614#[cfg_attr(feature = "capture", derive(Serialize))]
615#[cfg_attr(feature = "replay", derive(Deserialize))]
616pub struct PictureCacheTarget {
617 pub surface: ResolvedSurfaceTexture,
618 pub kind: PictureCacheTargetKind,
619 pub clear_color: Option<ColorF>,
620 pub dirty_rect: DeviceIntRect,
621 pub valid_rect: DeviceIntRect,
622}
623
624fn add_blur_instances(
625 instances: &mut FastHashMap<TextureSource, FrameVec<BlurInstance>>,
626 blur_direction: BlurDirection,
627 blur_std_deviation: f32,
628 blur_region: DeviceIntSize,
629 edge_mode: BlurEdgeMode,
630 task_address: RenderTaskAddress,
631 src_task_id: RenderTaskId,
632 render_tasks: &RenderTaskGraph,
633 memory: &FrameMemory,
634) {
635 let source = render_tasks[src_task_id].get_texture_source();
636
637 let instance = BlurInstance {
638 task_address,
639 src_task_address: src_task_id.into(),
640 blur_direction: blur_direction.as_int(),
641 blur_std_deviation,
642 edge_mode: edge_mode.as_int(),
643 blur_region: blur_region.to_f32(),
644 };
645
646 instances
647 .entry(source)
648 .or_insert_with(|| memory.new_vec())
649 .push(instance);
650}
651
652fn add_scaling_instances(
653 task: &ScalingTask,
654 instances: &mut FastHashMap<TextureSource, FrameVec<ScalingInstance>>,
655 target_task: &RenderTask,
656 source_task: Option<&RenderTask>,
657 memory: &FrameMemory,
658) {
659 let target_rect = target_task
660 .get_target_rect()
661 .inner_box(task.padding)
662 .to_f32();
663
664 let source = source_task.unwrap().get_texture_source();
665
666 let source_rect = source_task.unwrap().get_target_rect().to_f32();
667
668 instances
669 .entry(source)
670 .or_insert_with(|| memory.new_vec())
671 .push(ScalingInstance::new(
672 target_rect,
673 source_rect,
674 source.uses_normalized_uvs(),
675 ));
676}
677
678fn add_svg_filter_instances(
679 instances: &mut FrameVec<(BatchTextures, FrameVec<SvgFilterInstance>)>,
680 render_tasks: &RenderTaskGraph,
681 filter: &SvgFilterInfo,
682 task_id: RenderTaskId,
683 input_1_task: Option<RenderTaskId>,
684 input_2_task: Option<RenderTaskId>,
685 extra_data_address: Option<GpuCacheAddress>,
686 memory: &FrameMemory,
687) {
688 let mut textures = BatchTextures::empty();
689
690 if let Some(id) = input_1_task {
691 textures.input.colors[0] = render_tasks[id].get_texture_source();
692 }
693
694 if let Some(id) = input_2_task {
695 textures.input.colors[1] = render_tasks[id].get_texture_source();
696 }
697
698 let kind = match filter {
699 SvgFilterInfo::Blend(..) => 0,
700 SvgFilterInfo::Flood(..) => 1,
701 SvgFilterInfo::LinearToSrgb => 2,
702 SvgFilterInfo::SrgbToLinear => 3,
703 SvgFilterInfo::Opacity(..) => 4,
704 SvgFilterInfo::ColorMatrix(..) => 5,
705 SvgFilterInfo::DropShadow(..) => 6,
706 SvgFilterInfo::Offset(..) => 7,
707 SvgFilterInfo::ComponentTransfer(..) => 8,
708 SvgFilterInfo::Identity => 9,
709 SvgFilterInfo::Composite(..) => 10,
710 };
711
712 let input_count = match filter {
713 SvgFilterInfo::Flood(..) => 0,
714
715 SvgFilterInfo::LinearToSrgb |
716 SvgFilterInfo::SrgbToLinear |
717 SvgFilterInfo::Opacity(..) |
718 SvgFilterInfo::ColorMatrix(..) |
719 SvgFilterInfo::Offset(..) |
720 SvgFilterInfo::ComponentTransfer(..) |
721 SvgFilterInfo::Identity => 1,
722
723 SvgFilterInfo::DropShadow(..) |
725 SvgFilterInfo::Blend(..) |
726 SvgFilterInfo::Composite(..) => 2,
727 };
728
729 let generic_int = match filter {
730 SvgFilterInfo::Blend(mode) => *mode as u16,
731 SvgFilterInfo::ComponentTransfer(data) =>
732 (data.r_func.to_int() << 12 |
733 data.g_func.to_int() << 8 |
734 data.b_func.to_int() << 4 |
735 data.a_func.to_int()) as u16,
736 SvgFilterInfo::Composite(operator) =>
737 operator.as_int() as u16,
738 SvgFilterInfo::LinearToSrgb |
739 SvgFilterInfo::SrgbToLinear |
740 SvgFilterInfo::Flood(..) |
741 SvgFilterInfo::Opacity(..) |
742 SvgFilterInfo::ColorMatrix(..) |
743 SvgFilterInfo::DropShadow(..) |
744 SvgFilterInfo::Offset(..) |
745 SvgFilterInfo::Identity => 0,
746 };
747
748 let instance = SvgFilterInstance {
749 task_address: task_id.into(),
750 input_1_task_address: input_1_task.map(|id| id.into()).unwrap_or(RenderTaskAddress(0)),
751 input_2_task_address: input_2_task.map(|id| id.into()).unwrap_or(RenderTaskAddress(0)),
752 kind,
753 input_count,
754 generic_int,
755 padding: 0,
756 extra_data_address: extra_data_address.unwrap_or(GpuCacheAddress::INVALID),
757 };
758
759 for (ref mut batch_textures, ref mut batch) in instances.iter_mut() {
760 if let Some(combined_textures) = batch_textures.combine_textures(textures) {
761 batch.push(instance);
762 *batch_textures = combined_textures;
764 return;
765 }
766 }
767
768 let mut vec = memory.new_vec();
769 vec.push(instance);
770
771 instances.push((textures, vec));
772}
773
774fn add_svg_filter_node_instances(
783 instances: &mut FrameVec<(BatchTextures, FrameVec<SVGFEFilterInstance>)>,
784 render_tasks: &RenderTaskGraph,
785 task_info: &SVGFEFilterTask,
786 target_task: &RenderTask,
787 input_1_task: Option<RenderTaskId>,
788 input_2_task: Option<RenderTaskId>,
789 extra_data_address: Option<GpuCacheAddress>,
790 memory: &FrameMemory,
791) {
792 let node = &task_info.node;
793 let op = &task_info.op;
794 let mut textures = BatchTextures::empty();
795
796 let target_rect = target_task
799 .get_target_rect()
800 .inner_box(DeviceIntSideOffsets::new(node.inflate as i32, node.inflate as i32, node.inflate as i32, node.inflate as i32))
801 .to_f32();
802
803 let mut instance = SVGFEFilterInstance {
804 target_rect,
805 input_1_content_scale_and_offset: [0.0; 4],
806 input_2_content_scale_and_offset: [0.0; 4],
807 input_1_task_address: RenderTaskId::INVALID.into(),
808 input_2_task_address: RenderTaskId::INVALID.into(),
809 kind: 0,
810 input_count: node.inputs.len() as u16,
811 extra_data_address: extra_data_address.unwrap_or(GpuCacheAddress::INVALID),
812 };
813
814 instance.kind = match op {
816 FilterGraphOp::SVGFEIdentity => 0,
818 FilterGraphOp::SVGFESourceGraphic => 0,
820 FilterGraphOp::SVGFESourceAlpha => 4,
822 FilterGraphOp::SVGFEOpacity{..} => 2,
826 FilterGraphOp::SVGFEToAlpha => 4,
827 FilterGraphOp::SVGFEBlendColor => {match node.linear {false => 6, true => 7}},
828 FilterGraphOp::SVGFEBlendColorBurn => {match node.linear {false => 8, true => 9}},
829 FilterGraphOp::SVGFEBlendColorDodge => {match node.linear {false => 10, true => 11}},
830 FilterGraphOp::SVGFEBlendDarken => {match node.linear {false => 12, true => 13}},
831 FilterGraphOp::SVGFEBlendDifference => {match node.linear {false => 14, true => 15}},
832 FilterGraphOp::SVGFEBlendExclusion => {match node.linear {false => 16, true => 17}},
833 FilterGraphOp::SVGFEBlendHardLight => {match node.linear {false => 18, true => 19}},
834 FilterGraphOp::SVGFEBlendHue => {match node.linear {false => 20, true => 21}},
835 FilterGraphOp::SVGFEBlendLighten => {match node.linear {false => 22, true => 23}},
836 FilterGraphOp::SVGFEBlendLuminosity => {match node.linear {false => 24, true => 25}},
837 FilterGraphOp::SVGFEBlendMultiply => {match node.linear {false => 26, true => 27}},
838 FilterGraphOp::SVGFEBlendNormal => {match node.linear {false => 28, true => 29}},
839 FilterGraphOp::SVGFEBlendOverlay => {match node.linear {false => 30, true => 31}},
840 FilterGraphOp::SVGFEBlendSaturation => {match node.linear {false => 32, true => 33}},
841 FilterGraphOp::SVGFEBlendScreen => {match node.linear {false => 34, true => 35}},
842 FilterGraphOp::SVGFEBlendSoftLight => {match node.linear {false => 36, true => 37}},
843 FilterGraphOp::SVGFEColorMatrix{..} => {match node.linear {false => 38, true => 39}},
844 FilterGraphOp::SVGFEComponentTransfer => unreachable!(),
845 FilterGraphOp::SVGFEComponentTransferInterned{..} => {match node.linear {false => 40, true => 41}},
846 FilterGraphOp::SVGFECompositeArithmetic{..} => {match node.linear {false => 42, true => 43}},
847 FilterGraphOp::SVGFECompositeATop => {match node.linear {false => 44, true => 45}},
848 FilterGraphOp::SVGFECompositeIn => {match node.linear {false => 46, true => 47}},
849 FilterGraphOp::SVGFECompositeLighter => {match node.linear {false => 48, true => 49}},
850 FilterGraphOp::SVGFECompositeOut => {match node.linear {false => 50, true => 51}},
851 FilterGraphOp::SVGFECompositeOver => {match node.linear {false => 52, true => 53}},
852 FilterGraphOp::SVGFECompositeXOR => {match node.linear {false => 54, true => 55}},
853 FilterGraphOp::SVGFEConvolveMatrixEdgeModeDuplicate{..} => {match node.linear {false => 56, true => 57}},
854 FilterGraphOp::SVGFEConvolveMatrixEdgeModeNone{..} => {match node.linear {false => 58, true => 59}},
855 FilterGraphOp::SVGFEConvolveMatrixEdgeModeWrap{..} => {match node.linear {false => 60, true => 61}},
856 FilterGraphOp::SVGFEDiffuseLightingDistant{..} => {match node.linear {false => 62, true => 63}},
857 FilterGraphOp::SVGFEDiffuseLightingPoint{..} => {match node.linear {false => 64, true => 65}},
858 FilterGraphOp::SVGFEDiffuseLightingSpot{..} => {match node.linear {false => 66, true => 67}},
859 FilterGraphOp::SVGFEDisplacementMap{..} => {match node.linear {false => 68, true => 69}},
860 FilterGraphOp::SVGFEDropShadow{..} => {match node.linear {false => 70, true => 71}},
861 FilterGraphOp::SVGFEFlood{..} => 72,
863 FilterGraphOp::SVGFEGaussianBlur{..} => {match node.linear {false => 74, true => 75}},
864 FilterGraphOp::SVGFEImage{..} => 76,
868 FilterGraphOp::SVGFEMorphologyDilate{..} => {match node.linear {false => 80, true => 81}},
869 FilterGraphOp::SVGFEMorphologyErode{..} => {match node.linear {false => 82, true => 83}},
870 FilterGraphOp::SVGFESpecularLightingDistant{..} => {match node.linear {false => 86, true => 87}},
871 FilterGraphOp::SVGFESpecularLightingPoint{..} => {match node.linear {false => 88, true => 89}},
872 FilterGraphOp::SVGFESpecularLightingSpot{..} => {match node.linear {false => 90, true => 91}},
873 FilterGraphOp::SVGFETile => 92,
875 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithNoStitching{..} => {match node.linear {false => 94, true => 95}},
876 FilterGraphOp::SVGFETurbulenceWithFractalNoiseWithStitching{..} => {match node.linear {false => 96, true => 97}},
877 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{..} => {match node.linear {false => 98, true => 99}},
878 FilterGraphOp::SVGFETurbulenceWithTurbulenceNoiseWithStitching{..} => {match node.linear {false => 100, true => 101}},
879 };
880
881 let mut resolve_input = |index: usize, src_task: Option<RenderTaskId>| -> (RenderTaskAddress, [f32; 4]) {
883 let mut src_task_id = RenderTaskId::INVALID;
884 let mut resolved_scale_and_offset: [f32; 4] = [0.0; 4];
885 if let Some(input) = node.inputs.get(index) {
886 src_task_id = src_task.unwrap();
887 let src_task = &render_tasks[src_task_id];
888
889 textures.input.colors[index] = src_task.get_texture_source();
890 let src_task_size = src_task.location.size();
891 let src_scale_x = (src_task_size.width as f32 - input.inflate as f32 * 2.0) / input.subregion.width();
892 let src_scale_y = (src_task_size.height as f32 - input.inflate as f32 * 2.0) / input.subregion.height();
893 let scale_x = src_scale_x * node.subregion.width();
894 let scale_y = src_scale_y * node.subregion.height();
895 let offset_x = src_scale_x * (node.subregion.min.x - input.subregion.min.x) + input.inflate as f32;
896 let offset_y = src_scale_y * (node.subregion.min.y - input.subregion.min.y) + input.inflate as f32;
897 resolved_scale_and_offset = [
898 scale_x,
899 scale_y,
900 offset_x,
901 offset_y];
902 }
903 let address: RenderTaskAddress = src_task_id.into();
904 (address, resolved_scale_and_offset)
905 };
906 (instance.input_1_task_address, instance.input_1_content_scale_and_offset) = resolve_input(0, input_1_task);
907 (instance.input_2_task_address, instance.input_2_content_scale_and_offset) = resolve_input(1, input_2_task);
908
909 match op {
911 FilterGraphOp::SVGFEOpacity { valuebinding: _, value } => {
912 instance.input_2_content_scale_and_offset = [*value, 0.0, 0.0, 0.0];
915 },
916 FilterGraphOp::SVGFEMorphologyDilate { radius_x, radius_y } |
917 FilterGraphOp::SVGFEMorphologyErode { radius_x, radius_y } => {
918 instance.input_2_content_scale_and_offset = [*radius_x, *radius_y, 0.0, 0.0];
921 },
922 FilterGraphOp::SVGFEFlood { color } => {
923 instance.input_2_content_scale_and_offset = [color.r, color.g, color.b, color.a];
927 },
928 _ => {},
929 }
930
931 for (ref mut batch_textures, ref mut batch) in instances.iter_mut() {
932 if let Some(combined_textures) = batch_textures.combine_textures(textures) {
933 batch.push(instance);
934 *batch_textures = combined_textures;
936 return;
938 }
939 }
940
941 let mut vec = memory.new_vec();
942 vec.push(instance);
943
944 instances.push((textures, vec));
945}
946
947#[cfg_attr(feature = "capture", derive(Serialize))]
949#[cfg_attr(feature = "replay", derive(Deserialize))]
950pub struct BlitJob {
951 pub source: RenderTaskId,
952 pub source_rect: DeviceIntRect,
954 pub target_rect: DeviceIntRect,
955}
956
957#[cfg_attr(feature = "capture", derive(Serialize))]
958#[cfg_attr(feature = "replay", derive(Deserialize))]
959#[repr(C)]
960#[derive(Clone, Debug)]
961pub struct LineDecorationJob {
962 pub task_rect: DeviceRect,
963 pub local_size: LayoutSize,
964 pub wavy_line_thickness: f32,
965 pub style: i32,
966 pub axis_select: f32,
967}
968
969fn build_mask_tasks(
970 info: &MaskSubPass,
971 render_task_address: RenderTaskAddress,
972 task_world_rect: WorldRect,
973 target_rect: DeviceIntRect,
974 main_prim_address: GpuBufferAddress,
975 prim_spatial_node_index: SpatialNodeIndex,
976 raster_spatial_node_index: SpatialNodeIndex,
977 clip_store: &ClipStore,
978 data_stores: &DataStores,
979 spatial_tree: &SpatialTree,
980 gpu_buffer_builder: &mut GpuBufferBuilder,
981 transforms: &mut TransformPalette,
982 render_tasks: &RenderTaskGraph,
983 results: &mut ClipMaskInstanceList,
984 memory: &FrameMemory,
985) {
986 for i in 0 .. info.clip_node_range.count {
987 let clip_instance = clip_store.get_instance_from_range(&info.clip_node_range, i);
988 let clip_node = &data_stores.clip[clip_instance.handle];
989
990 let (clip_address, fast_path) = match clip_node.item.kind {
991 ClipItemKind::RoundedRectangle { rect, radius, mode } => {
992 let (fast_path, clip_address) = if radius.can_use_fast_path_in(&rect) {
993 let mut writer = gpu_buffer_builder.f32.write_blocks(3);
994 writer.push_one(rect);
995 writer.push_one([
996 radius.bottom_right.width,
997 radius.top_right.width,
998 radius.bottom_left.width,
999 radius.top_left.width,
1000 ]);
1001 writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
1002 let clip_address = writer.finish();
1003
1004 (true, clip_address)
1005 } else {
1006 let mut writer = gpu_buffer_builder.f32.write_blocks(4);
1007 writer.push_one(rect);
1008 writer.push_one([
1009 radius.top_left.width,
1010 radius.top_left.height,
1011 radius.top_right.width,
1012 radius.top_right.height,
1013 ]);
1014 writer.push_one([
1015 radius.bottom_left.width,
1016 radius.bottom_left.height,
1017 radius.bottom_right.width,
1018 radius.bottom_right.height,
1019 ]);
1020 writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
1021 let clip_address = writer.finish();
1022
1023 (false, clip_address)
1024 };
1025
1026 (clip_address, fast_path)
1027 }
1028 ClipItemKind::Rectangle { rect, mode, .. } => {
1029 let mut writer = gpu_buffer_builder.f32.write_blocks(3);
1030 writer.push_one(rect);
1031 writer.push_one([0.0, 0.0, 0.0, 0.0]);
1032 writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
1033 let clip_address = writer.finish();
1034
1035 (clip_address, true)
1036 }
1037 ClipItemKind::BoxShadow { .. } => {
1038 panic!("bug: box-shadow clips not expected on non-legacy rect/quads");
1039 }
1040 ClipItemKind::Image { rect, .. } => {
1041 let clip_transform_id = transforms.get_id(
1042 clip_node.item.spatial_node_index,
1043 raster_spatial_node_index,
1044 spatial_tree,
1045 );
1046
1047 let is_same_coord_system = spatial_tree.is_matching_coord_system(
1048 prim_spatial_node_index,
1049 raster_spatial_node_index,
1050 );
1051
1052 let pattern = Pattern::color(ColorF::WHITE);
1053 let clip_needs_scissor_rect = !is_same_coord_system;
1054 let mut quad_flags = QuadFlags::IS_MASK;
1055
1056 if is_same_coord_system {
1057 quad_flags |= QuadFlags::APPLY_RENDER_TASK_CLIP;
1058 }
1059
1060 for tile in clip_store.visible_mask_tiles(&clip_instance) {
1061 let clip_prim_address = quad::write_prim_blocks(
1062 &mut gpu_buffer_builder.f32,
1063 rect,
1064 rect,
1065 pattern.base_color,
1066 pattern.texture_input.task_id,
1067 &[QuadSegment {
1068 rect: tile.tile_rect,
1069 task_id: tile.task_id,
1070 }],
1071 ScaleOffset::identity(),
1072 );
1073
1074 let texture = render_tasks
1075 .resolve_texture(tile.task_id)
1076 .expect("bug: texture not found for tile");
1077
1078 quad::add_to_batch(
1079 PatternKind::ColorOrTexture,
1080 PatternShaderInput::default(),
1081 render_task_address,
1082 clip_transform_id,
1083 clip_prim_address,
1084 quad_flags,
1085 EdgeAaSegmentMask::empty(),
1086 0,
1087 tile.task_id,
1088 ZBufferId(0),
1089 render_tasks,
1090 gpu_buffer_builder,
1091 |_, prim| {
1092 if clip_needs_scissor_rect {
1093 results
1094 .image_mask_instances_with_scissor
1095 .entry((target_rect, texture))
1096 .or_insert_with(|| memory.new_vec())
1097 .push(prim);
1098 } else {
1099 results
1100 .image_mask_instances
1101 .entry(texture)
1102 .or_insert_with(|| memory.new_vec())
1103 .push(prim);
1104 }
1105 }
1106 );
1107 }
1108
1109 continue;
1113 }
1114 };
1115
1116 let prim_spatial_node = spatial_tree.get_spatial_node(prim_spatial_node_index);
1117 let clip_spatial_node = spatial_tree.get_spatial_node(clip_node.item.spatial_node_index);
1118 let raster_spatial_node = spatial_tree.get_spatial_node(raster_spatial_node_index);
1119 let raster_clip = raster_spatial_node.coordinate_system_id == clip_spatial_node.coordinate_system_id;
1120
1121 let (clip_space, clip_transform_id, main_prim_address, prim_transform_id, is_same_coord_system) = if raster_clip {
1122 let prim_transform_id = TransformPaletteId::IDENTITY;
1123 let pattern = Pattern::color(ColorF::WHITE);
1124
1125 let clip_transform_id = transforms.get_id(
1126 raster_spatial_node_index,
1127 clip_node.item.spatial_node_index,
1128 spatial_tree,
1129 );
1130
1131 let main_prim_address = quad::write_prim_blocks(
1132 &mut gpu_buffer_builder.f32,
1133 task_world_rect.cast_unit(),
1134 task_world_rect.cast_unit(),
1135 pattern.base_color,
1136 pattern.texture_input.task_id,
1137 &[],
1138 ScaleOffset::identity(),
1139 );
1140
1141 (ClipSpace::Raster, clip_transform_id, main_prim_address, prim_transform_id, true)
1142 } else {
1143 let prim_transform_id = transforms.get_id(
1144 prim_spatial_node_index,
1145 raster_spatial_node_index,
1146 spatial_tree,
1147 );
1148
1149 let clip_transform_id = if prim_spatial_node.coordinate_system_id < clip_spatial_node.coordinate_system_id {
1150 transforms.get_id(
1151 clip_node.item.spatial_node_index,
1152 prim_spatial_node_index,
1153 spatial_tree,
1154 )
1155 } else {
1156 transforms.get_id(
1157 prim_spatial_node_index,
1158 clip_node.item.spatial_node_index,
1159 spatial_tree,
1160 )
1161 };
1162
1163 let is_same_coord_system = spatial_tree.is_matching_coord_system(
1164 prim_spatial_node_index,
1165 raster_spatial_node_index,
1166 );
1167
1168 (ClipSpace::Primitive, clip_transform_id, main_prim_address, prim_transform_id, is_same_coord_system)
1169 };
1170
1171 let clip_needs_scissor_rect = !is_same_coord_system;
1172
1173 let quad_flags = if is_same_coord_system {
1174 QuadFlags::APPLY_RENDER_TASK_CLIP
1175 } else {
1176 QuadFlags::empty()
1177 };
1178
1179 quad::add_to_batch(
1180 PatternKind::Mask,
1181 PatternShaderInput::default(),
1182 render_task_address,
1183 prim_transform_id,
1184 main_prim_address,
1185 quad_flags,
1186 EdgeAaSegmentMask::all(),
1187 INVALID_SEGMENT_INDEX as u8,
1188 RenderTaskId::INVALID,
1189 ZBufferId(0),
1190 render_tasks,
1191 gpu_buffer_builder,
1192 |_, prim| {
1193 let instance = MaskInstance {
1194 prim,
1195 clip_transform_id,
1196 clip_address: clip_address.as_int(),
1197 clip_space: clip_space.as_int(),
1198 unused: 0,
1199 };
1200
1201 if clip_needs_scissor_rect {
1202 if fast_path {
1203 results.mask_instances_fast_with_scissor
1204 .entry(target_rect)
1205 .or_insert_with(|| memory.new_vec())
1206 .push(instance);
1207 } else {
1208 results.mask_instances_slow_with_scissor
1209 .entry(target_rect)
1210 .or_insert_with(|| memory.new_vec())
1211 .push(instance);
1212 }
1213 } else {
1214 if fast_path {
1215 results.mask_instances_fast.push(instance);
1216 } else {
1217 results.mask_instances_slow.push(instance);
1218 }
1219 }
1220 }
1221 );
1222 }
1223}
1224
1225fn build_sub_pass(
1226 task_id: RenderTaskId,
1227 task: &RenderTask,
1228 gpu_buffer_builder: &mut GpuBufferBuilder,
1229 render_tasks: &RenderTaskGraph,
1230 transforms: &mut TransformPalette,
1231 ctx: &RenderTargetContext,
1232 output: &mut ClipMaskInstanceList,
1233) {
1234 if let Some(ref sub_pass) = task.sub_pass {
1235 match sub_pass {
1236 SubPass::Masks { ref masks } => {
1237 let render_task_address = task_id.into();
1238 let target_rect = task.get_target_rect();
1239
1240 let (device_pixel_scale, content_origin, raster_spatial_node_index) = match task.kind {
1241 RenderTaskKind::Picture(ref info) => {
1242 (info.device_pixel_scale, info.content_origin, info.raster_spatial_node_index)
1243 }
1244 RenderTaskKind::Empty(ref info) => {
1245 (info.device_pixel_scale, info.content_origin, info.raster_spatial_node_index)
1246 }
1247 RenderTaskKind::Prim(ref info) => {
1248 (info.device_pixel_scale, info.content_origin, info.raster_spatial_node_index)
1249 }
1250 _ => panic!("unexpected: {}", task.kind.as_str()),
1251 };
1252
1253 let content_rect = DeviceRect::new(
1254 content_origin,
1255 content_origin + target_rect.size().to_f32(),
1256 );
1257
1258 build_mask_tasks(
1259 masks,
1260 render_task_address,
1261 content_rect / device_pixel_scale,
1262 target_rect,
1263 masks.prim_address_f,
1264 masks.prim_spatial_node_index,
1265 raster_spatial_node_index,
1266 ctx.clip_store,
1267 ctx.data_stores,
1268 ctx.spatial_tree,
1269 gpu_buffer_builder,
1270 transforms,
1271 render_tasks,
1272 output,
1273 &ctx.frame_memory,
1274 );
1275 }
1276 }
1277 }
1278}