1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 
6 use api::units::*;
7 use api::{ColorF, ImageFormat, LineOrientation, BorderStyle};
8 use crate::batch::{AlphaBatchBuilder, AlphaBatchContainer, BatchTextures};
9 use crate::batch::{ClipBatcher, BatchBuilder};
10 use crate::spatial_tree::SpatialTree;
11 use crate::clip::ClipStore;
12 use crate::composite::CompositeState;
13 use crate::frame_builder::{FrameGlobalResources};
14 use crate::gpu_cache::{GpuCache, GpuCacheAddress};
15 use crate::gpu_types::{BorderInstance, SvgFilterInstance, BlurDirection, BlurInstance, PrimitiveHeaders, ScalingInstance};
16 use crate::gpu_types::{TransformPalette, ZBufferIdGenerator};
17 use crate::internal_types::{FastHashMap, TextureSource, CacheTextureId};
18 use crate::picture::{SliceId, SurfaceInfo, ResolvedSurfaceTexture, TileCacheInstance};
19 use crate::prim_store::{PrimitiveInstance, PrimitiveStore, DeferredResolve, PrimitiveScratchBuffer};
20 use crate::prim_store::gradient::{
21     FastLinearGradientInstance, LinearGradientInstance, RadialGradientInstance,
22     ConicGradientInstance,
23 };
24 use crate::render_backend::DataStores;
25 use crate::render_task::{RenderTaskKind, RenderTaskAddress};
26 use crate::render_task::{RenderTask, ScalingTask, SvgFilterInfo};
27 use crate::render_task_graph::{RenderTaskGraph, RenderTaskId};
28 use crate::resource_cache::ResourceCache;
29 use crate::spatial_tree::SpatialNodeIndex;
30 
31 
32 const STYLE_SOLID: i32 = ((BorderStyle::Solid as i32) << 8) | ((BorderStyle::Solid as i32) << 16);
33 const STYLE_MASK: i32 = 0x00FF_FF00;
34 
35 /// A tag used to identify the output format of a `RenderTarget`.
36 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
37 #[cfg_attr(feature = "capture", derive(Serialize))]
38 #[cfg_attr(feature = "replay", derive(Deserialize))]
39 pub enum RenderTargetKind {
40     Color, // RGBA8
41     Alpha, // R8
42 }
43 
44 /// Identifies a given `RenderTarget` in a `RenderTargetList`.
45 #[derive(Debug, Copy, Clone)]
46 #[cfg_attr(feature = "capture", derive(Serialize))]
47 #[cfg_attr(feature = "replay", derive(Deserialize))]
48 pub struct RenderTargetIndex(pub usize);
49 
50 pub struct RenderTargetContext<'a, 'rc> {
51     pub global_device_pixel_scale: DevicePixelScale,
52     pub prim_store: &'a PrimitiveStore,
53     pub resource_cache: &'rc mut ResourceCache,
54     pub use_dual_source_blending: bool,
55     pub use_advanced_blending: bool,
56     pub break_advanced_blend_batches: bool,
57     pub batch_lookback_count: usize,
58     pub spatial_tree: &'a SpatialTree,
59     pub data_stores: &'a DataStores,
60     pub surfaces: &'a [SurfaceInfo],
61     pub scratch: &'a PrimitiveScratchBuffer,
62     pub screen_world_rect: WorldRect,
63     pub globals: &'a FrameGlobalResources,
64     pub tile_caches: &'a FastHashMap<SliceId, Box<TileCacheInstance>>,
65     pub root_spatial_node_index: SpatialNodeIndex,
66 }
67 
68 /// Represents a number of rendering operations on a surface.
69 ///
70 /// In graphics parlance, a "render target" usually means "a surface (texture or
71 /// framebuffer) bound to the output of a shader". This trait has a slightly
72 /// different meaning, in that it represents the operations on that surface
73 /// _before_ it's actually bound and rendered. So a `RenderTarget` is built by
74 /// the `RenderBackend` by inserting tasks, and then shipped over to the
75 /// `Renderer` where a device surface is resolved and the tasks are transformed
76 /// into draw commands on that surface.
77 ///
78 /// We express this as a trait to generalize over color and alpha surfaces.
79 /// a given `RenderTask` will draw to one or the other, depending on its type
80 /// and sometimes on its parameters. See `RenderTask::target_kind`.
81 pub trait RenderTarget {
82     /// Creates a new RenderTarget of the given type.
new( texture_id: CacheTextureId, screen_size: DeviceIntSize, gpu_supports_fast_clears: bool, used_rect: DeviceIntRect, ) -> Self83     fn new(
84         texture_id: CacheTextureId,
85         screen_size: DeviceIntSize,
86         gpu_supports_fast_clears: bool,
87         used_rect: DeviceIntRect,
88     ) -> Self;
89 
90     /// Optional hook to provide additional processing for the target at the
91     /// end of the build phase.
build( &mut self, _ctx: &mut RenderTargetContext, _gpu_cache: &mut GpuCache, _render_tasks: &RenderTaskGraph, _deferred_resolves: &mut Vec<DeferredResolve>, _prim_headers: &mut PrimitiveHeaders, _transforms: &mut TransformPalette, _z_generator: &mut ZBufferIdGenerator, _composite_state: &mut CompositeState, _prim_instances: &[PrimitiveInstance], )92     fn build(
93         &mut self,
94         _ctx: &mut RenderTargetContext,
95         _gpu_cache: &mut GpuCache,
96         _render_tasks: &RenderTaskGraph,
97         _deferred_resolves: &mut Vec<DeferredResolve>,
98         _prim_headers: &mut PrimitiveHeaders,
99         _transforms: &mut TransformPalette,
100         _z_generator: &mut ZBufferIdGenerator,
101         _composite_state: &mut CompositeState,
102         _prim_instances: &[PrimitiveInstance],
103     ) {
104     }
105 
106     /// Associates a `RenderTask` with this target. That task must be assigned
107     /// to a region returned by invoking `allocate()` on this target.
108     ///
109     /// TODO(gw): It's a bit odd that we need the deferred resolves and mutable
110     /// GPU cache here. They are typically used by the build step above. They
111     /// are used for the blit jobs to allow resolve_image to be called. It's a
112     /// bit of extra overhead to store the image key here and the resolve them
113     /// in the build step separately.  BUT: if/when we add more texture cache
114     /// target jobs, we might want to tidy this up.
add_task( &mut self, task_id: RenderTaskId, ctx: &RenderTargetContext, gpu_cache: &mut GpuCache, render_tasks: &RenderTaskGraph, clip_store: &ClipStore, transforms: &mut TransformPalette, )115     fn add_task(
116         &mut self,
117         task_id: RenderTaskId,
118         ctx: &RenderTargetContext,
119         gpu_cache: &mut GpuCache,
120         render_tasks: &RenderTaskGraph,
121         clip_store: &ClipStore,
122         transforms: &mut TransformPalette,
123     );
124 
needs_depth(&self) -> bool125     fn needs_depth(&self) -> bool;
texture_id(&self) -> CacheTextureId126     fn texture_id(&self) -> CacheTextureId;
127 }
128 
129 /// A series of `RenderTarget` instances, serving as the high-level container
130 /// into which `RenderTasks` are assigned.
131 ///
132 /// During the build phase, we iterate over the tasks in each `RenderPass`. For
133 /// each task, we invoke `allocate()` on the `RenderTargetList`, which in turn
134 /// attempts to allocate an output region in the last `RenderTarget` in the
135 /// list. If allocation fails (or if the list is empty), a new `RenderTarget` is
136 /// created and appended to the list. The build phase then assign the task into
137 /// the target associated with the final allocation.
138 ///
139 /// The result is that each `RenderPass` is associated with one or two
140 /// `RenderTargetLists`, depending on whether we have all our tasks have the
141 /// same `RenderTargetKind`. The lists are then shipped to the `Renderer`, which
142 /// allocates a device texture array, with one slice per render target in the
143 /// list.
144 ///
145 /// The upshot of this scheme is that it maximizes batching. In a given pass,
146 /// we need to do a separate batch for each individual render target. But with
147 /// the texture array, we can expose the entirety of the previous pass to each
148 /// task in the current pass in a single batch, which generally allows each
149 /// task to be drawn in a single batch regardless of how many results from the
150 /// previous pass it depends on.
151 ///
152 /// Note that in some cases (like drop-shadows), we can depend on the output of
153 /// a pass earlier than the immediately-preceding pass.
154 #[cfg_attr(feature = "capture", derive(Serialize))]
155 #[cfg_attr(feature = "replay", derive(Deserialize))]
156 pub struct RenderTargetList<T> {
157     pub format: ImageFormat,
158     pub targets: Vec<T>,
159 }
160 
161 impl<T: RenderTarget> RenderTargetList<T> {
new( format: ImageFormat, ) -> Self162     pub fn new(
163         format: ImageFormat,
164     ) -> Self {
165         RenderTargetList {
166             format,
167             targets: Vec::new(),
168         }
169     }
170 
build( &mut self, ctx: &mut RenderTargetContext, gpu_cache: &mut GpuCache, render_tasks: &RenderTaskGraph, deferred_resolves: &mut Vec<DeferredResolve>, prim_headers: &mut PrimitiveHeaders, transforms: &mut TransformPalette, z_generator: &mut ZBufferIdGenerator, composite_state: &mut CompositeState, prim_instances: &[PrimitiveInstance], )171     pub fn build(
172         &mut self,
173         ctx: &mut RenderTargetContext,
174         gpu_cache: &mut GpuCache,
175         render_tasks: &RenderTaskGraph,
176         deferred_resolves: &mut Vec<DeferredResolve>,
177         prim_headers: &mut PrimitiveHeaders,
178         transforms: &mut TransformPalette,
179         z_generator: &mut ZBufferIdGenerator,
180         composite_state: &mut CompositeState,
181         prim_instances: &[PrimitiveInstance],
182     ) {
183         if self.targets.is_empty() {
184             return;
185         }
186 
187         for target in &mut self.targets {
188             target.build(
189                 ctx,
190                 gpu_cache,
191                 render_tasks,
192                 deferred_resolves,
193                 prim_headers,
194                 transforms,
195                 z_generator,
196                 composite_state,
197                 prim_instances,
198             );
199         }
200     }
201 
needs_depth(&self) -> bool202     pub fn needs_depth(&self) -> bool {
203         self.targets.iter().any(|target| target.needs_depth())
204     }
205 }
206 
207 
208 /// Contains the work (in the form of instance arrays) needed to fill a color
209 /// color output surface (RGBA8).
210 ///
211 /// See `RenderTarget`.
212 #[cfg_attr(feature = "capture", derive(Serialize))]
213 #[cfg_attr(feature = "replay", derive(Deserialize))]
214 pub struct ColorRenderTarget {
215     pub alpha_batch_containers: Vec<AlphaBatchContainer>,
216     // List of blur operations to apply for this render target.
217     pub vertical_blurs: FastHashMap<TextureSource, Vec<BlurInstance>>,
218     pub horizontal_blurs: FastHashMap<TextureSource, Vec<BlurInstance>>,
219     pub scalings: FastHashMap<TextureSource, Vec<ScalingInstance>>,
220     pub svg_filters: Vec<(BatchTextures, Vec<SvgFilterInstance>)>,
221     pub blits: Vec<BlitJob>,
222     alpha_tasks: Vec<RenderTaskId>,
223     screen_size: DeviceIntSize,
224     pub texture_id: CacheTextureId,
225     // Track the used rect of the render target, so that
226     // we can set a scissor rect and only clear to the
227     // used portion of the target as an optimization.
228     pub used_rect: DeviceIntRect,
229 }
230 
231 impl RenderTarget for ColorRenderTarget {
new( texture_id: CacheTextureId, screen_size: DeviceIntSize, _: bool, used_rect: DeviceIntRect, ) -> Self232     fn new(
233         texture_id: CacheTextureId,
234         screen_size: DeviceIntSize,
235         _: bool,
236         used_rect: DeviceIntRect,
237     ) -> Self {
238         ColorRenderTarget {
239             alpha_batch_containers: Vec::new(),
240             vertical_blurs: FastHashMap::default(),
241             horizontal_blurs: FastHashMap::default(),
242             scalings: FastHashMap::default(),
243             svg_filters: Vec::new(),
244             blits: Vec::new(),
245             alpha_tasks: Vec::new(),
246             screen_size,
247             texture_id,
248             used_rect,
249         }
250     }
251 
build( &mut self, ctx: &mut RenderTargetContext, gpu_cache: &mut GpuCache, render_tasks: &RenderTaskGraph, deferred_resolves: &mut Vec<DeferredResolve>, prim_headers: &mut PrimitiveHeaders, transforms: &mut TransformPalette, z_generator: &mut ZBufferIdGenerator, composite_state: &mut CompositeState, prim_instances: &[PrimitiveInstance], )252     fn build(
253         &mut self,
254         ctx: &mut RenderTargetContext,
255         gpu_cache: &mut GpuCache,
256         render_tasks: &RenderTaskGraph,
257         deferred_resolves: &mut Vec<DeferredResolve>,
258         prim_headers: &mut PrimitiveHeaders,
259         transforms: &mut TransformPalette,
260         z_generator: &mut ZBufferIdGenerator,
261         composite_state: &mut CompositeState,
262         prim_instances: &[PrimitiveInstance],
263     ) {
264         profile_scope!("build");
265         let mut merged_batches = AlphaBatchContainer::new(None);
266 
267         for task_id in &self.alpha_tasks {
268             profile_scope!("alpha_task");
269             let task = &render_tasks[*task_id];
270 
271             match task.kind {
272                 RenderTaskKind::Picture(ref pic_task) => {
273                     let pic = &ctx.prim_store.pictures[pic_task.pic_index.0];
274 
275                     let raster_spatial_node_index = match pic.raster_config {
276                         Some(ref raster_config) => {
277                             let surface = &ctx.surfaces[raster_config.surface_index.0];
278                             surface.raster_spatial_node_index
279                         }
280                         None => {
281                             // This must be the main framebuffer
282                             ctx.root_spatial_node_index
283                         }
284                     };
285 
286                     let target_rect = task.get_target_rect();
287 
288                     let scissor_rect = if pic_task.can_merge {
289                         None
290                     } else {
291                         Some(target_rect)
292                     };
293 
294                     // Typical workloads have a single or a few batch builders with a
295                     // large number of batches (regular pictres) and a higher number
296                     // of batch builders with only a single or two batches (for example
297                     // rendering isolated primitives to compute their shadows).
298                     // We can easily guess which category we are in for each picture
299                     // by checking whether it has multiple clusters.
300                     let prealloc_batch_count = if pic.prim_list.clusters.len() > 1 {
301                         128
302                     } else {
303                         0
304                     };
305 
306                     // TODO(gw): The type names of AlphaBatchBuilder and BatchBuilder
307                     //           are still confusing. Once more of the picture caching
308                     //           improvement code lands, the AlphaBatchBuilder and
309                     //           AlphaBatchList types will be collapsed into one, which
310                     //           should simplify coming up with better type names.
311                     let alpha_batch_builder = AlphaBatchBuilder::new(
312                         self.screen_size,
313                         ctx.break_advanced_blend_batches,
314                         ctx.batch_lookback_count,
315                         *task_id,
316                         (*task_id).into(),
317                         None,
318                         prealloc_batch_count,
319                     );
320 
321                     let mut batch_builder = BatchBuilder::new(
322                         vec![alpha_batch_builder],
323                     );
324 
325                     batch_builder.add_pic_to_batch(
326                         pic,
327                         ctx,
328                         gpu_cache,
329                         render_tasks,
330                         deferred_resolves,
331                         prim_headers,
332                         transforms,
333                         raster_spatial_node_index,
334                         pic_task.surface_spatial_node_index,
335                         z_generator,
336                         composite_state,
337                         prim_instances,
338                     );
339 
340                     let alpha_batch_builders = batch_builder.finalize();
341 
342                     for batcher in alpha_batch_builders {
343                         batcher.build(
344                             &mut self.alpha_batch_containers,
345                             &mut merged_batches,
346                             target_rect,
347                             scissor_rect,
348                         );
349                     }
350                 }
351                 _ => {
352                     unreachable!();
353                 }
354             }
355         }
356 
357         if !merged_batches.is_empty() {
358             self.alpha_batch_containers.push(merged_batches);
359         }
360     }
361 
texture_id(&self) -> CacheTextureId362     fn texture_id(&self) -> CacheTextureId {
363         self.texture_id
364     }
365 
add_task( &mut self, task_id: RenderTaskId, _ctx: &RenderTargetContext, gpu_cache: &mut GpuCache, render_tasks: &RenderTaskGraph, _: &ClipStore, _: &mut TransformPalette, )366     fn add_task(
367         &mut self,
368         task_id: RenderTaskId,
369         _ctx: &RenderTargetContext,
370         gpu_cache: &mut GpuCache,
371         render_tasks: &RenderTaskGraph,
372         _: &ClipStore,
373         _: &mut TransformPalette,
374     ) {
375         profile_scope!("add_task");
376         let task = &render_tasks[task_id];
377 
378         match task.kind {
379             RenderTaskKind::VerticalBlur(..) => {
380                 add_blur_instances(
381                     &mut self.vertical_blurs,
382                     BlurDirection::Vertical,
383                     task_id.into(),
384                     task.children[0],
385                     render_tasks,
386                 );
387             }
388             RenderTaskKind::HorizontalBlur(..) => {
389                 add_blur_instances(
390                     &mut self.horizontal_blurs,
391                     BlurDirection::Horizontal,
392                     task_id.into(),
393                     task.children[0],
394                     render_tasks,
395                 );
396             }
397             RenderTaskKind::Picture(..) => {
398                 self.alpha_tasks.push(task_id);
399             }
400             RenderTaskKind::SvgFilter(ref task_info) => {
401                 add_svg_filter_instances(
402                     &mut self.svg_filters,
403                     render_tasks,
404                     &task_info.info,
405                     task_id,
406                     task.children.get(0).cloned(),
407                     task.children.get(1).cloned(),
408                     task_info.extra_gpu_cache_handle.map(|handle| gpu_cache.get_address(&handle)),
409                 )
410             }
411             RenderTaskKind::Image(..) |
412             RenderTaskKind::Cached(..) |
413             RenderTaskKind::ClipRegion(..) |
414             RenderTaskKind::Border(..) |
415             RenderTaskKind::CacheMask(..) |
416             RenderTaskKind::FastLinearGradient(..) |
417             RenderTaskKind::LinearGradient(..) |
418             RenderTaskKind::RadialGradient(..) |
419             RenderTaskKind::ConicGradient(..) |
420             RenderTaskKind::LineDecoration(..) => {
421                 panic!("Should not be added to color target!");
422             }
423             RenderTaskKind::Readback(..) => {}
424             RenderTaskKind::Scaling(ref info) => {
425                 add_scaling_instances(
426                     info,
427                     &mut self.scalings,
428                     task,
429                     task.children.first().map(|&child| &render_tasks[child]),
430                 );
431             }
432             RenderTaskKind::Blit(ref task_info) => {
433                 let target_rect = task
434                     .get_target_rect();
435                 self.blits.push(BlitJob {
436                     source: task_info.source,
437                     target_rect,
438                 });
439             }
440             #[cfg(test)]
441             RenderTaskKind::Test(..) => {}
442         }
443     }
444 
needs_depth(&self) -> bool445     fn needs_depth(&self) -> bool {
446         self.alpha_batch_containers.iter().any(|ab| {
447             !ab.opaque_batches.is_empty()
448         })
449     }
450 }
451 
452 /// Contains the work (in the form of instance arrays) needed to fill an alpha
453 /// output surface (R8).
454 ///
455 /// See `RenderTarget`.
456 #[cfg_attr(feature = "capture", derive(Serialize))]
457 #[cfg_attr(feature = "replay", derive(Deserialize))]
458 pub struct AlphaRenderTarget {
459     pub clip_batcher: ClipBatcher,
460     // List of blur operations to apply for this render target.
461     pub vertical_blurs: FastHashMap<TextureSource, Vec<BlurInstance>>,
462     pub horizontal_blurs: FastHashMap<TextureSource, Vec<BlurInstance>>,
463     pub scalings: FastHashMap<TextureSource, Vec<ScalingInstance>>,
464     pub zero_clears: Vec<RenderTaskId>,
465     pub one_clears: Vec<RenderTaskId>,
466     pub texture_id: CacheTextureId,
467 }
468 
469 impl RenderTarget for AlphaRenderTarget {
new( texture_id: CacheTextureId, _: DeviceIntSize, gpu_supports_fast_clears: bool, _: DeviceIntRect, ) -> Self470     fn new(
471         texture_id: CacheTextureId,
472         _: DeviceIntSize,
473         gpu_supports_fast_clears: bool,
474         _: DeviceIntRect,
475     ) -> Self {
476         AlphaRenderTarget {
477             clip_batcher: ClipBatcher::new(gpu_supports_fast_clears),
478             vertical_blurs: FastHashMap::default(),
479             horizontal_blurs: FastHashMap::default(),
480             scalings: FastHashMap::default(),
481             zero_clears: Vec::new(),
482             one_clears: Vec::new(),
483             texture_id,
484         }
485     }
486 
texture_id(&self) -> CacheTextureId487     fn texture_id(&self) -> CacheTextureId {
488         self.texture_id
489     }
490 
add_task( &mut self, task_id: RenderTaskId, ctx: &RenderTargetContext, gpu_cache: &mut GpuCache, render_tasks: &RenderTaskGraph, clip_store: &ClipStore, transforms: &mut TransformPalette, )491     fn add_task(
492         &mut self,
493         task_id: RenderTaskId,
494         ctx: &RenderTargetContext,
495         gpu_cache: &mut GpuCache,
496         render_tasks: &RenderTaskGraph,
497         clip_store: &ClipStore,
498         transforms: &mut TransformPalette,
499     ) {
500         profile_scope!("add_task");
501         let task = &render_tasks[task_id];
502         let target_rect = task.get_target_rect();
503 
504         match task.kind {
505             RenderTaskKind::Image(..) |
506             RenderTaskKind::Cached(..) |
507             RenderTaskKind::Readback(..) |
508             RenderTaskKind::Picture(..) |
509             RenderTaskKind::Blit(..) |
510             RenderTaskKind::Border(..) |
511             RenderTaskKind::LineDecoration(..) |
512             RenderTaskKind::FastLinearGradient(..) |
513             RenderTaskKind::LinearGradient(..) |
514             RenderTaskKind::RadialGradient(..) |
515             RenderTaskKind::ConicGradient(..) |
516             RenderTaskKind::SvgFilter(..) => {
517                 panic!("BUG: should not be added to alpha target!");
518             }
519             RenderTaskKind::VerticalBlur(..) => {
520                 self.zero_clears.push(task_id);
521                 add_blur_instances(
522                     &mut self.vertical_blurs,
523                     BlurDirection::Vertical,
524                     task_id.into(),
525                     task.children[0],
526                     render_tasks,
527                 );
528             }
529             RenderTaskKind::HorizontalBlur(..) => {
530                 self.zero_clears.push(task_id);
531                 add_blur_instances(
532                     &mut self.horizontal_blurs,
533                     BlurDirection::Horizontal,
534                     task_id.into(),
535                     task.children[0],
536                     render_tasks,
537                 );
538             }
539             RenderTaskKind::CacheMask(ref task_info) => {
540                 let clear_to_one = self.clip_batcher.add(
541                     task_info.clip_node_range,
542                     task_info.root_spatial_node_index,
543                     render_tasks,
544                     gpu_cache,
545                     clip_store,
546                     transforms,
547                     task_info.actual_rect,
548                     task_info.device_pixel_scale,
549                     target_rect.min.to_f32(),
550                     task_info.actual_rect.min,
551                     ctx,
552                 );
553                 if task_info.clear_to_one || clear_to_one {
554                     self.one_clears.push(task_id);
555                 }
556             }
557             RenderTaskKind::ClipRegion(ref region_task) => {
558                 if region_task.clear_to_one {
559                     self.one_clears.push(task_id);
560                 }
561                 let device_rect = DeviceRect::from_size(
562                     target_rect.size().to_f32(),
563                 );
564                 self.clip_batcher.add_clip_region(
565                     region_task.local_pos,
566                     device_rect,
567                     region_task.clip_data.clone(),
568                     target_rect.min.to_f32(),
569                     DevicePoint::zero(),
570                     region_task.device_pixel_scale.0,
571                 );
572             }
573             RenderTaskKind::Scaling(ref info) => {
574                 add_scaling_instances(
575                     info,
576                     &mut self.scalings,
577                     task,
578                     task.children.first().map(|&child| &render_tasks[child]),
579                 );
580             }
581             #[cfg(test)]
582             RenderTaskKind::Test(..) => {}
583         }
584     }
585 
needs_depth(&self) -> bool586     fn needs_depth(&self) -> bool {
587         false
588     }
589 }
590 
591 #[cfg_attr(feature = "capture", derive(Serialize))]
592 #[cfg_attr(feature = "replay", derive(Deserialize))]
593 pub struct PictureCacheTarget {
594     pub surface: ResolvedSurfaceTexture,
595     pub alpha_batch_container: AlphaBatchContainer,
596     pub clear_color: Option<ColorF>,
597     pub dirty_rect: DeviceIntRect,
598     pub valid_rect: DeviceIntRect,
599 }
600 
601 #[cfg_attr(feature = "capture", derive(Serialize))]
602 #[cfg_attr(feature = "replay", derive(Deserialize))]
603 pub struct TextureCacheRenderTarget {
604     pub target_kind: RenderTargetKind,
605     pub horizontal_blurs: FastHashMap<TextureSource, Vec<BlurInstance>>,
606     pub blits: Vec<BlitJob>,
607     pub border_segments_complex: Vec<BorderInstance>,
608     pub border_segments_solid: Vec<BorderInstance>,
609     pub clears: Vec<DeviceIntRect>,
610     pub line_decorations: Vec<LineDecorationJob>,
611     pub fast_linear_gradients: Vec<FastLinearGradientInstance>,
612     pub linear_gradients: Vec<LinearGradientInstance>,
613     pub radial_gradients: Vec<RadialGradientInstance>,
614     pub conic_gradients: Vec<ConicGradientInstance>,
615 }
616 
617 impl TextureCacheRenderTarget {
new(target_kind: RenderTargetKind) -> Self618     pub fn new(target_kind: RenderTargetKind) -> Self {
619         TextureCacheRenderTarget {
620             target_kind,
621             horizontal_blurs: FastHashMap::default(),
622             blits: vec![],
623             border_segments_complex: vec![],
624             border_segments_solid: vec![],
625             clears: vec![],
626             line_decorations: vec![],
627             fast_linear_gradients: vec![],
628             linear_gradients: vec![],
629             radial_gradients: vec![],
630             conic_gradients: vec![],
631         }
632     }
633 
add_task( &mut self, task_id: RenderTaskId, render_tasks: &RenderTaskGraph, gpu_cache: &mut GpuCache, )634     pub fn add_task(
635         &mut self,
636         task_id: RenderTaskId,
637         render_tasks: &RenderTaskGraph,
638         gpu_cache: &mut GpuCache,
639     ) {
640         profile_scope!("add_task");
641         let task_address = task_id.into();
642 
643         let task = &render_tasks[task_id];
644         let target_rect = task.get_target_rect();
645 
646         match task.kind {
647             RenderTaskKind::LineDecoration(ref info) => {
648                 self.clears.push(target_rect);
649 
650                 self.line_decorations.push(LineDecorationJob {
651                     task_rect: target_rect.to_f32(),
652                     local_size: info.local_size,
653                     style: info.style as i32,
654                     axis_select: match info.orientation {
655                         LineOrientation::Horizontal => 0.0,
656                         LineOrientation::Vertical => 1.0,
657                     },
658                     wavy_line_thickness: info.wavy_line_thickness,
659                 });
660             }
661             RenderTaskKind::HorizontalBlur(..) => {
662                 add_blur_instances(
663                     &mut self.horizontal_blurs,
664                     BlurDirection::Horizontal,
665                     task_address,
666                     task.children[0],
667                     render_tasks,
668                 );
669             }
670             RenderTaskKind::Blit(ref task_info) => {
671                 // Add a blit job to copy from an existing render
672                 // task to this target.
673                 self.blits.push(BlitJob {
674                     source: task_info.source,
675                     target_rect,
676                 });
677             }
678             RenderTaskKind::Border(ref task_info) => {
679                 self.clears.push(target_rect);
680 
681                 let task_origin = target_rect.min.to_f32();
682                 // TODO(gw): Clone here instead of a move of this vec, since the frame
683                 //           graph is immutable by this point. It's rare that borders
684                 //           are drawn since they are persisted in the texture cache,
685                 //           but perhaps this could be improved in future.
686                 let instances = task_info.instances.clone();
687                 for mut instance in instances {
688                     // TODO(gw): It may be better to store the task origin in
689                     //           the render task data instead of per instance.
690                     instance.task_origin = task_origin;
691                     if instance.flags & STYLE_MASK == STYLE_SOLID {
692                         self.border_segments_solid.push(instance);
693                     } else {
694                         self.border_segments_complex.push(instance);
695                     }
696                 }
697             }
698             RenderTaskKind::FastLinearGradient(ref task_info) => {
699                 self.fast_linear_gradients.push(task_info.to_instance(&target_rect));
700             }
701             RenderTaskKind::LinearGradient(ref task_info) => {
702                 self.linear_gradients.push(task_info.to_instance(&target_rect, gpu_cache));
703             }
704             RenderTaskKind::RadialGradient(ref task_info) => {
705                 self.radial_gradients.push(task_info.to_instance(&target_rect, gpu_cache));
706             }
707             RenderTaskKind::ConicGradient(ref task_info) => {
708                 self.conic_gradients.push(task_info.to_instance(&target_rect, gpu_cache));
709             }
710             RenderTaskKind::Image(..) |
711             RenderTaskKind::Cached(..) |
712             RenderTaskKind::VerticalBlur(..) |
713             RenderTaskKind::Picture(..) |
714             RenderTaskKind::ClipRegion(..) |
715             RenderTaskKind::CacheMask(..) |
716             RenderTaskKind::Readback(..) |
717             RenderTaskKind::Scaling(..) |
718             RenderTaskKind::SvgFilter(..) => {
719                 panic!("BUG: unexpected task kind for texture cache target");
720             }
721             #[cfg(test)]
722             RenderTaskKind::Test(..) => {}
723         }
724     }
725 }
726 
add_blur_instances( instances: &mut FastHashMap<TextureSource, Vec<BlurInstance>>, blur_direction: BlurDirection, task_address: RenderTaskAddress, src_task_id: RenderTaskId, render_tasks: &RenderTaskGraph, )727 fn add_blur_instances(
728     instances: &mut FastHashMap<TextureSource, Vec<BlurInstance>>,
729     blur_direction: BlurDirection,
730     task_address: RenderTaskAddress,
731     src_task_id: RenderTaskId,
732     render_tasks: &RenderTaskGraph,
733 ) {
734     let source = render_tasks[src_task_id].get_texture_source();
735 
736     let instance = BlurInstance {
737         task_address,
738         src_task_address: src_task_id.into(),
739         blur_direction,
740     };
741 
742     instances
743         .entry(source)
744         .or_insert(Vec::new())
745         .push(instance);
746 }
747 
add_scaling_instances( task: &ScalingTask, instances: &mut FastHashMap<TextureSource, Vec<ScalingInstance>>, target_task: &RenderTask, source_task: Option<&RenderTask>, )748 fn add_scaling_instances(
749     task: &ScalingTask,
750     instances: &mut FastHashMap<TextureSource, Vec<ScalingInstance>>,
751     target_task: &RenderTask,
752     source_task: Option<&RenderTask>,
753 ) {
754     let target_rect = target_task
755         .get_target_rect()
756         .inner_box(task.padding)
757         .to_f32();
758 
759     let source = source_task.unwrap().get_texture_source();
760 
761     let source_rect = source_task.unwrap().get_target_rect().to_f32();
762 
763     instances
764         .entry(source)
765         .or_insert(Vec::new())
766         .push(ScalingInstance {
767             target_rect,
768             source_rect,
769         });
770 }
771 
add_svg_filter_instances( instances: &mut Vec<(BatchTextures, Vec<SvgFilterInstance>)>, render_tasks: &RenderTaskGraph, filter: &SvgFilterInfo, task_id: RenderTaskId, input_1_task: Option<RenderTaskId>, input_2_task: Option<RenderTaskId>, extra_data_address: Option<GpuCacheAddress>, )772 fn add_svg_filter_instances(
773     instances: &mut Vec<(BatchTextures, Vec<SvgFilterInstance>)>,
774     render_tasks: &RenderTaskGraph,
775     filter: &SvgFilterInfo,
776     task_id: RenderTaskId,
777     input_1_task: Option<RenderTaskId>,
778     input_2_task: Option<RenderTaskId>,
779     extra_data_address: Option<GpuCacheAddress>,
780 ) {
781     let mut textures = BatchTextures::empty();
782 
783     if let Some(id) = input_1_task {
784         textures.input.colors[0] = render_tasks[id].get_texture_source();
785     }
786 
787     if let Some(id) = input_2_task {
788         textures.input.colors[1] = render_tasks[id].get_texture_source();
789     }
790 
791     let kind = match filter {
792         SvgFilterInfo::Blend(..) => 0,
793         SvgFilterInfo::Flood(..) => 1,
794         SvgFilterInfo::LinearToSrgb => 2,
795         SvgFilterInfo::SrgbToLinear => 3,
796         SvgFilterInfo::Opacity(..) => 4,
797         SvgFilterInfo::ColorMatrix(..) => 5,
798         SvgFilterInfo::DropShadow(..) => 6,
799         SvgFilterInfo::Offset(..) => 7,
800         SvgFilterInfo::ComponentTransfer(..) => 8,
801         SvgFilterInfo::Identity => 9,
802         SvgFilterInfo::Composite(..) => 10,
803     };
804 
805     let input_count = match filter {
806         SvgFilterInfo::Flood(..) => 0,
807 
808         SvgFilterInfo::LinearToSrgb |
809         SvgFilterInfo::SrgbToLinear |
810         SvgFilterInfo::Opacity(..) |
811         SvgFilterInfo::ColorMatrix(..) |
812         SvgFilterInfo::Offset(..) |
813         SvgFilterInfo::ComponentTransfer(..) |
814         SvgFilterInfo::Identity => 1,
815 
816         // Not techincally a 2 input filter, but we have 2 inputs here: original content & blurred content.
817         SvgFilterInfo::DropShadow(..) |
818         SvgFilterInfo::Blend(..) |
819         SvgFilterInfo::Composite(..) => 2,
820     };
821 
822     let generic_int = match filter {
823         SvgFilterInfo::Blend(mode) => *mode as u16,
824         SvgFilterInfo::ComponentTransfer(data) =>
825             ((data.r_func.to_int() << 12 |
826               data.g_func.to_int() << 8 |
827               data.b_func.to_int() << 4 |
828               data.a_func.to_int()) as u16),
829         SvgFilterInfo::Composite(operator) =>
830             operator.as_int() as u16,
831         SvgFilterInfo::LinearToSrgb |
832         SvgFilterInfo::SrgbToLinear |
833         SvgFilterInfo::Flood(..) |
834         SvgFilterInfo::Opacity(..) |
835         SvgFilterInfo::ColorMatrix(..) |
836         SvgFilterInfo::DropShadow(..) |
837         SvgFilterInfo::Offset(..) |
838         SvgFilterInfo::Identity => 0,
839     };
840 
841     let instance = SvgFilterInstance {
842         task_address: task_id.into(),
843         input_1_task_address: input_1_task.map(|id| id.into()).unwrap_or(RenderTaskAddress(0)),
844         input_2_task_address: input_2_task.map(|id| id.into()).unwrap_or(RenderTaskAddress(0)),
845         kind,
846         input_count,
847         generic_int,
848         extra_data_address: extra_data_address.unwrap_or(GpuCacheAddress::INVALID),
849     };
850 
851     for (ref mut batch_textures, ref mut batch) in instances.iter_mut() {
852         if let Some(combined_textures) = batch_textures.combine_textures(textures) {
853             batch.push(instance);
854             // Update the batch textures to the newly combined batch textures
855             *batch_textures = combined_textures;
856             return;
857         }
858     }
859 
860     instances.push((textures, vec![instance]));
861 }
862 
863 // Information required to do a blit from a source to a target.
864 #[cfg_attr(feature = "capture", derive(Serialize))]
865 #[cfg_attr(feature = "replay", derive(Deserialize))]
866 pub struct BlitJob {
867     pub source: RenderTaskId,
868     pub target_rect: DeviceIntRect,
869 }
870 
871 #[cfg_attr(feature = "capture", derive(Serialize))]
872 #[cfg_attr(feature = "replay", derive(Deserialize))]
873 #[derive(Clone, Debug)]
874 pub struct LineDecorationJob {
875     pub task_rect: DeviceRect,
876     pub local_size: LayoutSize,
877     pub wavy_line_thickness: f32,
878     pub style: i32,
879     pub axis_select: f32,
880 }
881