| author | Connor Brewster <cbrewster@mozilla.com> |
| Tue, 13 Aug 2019 22:02:44 +0000 | |
| changeset 487807 | abdb4f5f3323cc1474d02a3722741c5d2cea5df7 |
| parent 487806 | b5d6ed62cda18c51ae303d6b904771850a3d1e03 |
| child 487808 | 94f900c3b51435d0a098ecd4f0082800bcfd05f7 |
| push id | 36430 |
| push user | dvarga@mozilla.com |
| push date | Wed, 14 Aug 2019 04:09:17 +0000 |
| treeherder | mozilla-central@d3deef805f92 [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | gw |
| bugs | 1178765 |
| milestone | 70.0a1 |
| first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/webrender_bindings/webrender_ffi.h +++ b/gfx/webrender_bindings/webrender_ffi.h @@ -46,17 +46,18 @@ bool gecko_profiler_thread_is_being_prof macro(image_border); \ macro(image); \ macro(yuv_image); \ macro(line_decoration); \ macro(linear_grad); \ macro(radial_grad); \ macro(picture); \ macro(text_run); \ - macro(filterdata); + macro(filterdata); \ + macro(backdrop); // Prelude of types necessary before including webrender_ffi_generated.h namespace mozilla { namespace wr { // Because this struct is macro-generated on the Rust side, cbindgen can't see // it. Work around that by re-declaring it here. #define DECLARE_MEMBER(id) uintptr_t id;
--- a/gfx/wr/webrender/src/batch.rs +++ b/gfx/wr/webrender/src/batch.rs @@ -1627,19 +1627,29 @@ impl BatchBuilder { prim_vis_mask, ); } PictureCompositeMode::Blit(_) => { let cache_task_id = surface_task.expect("bug: surface must be allocated by now"); let uv_rect_address = render_tasks[cache_task_id] .get_texture_address(gpu_cache) .as_int(); + let textures = match render_tasks[cache_task_id].saved_index { + Some(saved_index) => BatchTextures { + colors: [ + TextureSource::RenderTaskCache(saved_index, Swizzle::default()), + TextureSource::PrevPassAlpha, + TextureSource::Invalid, + ] + }, + None => BatchTextures::render_target_cache(), + }; let batch_params = BrushBatchParameters::shared( BrushBatchKind::Image(ImageBufferKind::Texture2DArray), - BatchTextures::render_target_cache(), + textures, [ ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), RasterizationSpace::Screen as i32, get_shader_opacity(1.0), 0, ], uv_rect_address, ); @@ -2362,16 +2372,77 @@ impl BatchBuilder { gpu_cache, &prim_header, prim_headers, z_id, prim_vis_mask, ); } } + PrimitiveInstanceKind::Backdrop { data_handle } => { + let prim_data = &ctx.data_stores.backdrop[data_handle]; + let backdrop_pic_index = prim_data.kind.pic_index; + let backdrop_surface_index = ctx.prim_store.pictures[backdrop_pic_index.0] + .raster_config + .as_ref() + .expect("backdrop surface should be alloc by now") + .surface_index; + + let backdrop_task_id = ctx.surfaces[backdrop_surface_index.0] + .render_tasks + .as_ref() + .expect("backdrop task not available") + .root; + + let backdrop_uv_rect_address = render_tasks[backdrop_task_id] + .get_texture_address(gpu_cache) + .as_int(); + + let textures = BatchTextures::render_target_cache(); + let batch_key = BatchKey::new( + BatchKind::Brush(BrushBatchKind::Image(ImageBufferKind::Texture2DArray)), + BlendMode::PremultipliedAlpha, + textures, + ); + + let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle); + let backdrop_picture = &ctx.prim_store.pictures[backdrop_pic_index.0]; + let prim_header = PrimitiveHeader { + local_rect: backdrop_picture.snapped_local_rect, + local_clip_rect: prim_info.combined_local_clip_rect, + transform_id, + snap_offsets, + specific_prim_address: prim_cache_address, + }; + + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + [ + ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), + RasterizationSpace::Screen as i32, + get_shader_opacity(1.0), + 0 + ], + ); + + self.add_brush_instance_to_batches( + batch_key, + batch_features, + bounding_rect, + z_id, + INVALID_SEGMENT_INDEX, + EdgeAaSegmentMask::empty(), + OPAQUE_TASK_ADDRESS, + BrushFlags::empty(), + prim_header_index, + backdrop_uv_rect_address, + prim_vis_mask, + ); + } } } /// Add a single segment instance to a batch. fn add_segment_to_batch( &mut self, segment: &BrushSegment, segment_data: &SegmentInstanceData, @@ -2690,17 +2761,18 @@ impl PrimitiveInstance { PrimitiveInstanceKind::LineDecoration { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::Rectangle { .. } | PrimitiveInstanceKind::LinearGradient { .. } | PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::PushClipChain | PrimitiveInstanceKind::PopClipChain | - PrimitiveInstanceKind::Clear { .. } => { + PrimitiveInstanceKind::Clear { .. } | + PrimitiveInstanceKind::Backdrop { .. } => { return true; } }; match resource_cache.get_image_properties(image_key) { Some(ImageProperties { external_image: Some(_), .. }) => { false } _ => true
--- a/gfx/wr/webrender/src/display_list_flattener.rs +++ b/gfx/wr/webrender/src/display_list_flattener.rs @@ -1,37 +1,38 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter}; -use api::{ClipId, ColorF, CommonItemProperties, ComplexClipRegion, RasterSpace}; -use api::{DisplayItem, DisplayItemRef, ExtendMode, ExternalScrollId}; +use api::{ClipId, ColorF, CommonItemProperties, ComplexClipRegion, ComponentTransferFuncType, RasterSpace}; +use api::{DisplayItem, DisplayItemRef, ExtendMode, ExternalScrollId, FilterData}; use api::{FilterOp, FilterPrimitive, FontInstanceKey, GlyphInstance, GlyphOptions, GradientStop}; use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, ColorDepth}; use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId}; use api::{PropertyBinding, ReferenceFrame, ReferenceFrameKind, ScrollFrameDisplayItem, ScrollSensitivity}; use api::{Shadow, SpaceAndClipInfo, SpatialId, StackingContext, StickyFrameDisplayItem}; use api::{ClipMode, PrimitiveKeyKind, TransformStyle, YuvColorSpace, ColorRange, YuvData, TempFilterData}; use api::units::*; use crate::clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore}; use crate::clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex}; use crate::frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig}; use crate::glyph_rasterizer::FontInstance; use crate::hit_test::{HitTestingItem, HitTestingScene}; use crate::image::simplify_repeated_primitive; use crate::intern::Interner; use crate::internal_types::{FastHashMap, FastHashSet, LayoutPrimitiveInfo, Filter}; use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureOptions}; -use crate::picture::{BlitReason, PrimitiveList, TileCacheInstance}; +use crate::picture::{BlitReason, OrderedPictureChild, PrimitiveList, TileCacheInstance}; use crate::prim_store::{PrimitiveInstance, PrimitiveSceneData}; use crate::prim_store::{PrimitiveInstanceKind, NinePatchDescriptor, PrimitiveStore}; use crate::prim_store::{ScrollNodeAndClipChain, PictureIndex}; use crate::prim_store::{InternablePrimitive, SegmentInstanceIndex}; use crate::prim_store::{register_prim_chase_id, get_line_decoration_sizes}; +use crate::prim_store::backdrop::Backdrop; use crate::prim_store::borders::{ImageBorder, NormalBorderPrim}; use crate::prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams}; use crate::prim_store::image::{Image, YuvImage}; use crate::prim_store::line_dec::{LineDecoration, LineDecorationCacheKey}; use crate::prim_store::picture::{Picture, PictureCompositeKey, PictureKey}; use crate::prim_store::text_run::TextRun; use crate::render_backend::{DocumentView}; use crate::resource_cache::{FontInstanceMap, ImageRequest}; @@ -326,16 +327,17 @@ impl<'a> DisplayListFlattener<'a> { root_pipeline.pipeline_id, CompositeOps::default(), TransformStyle::Flat, /* is_backface_visible = */ true, /* create_tile_cache = */ false, ROOT_SPATIAL_NODE_INDEX, ClipChainId::NONE, RasterSpace::Screen, + /* is_backdrop_root = */ true, ); flattener.flatten_items( &mut root_pipeline.display_list.iter(), root_pipeline.pipeline_id, true, ); @@ -803,19 +805,19 @@ impl<'a> DisplayListFlattener<'a> { // Avoid doing unnecessary work for empty stacking contexts. if traversal.current_stacking_context_empty() { traversal.skip_current_stacking_context(); return; } let composition_operations = { CompositeOps::new( - stacking_context.filter_ops_for_compositing(filters), - stacking_context.filter_datas_for_compositing(filter_datas), - stacking_context.filter_primitives_for_compositing(filter_primitives), + filter_ops_for_compositing(filters), + filter_datas_for_compositing(filter_datas), + filter_primitives_for_compositing(filter_primitives), stacking_context.mix_blend_mode_for_compositing(), ) }; let clip_chain_id = match stacking_context.clip_id { Some(clip_id) => self.id_to_index_mapper.get_clip_chain_id(clip_id), None => ClipChainId::NONE, }; @@ -824,16 +826,17 @@ impl<'a> DisplayListFlattener<'a> { pipeline_id, composition_operations, stacking_context.transform_style, is_backface_visible, stacking_context.cache_tiles, spatial_node_index, clip_chain_id, stacking_context.raster_space, + stacking_context.is_backdrop_root, ); if cfg!(debug_assertions) && apply_pipeline_clip && clip_chain_id != ClipChainId::NONE { // This is the rootmost stacking context in this pipeline that has // a clip set. Check that the clip chain includes the pipeline clip // as well, because this where we recurse with `apply_pipeline_clip` // set to false and stop explicitly adding the pipeline clip to // individual items. @@ -1307,17 +1310,32 @@ impl<'a> DisplayListFlattener<'a> { DisplayItem::StickyFrame(ref info) => { let parent_space = self.get_space(&info.parent_spatial_id); self.flatten_sticky_frame( info, parent_space, ); } DisplayItem::BackdropFilter(ref info) => { - unimplemented!(); + let (layout, clip_and_scroll) = self.process_common_properties( + &info.common, + apply_pipeline_clip, + ); + + let filters = filter_ops_for_compositing(item.filters()); + let filter_datas = filter_datas_for_compositing(item.filter_datas()); + let filter_primitives = filter_primitives_for_compositing(item.filter_primitives()); + + self.add_backdrop_filter( + clip_and_scroll, + &layout, + filters, + filter_datas, + filter_primitives, + ); } // Do nothing; these are dummy items for the display list parser DisplayItem::SetGradientStops | DisplayItem::SetFilterOps | DisplayItem::SetFilterData | DisplayItem::SetFilterPrimitives => {} @@ -1569,16 +1587,17 @@ impl<'a> DisplayListFlattener<'a> { pipeline_id: PipelineId, composite_ops: CompositeOps, transform_style: TransformStyle, is_backface_visible: bool, create_tile_cache: bool, spatial_node_index: SpatialNodeIndex, clip_chain_id: ClipChainId, requested_raster_space: RasterSpace, + is_backdrop_root: bool, ) { // Check if this stacking context is the root of a pipeline, and the caller // has requested it as an output frame. let is_pipeline_root = self.sc_stack.last().map_or(true, |sc| sc.pipeline_id != pipeline_id); let frame_output_pipeline_id = if is_pipeline_root && self.output_pipelines.contains(&pipeline_id) { Some(pipeline_id) } else { @@ -1592,26 +1611,35 @@ impl<'a> DisplayListFlattener<'a> { // we don't expect any nested tile-cache-enabled stacking contexts debug_assert!(!self.sc_stack.iter().any(|sc| sc.create_tile_cache)); } // Get the transform-style of the parent stacking context, // which determines if we *might* need to draw this on // an intermediate surface for plane splitting purposes. let (parent_is_3d, extra_3d_instance) = match self.sc_stack.last_mut() { - Some(sc) => { + Some(ref mut sc) if sc.is_3d() => { + let flat_items_context_3d = match sc.context_3d { + Picture3DContext::In { ancestor_index, .. } => Picture3DContext::In { + root_data: None, + ancestor_index, + }, + Picture3DContext::Out => panic!("Unexpected out of 3D context"), + }; // Cut the sequence of flat children before starting a child stacking context, // so that the relative order between them and our current SC is preserved. - let extra_instance = sc.cut_flat_item_sequence( + let extra_instance = sc.cut_item_sequence( &mut self.prim_store, &mut self.interners, + Some(PictureCompositeMode::Blit(BlitReason::PRESERVE3D)), + flat_items_context_3d, ); - (sc.is_3d(), extra_instance) + (true, extra_instance.map(|(_, instance)| instance)) }, - None => (false, None), + _ => (false, None), }; if let Some(instance) = extra_3d_instance { self.add_primitive_instance_to_3d_root(instance); } // If this is preserve-3d *or* the parent is, then this stacking // context is participating in the 3d rendering context. In that @@ -1675,16 +1703,17 @@ impl<'a> DisplayListFlattener<'a> { spatial_node_index, clip_chain_id, frame_output_pipeline_id, composite_ops, blit_reason, transform_style, context_3d, create_tile_cache, + is_backdrop_root, }); } pub fn pop_stacking_context(&mut self) { let mut stacking_context = self.sc_stack.pop().unwrap(); // If we encounter a stacking context that is effectively a no-op, then instead // of creating a picture, just append the primitive list to the parent stacking @@ -1905,155 +1934,30 @@ impl<'a> DisplayListFlattener<'a> { PictureCompositeKey::Identity, stacking_context.is_backface_visible, ClipChainId::NONE, stacking_context.spatial_node_index, &mut self.interners, ); } - // For each filter, create a new image with that composite mode. - let mut current_filter_data_index = 0; - for filter in &mut stacking_context.composite_ops.filters { - filter.sanitize(); - - let composite_mode = Some(match *filter { - Filter::ComponentTransfer => { - let filter_data = - &stacking_context.composite_ops.filter_datas[current_filter_data_index]; - let filter_data = filter_data.sanitize(); - current_filter_data_index = current_filter_data_index + 1; - if filter_data.is_identity() { - continue - } else { - let filter_data_key = SFilterDataKey { - data: - SFilterData { - r_func: SFilterDataComponent::from_functype_values( - filter_data.func_r_type, &filter_data.r_values), - g_func: SFilterDataComponent::from_functype_values( - filter_data.func_g_type, &filter_data.g_values), - b_func: SFilterDataComponent::from_functype_values( - filter_data.func_b_type, &filter_data.b_values), - a_func: SFilterDataComponent::from_functype_values( - filter_data.func_a_type, &filter_data.a_values), - }, - }; - - let handle = self.interners - .filter_data - .intern(&filter_data_key, || ()); - PictureCompositeMode::ComponentTransferFilter(handle) - } - } - _ => PictureCompositeMode::Filter(filter.clone()), - }); - - let filter_pic_index = PictureIndex(self.prim_store.pictures - .alloc() - .init(PicturePrimitive::new_image( - composite_mode.clone(), - Picture3DContext::Out, - None, - true, - stacking_context.is_backface_visible, - stacking_context.requested_raster_space, - PrimitiveList::new( - vec![cur_instance.clone()], - &self.interners, - ), - stacking_context.spatial_node_index, - None, - PictureOptions::default(), - )) - ); - - current_pic_index = filter_pic_index; - cur_instance = create_prim_instance( - current_pic_index, - composite_mode.into(), - stacking_context.is_backface_visible, - ClipChainId::NONE, - stacking_context.spatial_node_index, - &mut self.interners, - ); - - if cur_instance.is_chased() { - println!("\tis a composite picture for a stacking context with {:?}", filter); - } - - // Run the optimize pass on this picture, to see if we can - // collapse opacity and avoid drawing to an off-screen surface. - self.prim_store.optimize_picture_if_possible(current_pic_index); - } - - if !stacking_context.composite_ops.filter_primitives.is_empty() { - let filter_datas = stacking_context.composite_ops.filter_datas.iter() - .map(|filter_data| filter_data.sanitize()) - .map(|filter_data| { - SFilterData { - r_func: SFilterDataComponent::from_functype_values( - filter_data.func_r_type, &filter_data.r_values), - g_func: SFilterDataComponent::from_functype_values( - filter_data.func_g_type, &filter_data.g_values), - b_func: SFilterDataComponent::from_functype_values( - filter_data.func_b_type, &filter_data.b_values), - a_func: SFilterDataComponent::from_functype_values( - filter_data.func_a_type, &filter_data.a_values), - } - }) - .collect(); - - // Sanitize filter inputs - for primitive in &mut stacking_context.composite_ops.filter_primitives { - primitive.sanitize(); - } - - let composite_mode = PictureCompositeMode::SvgFilter( - stacking_context.composite_ops.filter_primitives, - filter_datas, - ); - - let filter_pic_index = PictureIndex(self.prim_store.pictures - .alloc() - .init(PicturePrimitive::new_image( - Some(composite_mode.clone()), - Picture3DContext::Out, - None, - true, - stacking_context.is_backface_visible, - stacking_context.requested_raster_space, - PrimitiveList::new( - vec![cur_instance.clone()], - &self.interners, - ), - stacking_context.spatial_node_index, - None, - PictureOptions::default(), - )) - ); - - current_pic_index = filter_pic_index; - cur_instance = create_prim_instance( - current_pic_index, - Some(composite_mode).into(), - stacking_context.is_backface_visible, - ClipChainId::NONE, - stacking_context.spatial_node_index, - &mut self.interners, - ); - - if cur_instance.is_chased() { - println!("\tis a composite picture for a stacking context with an SVG filter"); - } - - // Run the optimize pass on this picture, to see if we can - // collapse opacity and avoid drawing to an off-screen surface. - self.prim_store.optimize_picture_if_possible(current_pic_index); - } + let (filtered_pic_index, filtered_instance) = self.wrap_prim_with_filters( + cur_instance, + current_pic_index, + stacking_context.composite_ops.filters, + stacking_context.composite_ops.filter_primitives, + stacking_context.composite_ops.filter_datas, + stacking_context.is_backface_visible, + stacking_context.requested_raster_space, + stacking_context.spatial_node_index, + true, + ); + + current_pic_index = filtered_pic_index; + cur_instance = filtered_instance; // Same for mix-blend-mode, except we can skip if this primitive is the first in the parent // stacking context. // From https://drafts.fxtf.org/compositing-1/#generalformula, the formula for blending is: // Cs = (1 - ab) x Cs + ab x Blend(Cb, Cs) // where // Cs = Source color // ab = Backdrop alpha @@ -3056,16 +2960,323 @@ impl<'a> DisplayListFlattener<'a> { prims.push(instance); break; } Picture3DContext::In { .. } => {} Picture3DContext::Out => panic!("Unable to find 3D root"), } } } + + pub fn add_backdrop_filter( + &mut self, + clip_and_scroll: ScrollNodeAndClipChain, + info: &LayoutPrimitiveInfo, + filters: Vec<Filter>, + filter_datas: Vec<FilterData>, + filter_primitives: Vec<FilterPrimitive>, + ) { + let mut backdrop_pic_index = match self.cut_backdrop_picture() { + // Backdrop contains no content, so no need to add backdrop-filter + None => return, + Some(backdrop_pic_index) => backdrop_pic_index, + }; + + let backdrop_spatial_node_index = self.prim_store.pictures[backdrop_pic_index.0].spatial_node_index; + let requested_raster_space = self.sc_stack.last().expect("no active stacking context").requested_raster_space; + + let mut instance = self.create_primitive( + info, + // TODO(cbrewster): This is a bit of a hack to help figure out the correct sizing of the backdrop + // region. By makings sure to include this, the clip chain instance computes the correct clip rect, + // but we don't actually apply the filtered backdrop clip yet (this is done to the last instance in + // the filter chain below). + clip_and_scroll.clip_chain_id, + backdrop_spatial_node_index, + Backdrop { + pic_index: backdrop_pic_index, + spatial_node_index: clip_and_scroll.spatial_node_index, + border_rect: info.rect.into(), + }, + ); + + // We will append the filtered backdrop to the backdrop root, but we need to + // make sure all clips between the current stacking context and backdrop root + // are taken into account. So we wrap the backdrop filter instance with a picture with + // a clip for each stacking context. + for stacking_context in self.sc_stack.iter().rev().take_while(|sc| !sc.is_backdrop_root) { + let clip_chain_id = stacking_context.clip_chain_id; + let is_backface_visible = stacking_context.is_backface_visible; + let composite_mode = None; + + backdrop_pic_index = PictureIndex(self.prim_store.pictures + .alloc() + .init(PicturePrimitive::new_image( + composite_mode.clone(), + Picture3DContext::Out, + None, + true, + is_backface_visible, + requested_raster_space, + PrimitiveList::new( + vec![instance], + &mut self.interners, + ), + backdrop_spatial_node_index, + None, + PictureOptions { + inflate_if_required: false, + }, + )) + ); + + instance = create_prim_instance( + backdrop_pic_index, + composite_mode.into(), + is_backface_visible, + clip_chain_id, + backdrop_spatial_node_index, + &mut self.interners, + ); + } + + let (mut filtered_pic_index, mut filtered_instance) = self.wrap_prim_with_filters( + instance, + backdrop_pic_index, + filters, + filter_primitives, + filter_datas, + info.is_backface_visible, + requested_raster_space, + backdrop_spatial_node_index, + false, + ); + + // Apply filters from all stacking contexts up to, but not including the backdrop root. + // Gecko pushes separate stacking contexts for filters and opacity, + // so we must iterate through multiple stacking contexts to find all effects + // that need to be applied to the filtered backdrop. + let backdrop_root_pos = self.sc_stack.iter().rposition(|sc| sc.is_backdrop_root).expect("no backdrop root?"); + for i in ((backdrop_root_pos + 1)..self.sc_stack.len()).rev() { + let stacking_context = &self.sc_stack[i]; + let filters = stacking_context.composite_ops.filters.clone(); + let filter_primitives = stacking_context.composite_ops.filter_primitives.clone(); + let filter_datas = stacking_context.composite_ops.filter_datas.clone(); + + let (pic_index, instance) = self.wrap_prim_with_filters( + filtered_instance, + filtered_pic_index, + filters, + filter_primitives, + filter_datas, + info.is_backface_visible, + requested_raster_space, + backdrop_spatial_node_index, + false, + ); + + filtered_instance = instance; + filtered_pic_index = pic_index; + } + + filtered_instance.clip_chain_id = clip_and_scroll.clip_chain_id; + + self.sc_stack.iter_mut().rev().find(|sc| sc.is_backdrop_root).unwrap().primitives.push(filtered_instance); + } + + pub fn cut_backdrop_picture(&mut self) -> Option<PictureIndex> { + let mut flattened_items = None; + let mut backdrop_root = None; + for sc in self.sc_stack.iter_mut().rev() { + // Add child contents to parent stacking context + if let Some((_, flattened_instance)) = flattened_items.take() { + sc.primitives.push(flattened_instance); + } + flattened_items = sc.cut_item_sequence( + &mut self.prim_store, + &mut self.interners, + None, + Picture3DContext::Out, + ); + if sc.is_backdrop_root { + backdrop_root = Some(sc); + break; + } + } + + let (pic_index, instance) = flattened_items?; + self.prim_store.pictures[pic_index.0].requested_composite_mode = Some(PictureCompositeMode::Blit(BlitReason::BACKDROP)); + backdrop_root.expect("no backdrop root found").primitives.push(instance); + + Some(pic_index) + } + + fn wrap_prim_with_filters( + &mut self, + mut cur_instance: PrimitiveInstance, + mut current_pic_index: PictureIndex, + mut filter_ops: Vec<Filter>, + mut filter_primitives: Vec<FilterPrimitive>, + filter_datas: Vec<FilterData>, + is_backface_visible: bool, + requested_raster_space: RasterSpace, + spatial_node_index: SpatialNodeIndex, + inflate_if_required: bool, + ) -> (PictureIndex, PrimitiveInstance) { + // TODO(cbrewster): Currently CSS and SVG filters live side by side in WebRender, but unexpected results will + // happen if they are used simulataneously. Gecko only provides either filter ops or filter primitives. + // At some point, these two should be combined and CSS filters should be expressed in terms of SVG filters. + assert!(filter_ops.is_empty() || filter_primitives.is_empty(), + "Filter ops and filter primitives are not allowed on the same stacking context."); + + // For each filter, create a new image with that composite mode. + let mut current_filter_data_index = 0; + for filter in &mut filter_ops { + filter.sanitize(); + + let composite_mode = Some(match *filter { + Filter::ComponentTransfer => { + let filter_data = + &filter_datas[current_filter_data_index]; + let filter_data = filter_data.sanitize(); + current_filter_data_index = current_filter_data_index + 1; + if filter_data.is_identity() { + continue + } else { + let filter_data_key = SFilterDataKey { + data: + SFilterData { + r_func: SFilterDataComponent::from_functype_values( + filter_data.func_r_type, &filter_data.r_values), + g_func: SFilterDataComponent::from_functype_values( + filter_data.func_g_type, &filter_data.g_values), + b_func: SFilterDataComponent::from_functype_values( + filter_data.func_b_type, &filter_data.b_values), + a_func: SFilterDataComponent::from_functype_values( + filter_data.func_a_type, &filter_data.a_values), + }, + }; + + let handle = self.interners + .filter_data + .intern(&filter_data_key, || ()); + PictureCompositeMode::ComponentTransferFilter(handle) + } + } + _ => PictureCompositeMode::Filter(filter.clone()), + }); + + let filter_pic_index = PictureIndex(self.prim_store.pictures + .alloc() + .init(PicturePrimitive::new_image( + composite_mode.clone(), + Picture3DContext::Out, + None, + true, + is_backface_visible, + requested_raster_space, + PrimitiveList::new( + vec![cur_instance.clone()], + &mut self.interners, + ), + spatial_node_index, + None, + PictureOptions { + inflate_if_required, + }, + )) + ); + + current_pic_index = filter_pic_index; + cur_instance = create_prim_instance( + current_pic_index, + composite_mode.into(), + is_backface_visible, + ClipChainId::NONE, + spatial_node_index, + &mut self.interners, + ); + + if cur_instance.is_chased() { + println!("\tis a composite picture for a stacking context with {:?}", filter); + } + + // Run the optimize pass on this picture, to see if we can + // collapse opacity and avoid drawing to an off-screen surface. + self.prim_store.optimize_picture_if_possible(current_pic_index); + } + + if !filter_primitives.is_empty() { + let filter_datas = filter_datas.iter() + .map(|filter_data| filter_data.sanitize()) + .map(|filter_data| { + SFilterData { + r_func: SFilterDataComponent::from_functype_values( + filter_data.func_r_type, &filter_data.r_values), + g_func: SFilterDataComponent::from_functype_values( + filter_data.func_g_type, &filter_data.g_values), + b_func: SFilterDataComponent::from_functype_values( + filter_data.func_b_type, &filter_data.b_values), + a_func: SFilterDataComponent::from_functype_values( + filter_data.func_a_type, &filter_data.a_values), + } + }) + .collect(); + + // Sanitize filter inputs + for primitive in &mut filter_primitives { + primitive.sanitize(); + } + + let composite_mode = PictureCompositeMode::SvgFilter( + filter_primitives, + filter_datas, + ); + + let filter_pic_index = PictureIndex(self.prim_store.pictures + .alloc() + .init(PicturePrimitive::new_image( + Some(composite_mode.clone()), + Picture3DContext::Out, + None, + true, + is_backface_visible, + requested_raster_space, + PrimitiveList::new( + vec![cur_instance.clone()], + &mut self.interners, + ), + spatial_node_index, + None, + PictureOptions { + inflate_if_required, + }, + )) + ); + + current_pic_index = filter_pic_index; + cur_instance = create_prim_instance( + current_pic_index, + Some(composite_mode).into(), + is_backface_visible, + ClipChainId::NONE, + spatial_node_index, + &mut self.interners, + ); + + if cur_instance.is_chased() { + println!("\tis a composite picture for a stacking context with an SVG filter"); + } + + // Run the optimize pass on this picture, to see if we can + // collapse opacity and avoid drawing to an off-screen surface. + self.prim_store.optimize_picture_if_possible(current_pic_index); + } + (current_pic_index, cur_instance) + } } pub trait CreateShadow { fn create_shadow(&self, shadow: &Shadow) -> Self; } pub trait IsVisible { @@ -3110,16 +3321,19 @@ struct FlattenedStackingContext { /// CSS transform-style property. transform_style: TransformStyle, /// Defines the relationship to a preserve-3D hiearachy. context_3d: Picture3DContext<PrimitiveInstance>, /// If true, create a tile cache for this stacking context. create_tile_cache: bool, + + /// True if this stacking context is a backdrop root. + is_backdrop_root: bool, } impl FlattenedStackingContext { /// Return true if the stacking context has a valid preserve-3d property pub fn is_3d(&self) -> bool { self.transform_style == TransformStyle::Preserve3D && self.composite_ops.is_empty() } @@ -3169,38 +3383,32 @@ impl FlattenedStackingContext { if self.create_tile_cache { return false; } // It is redundant! true } - /// For a Preserve3D context, cut the sequence of the immediate flat children - /// recorded so far and generate a picture from them. - pub fn cut_flat_item_sequence( + /// Cut the sequence of the immediate children recorded so far and generate a picture from them. + pub fn cut_item_sequence( &mut self, prim_store: &mut PrimitiveStore, interners: &mut Interners, - ) -> Option<PrimitiveInstance> { - if !self.is_3d() || self.primitives.is_empty() { + composite_mode: Option<PictureCompositeMode>, + flat_items_context_3d: Picture3DContext<OrderedPictureChild>, + ) -> Option<(PictureIndex, PrimitiveInstance)> { + if self.primitives.is_empty() { return None } - let flat_items_context_3d = match self.context_3d { - Picture3DContext::In { ancestor_index, .. } => Picture3DContext::In { - root_data: None, - ancestor_index, - }, - Picture3DContext::Out => panic!("Unexpected out of 3D context"), - }; let pic_index = PictureIndex(prim_store.pictures .alloc() .init(PicturePrimitive::new_image( - Some(PictureCompositeMode::Blit(BlitReason::PRESERVE3D)), + composite_mode.clone(), flat_items_context_3d, None, true, self.is_backface_visible, self.requested_raster_space, PrimitiveList::new( mem::replace(&mut self.primitives, Vec::new()), interners, @@ -3208,24 +3416,24 @@ impl FlattenedStackingContext { self.spatial_node_index, None, PictureOptions::default(), )) ); let prim_instance = create_prim_instance( pic_index, - PictureCompositeKey::Identity, + composite_mode.into(), self.is_backface_visible, self.clip_chain_id, self.spatial_node_index, interners, ); - Some(prim_instance) + Some((pic_index, prim_instance)) } } /// A primitive that is added while a shadow context is /// active is stored as a pending primitive and only /// added to pictures during pop_all_shadows. pub struct PendingPrimitive<T> { clip_and_scroll: ScrollNodeAndClipChain, @@ -3325,8 +3533,52 @@ fn create_clip_prim_instance( PrimitiveInstance::new( LayoutPoint::zero(), LayoutRect::max_rect(), kind, clip_chain_id, spatial_node_index, ) } + + +fn filter_ops_for_compositing( + input_filters: ItemRange<FilterOp>, +) -> Vec<Filter> { + // TODO(gw): Now that we resolve these later on, + // we could probably make it a bit + // more efficient than cloning these here. + input_filters.iter().map(|filter| filter.into()).collect() +} + +fn filter_datas_for_compositing( + input_filter_datas: &[TempFilterData], +) -> Vec<FilterData> { + // TODO(gw): Now that we resolve these later on, + // we could probably make it a bit + // more efficient than cloning these here. + let mut filter_datas = vec![]; + for temp_filter_data in input_filter_datas { + let func_types : Vec<ComponentTransferFuncType> = temp_filter_data.func_types.iter().collect(); + debug_assert!(func_types.len() == 4); + filter_datas.push( FilterData { + func_r_type: func_types[0], + r_values: temp_filter_data.r_values.iter().collect(), + func_g_type: func_types[1], + g_values: temp_filter_data.g_values.iter().collect(), + func_b_type: func_types[2], + b_values: temp_filter_data.b_values.iter().collect(), + func_a_type: func_types[3], + a_values: temp_filter_data.a_values.iter().collect(), + }); + } + filter_datas +} + +fn filter_primitives_for_compositing( + input_filter_primitives: ItemRange<FilterPrimitive>, +) -> Vec<FilterPrimitive> { + // Resolve these in the flattener? + // TODO(gw): Now that we resolve these later on, + // we could probably make it a bit + // more efficient than cloning these here. + input_filter_primitives.iter().map(|primitive| primitive.into()).collect() +}
--- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -1560,17 +1560,18 @@ impl TileCacheInstance { } } } } PrimitiveInstanceKind::LineDecoration { .. } | PrimitiveInstanceKind::Clear { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::LinearGradient { .. } | - PrimitiveInstanceKind::RadialGradient { .. } => { + PrimitiveInstanceKind::RadialGradient { .. } | + PrimitiveInstanceKind::Backdrop { .. } => { // These don't contribute dependencies } }; // Normalize the tile coordinates before adding to tile dependencies. // For each affected tile, mark any of the primitive dependencies. for y in p0.y .. p1.y { for x in p0.x .. p1.x { @@ -1886,16 +1887,18 @@ bitflags! { #[cfg_attr(feature = "capture", derive(Serialize))] pub struct BlitReason: u32 { /// Mix-blend-mode on a child that requires isolation. const ISOLATE = 1; /// Clip node that _might_ require a surface. const CLIP = 2; /// Preserve-3D requires a surface for plane-splitting. const PRESERVE3D = 4; + /// A backdrop that is reused which requires a surface. + const BACKDROP = 8; } } /// Specifies how this Picture should be composited /// onto the target it belongs to. #[allow(dead_code)] #[derive(Debug, Clone)] #[cfg_attr(feature = "capture", derive(Serialize))] @@ -2157,16 +2160,20 @@ impl PrimitiveList { PrimitiveInstanceKind::TextRun { data_handle, .. } => { let data = &interners.text_run[data_handle]; (data.is_backface_visible, data.prim_size) } PrimitiveInstanceKind::YuvImage { data_handle, .. } => { let data = &interners.yuv_image[data_handle]; (data.is_backface_visible, data.prim_size) } + PrimitiveInstanceKind::Backdrop { data_handle, .. } => { + let data = &interners.backdrop[data_handle]; + (data.is_backface_visible, data.prim_size) + } PrimitiveInstanceKind::PushClipChain | PrimitiveInstanceKind::PopClipChain => { (true, LayoutSize::zero()) } }; // Get the key for the cluster that this primitive should // belong to. @@ -2298,17 +2305,17 @@ pub struct PicturePrimitive { /// transform animation and/or scrolling. pub segments_are_valid: bool, /// If Some(..) the tile cache that is associated with this picture. #[cfg_attr(feature = "capture", serde(skip))] //TODO pub tile_cache: Option<Box<TileCacheInstance>>, /// The config options for this picture. - options: PictureOptions, + pub options: PictureOptions, } impl PicturePrimitive { pub fn print<T: PrintTreePrinter>( &self, pictures: &[Self], self_index: PictureIndex, pt: &mut T, @@ -2551,49 +2558,55 @@ impl PicturePrimitive { let dep_info = match raster_config.composite_mode { PictureCompositeMode::Filter(Filter::Blur(blur_radius)) => { let blur_std_deviation = blur_radius * device_pixel_scale.0; let scale_factors = scale_factors(&transform); let blur_std_deviation = DeviceSize::new( blur_std_deviation * scale_factors.0, blur_std_deviation * scale_factors.1 ); - let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor; - let inflation_factor = (inflation_factor * device_pixel_scale.0).ceil(); - - // The clipped field is the part of the picture that is visible - // on screen. The unclipped field is the screen-space rect of - // the complete picture, if no screen / clip-chain was applied - // (this includes the extra space for blur region). To ensure - // that we draw a large enough part of the picture to get correct - // blur results, inflate that clipped area by the blur range, and - // then intersect with the total screen rect, to minimize the - // allocation size. - // We cast clipped to f32 instead of casting unclipped to i32 - // because unclipped can overflow an i32. - let device_rect = clipped.to_f32() - .inflate(inflation_factor, inflation_factor) - .intersection(&unclipped) - .unwrap(); - - let mut device_rect = match device_rect.try_cast::<i32>() { - Some(rect) => rect, - None => { - return None - } + let device_rect = if self.options.inflate_if_required { + let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor; + let inflation_factor = (inflation_factor * device_pixel_scale.0).ceil(); + + // The clipped field is the part of the picture that is visible + // on screen. The unclipped field is the screen-space rect of + // the complete picture, if no screen / clip-chain was applied + // (this includes the extra space for blur region). To ensure + // that we draw a large enough part of the picture to get correct + // blur results, inflate that clipped area by the blur range, and + // then intersect with the total screen rect, to minimize the + // allocation size. + // We cast clipped to f32 instead of casting unclipped to i32 + // because unclipped can overflow an i32. + let device_rect = clipped.to_f32() + .inflate(inflation_factor, inflation_factor) + .intersection(&unclipped) + .unwrap(); + + let mut device_rect = match device_rect.try_cast::<i32>() { + Some(rect) => rect, + None => { + return None + } + }; + + // Adjust the size to avoid introducing sampling errors during the down-scaling passes. + // what would be even better is to rasterize the picture at the down-scaled size + // directly. + device_rect.size = RenderTask::adjusted_blur_source_size( + device_rect.size, + blur_std_deviation, + ); + + device_rect + } else { + clipped }; - // Adjust the size to avoid introducing sampling errors during the down-scaling passes. - // what would be even better is to rasterize the picture at the down-scaled size - // directly. - device_rect.size = RenderTask::adjusted_blur_source_size( - device_rect.size, - blur_std_deviation, - ); - let uv_rect_kind = calculate_uv_rect_kind( &pic_rect, &transform, &device_rect, device_pixel_scale, true, ); @@ -3320,17 +3333,19 @@ impl PicturePrimitive { // If this picture establishes a surface, then map the surface bounding // rect into the parent surface coordinate space, and propagate that up // to the parent. if let Some(ref mut raster_config) = self.raster_config { let surface = state.current_surface_mut(); // Inflate the local bounding rect if required by the filter effect. // This inflaction factor is to be applied to the surface itself. - surface.rect = raster_config.composite_mode.inflate_picture_rect(surface.rect, surface.inflation_factor); + if self.options.inflate_if_required { + surface.rect = raster_config.composite_mode.inflate_picture_rect(surface.rect, surface.inflation_factor); + } let mut surface_rect = surface.rect * Scale::new(1.0); // Pop this surface from the stack let surface_index = state.pop_surface(); debug_assert_eq!(surface_index, raster_config.surface_index); // Snapping may change the local rect slightly, and as such should just be
new file mode 100644 --- /dev/null +++ b/gfx/wr/webrender/src/prim_store/backdrop.rs @@ -0,0 +1,105 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use api::units::*; +use crate::clip_scroll_tree::SpatialNodeIndex; +use crate::intern::{Internable, InternDebug, Handle as InternHandle}; +use crate::internal_types::LayoutPrimitiveInfo; +use crate::prim_store::{ + InternablePrimitive, PictureIndex, PrimitiveInstanceKind, PrimKey, PrimKeyCommonData, PrimTemplate, + PrimTemplateCommonData, PrimitiveStore, PrimitiveSceneData, RectangleKey, +}; + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Debug, Clone, Eq, PartialEq, MallocSizeOf, Hash)] +pub struct Backdrop { + pub pic_index: PictureIndex, + pub spatial_node_index: SpatialNodeIndex, + pub border_rect: RectangleKey, +} + +impl From<Backdrop> for BackdropData { + fn from(backdrop: Backdrop) -> Self { + BackdropData { + pic_index: backdrop.pic_index, + spatial_node_index: backdrop.spatial_node_index, + border_rect: backdrop.border_rect.into(), + } + } +} + +pub type BackdropKey = PrimKey<Backdrop>; + +impl BackdropKey { + pub fn new( + is_backface_visible: bool, + prim_size: LayoutSize, + backdrop: Backdrop, + ) -> Self { + BackdropKey { + common: PrimKeyCommonData { + is_backface_visible, + prim_size: prim_size.into(), + }, + kind: backdrop, + } + } +} + +impl InternDebug for BackdropKey {} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Debug, MallocSizeOf)] +pub struct BackdropData { + pub pic_index: PictureIndex, + pub spatial_node_index: SpatialNodeIndex, + pub border_rect: LayoutRect, +} + +pub type BackdropTemplate = PrimTemplate<BackdropData>; + +impl From<BackdropKey> for BackdropTemplate { + fn from(backdrop: BackdropKey) -> Self { + let common = PrimTemplateCommonData::with_key_common(backdrop.common); + + BackdropTemplate { + common, + kind: backdrop.kind.into(), + } + } +} + +pub type BackdropDataHandle = InternHandle<Backdrop>; + +impl Internable for Backdrop { + type Key = BackdropKey; + type StoreData = BackdropTemplate; + type InternData = PrimitiveSceneData; +} + +impl InternablePrimitive for Backdrop { + fn into_key( + self, + info: &LayoutPrimitiveInfo, + ) -> BackdropKey { + BackdropKey::new( + info.is_backface_visible, + info.rect.size, + self + ) + } + + fn make_instance_kind( + _key: BackdropKey, + data_handle: BackdropDataHandle, + _prim_store: &mut PrimitiveStore, + _reference_frame_relative_offset: LayoutVector2D, + ) -> PrimitiveInstanceKind { + PrimitiveInstanceKind::Backdrop { + data_handle, + } + } +}
--- a/gfx/wr/webrender/src/prim_store/interned.rs +++ b/gfx/wr/webrender/src/prim_store/interned.rs @@ -1,12 +1,14 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // list of all interned primitives to match enumerate_interners! +pub use crate::prim_store::backdrop::Backdrop; pub use crate::prim_store::borders::{ImageBorder, NormalBorderPrim}; pub use crate::prim_store::image::{Image, YuvImage}; pub use crate::prim_store::line_dec::{LineDecoration}; pub use crate::prim_store::gradient::{LinearGradient, RadialGradient}; pub use crate::prim_store::picture::Picture; pub use crate::prim_store::text_run::TextRun; +
--- a/gfx/wr/webrender/src/prim_store/mod.rs +++ b/gfx/wr/webrender/src/prim_store/mod.rs @@ -23,16 +23,17 @@ use crate::frame_builder::{FrameVisibili use crate::glyph_rasterizer::GlyphKey; use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; use crate::gpu_types::{BrushFlags, SnapOffsets}; use crate::image::{Repetition}; use crate::intern; use malloc_size_of::MallocSizeOf; use crate::picture::{PictureCompositeMode, PicturePrimitive}; use crate::picture::{ClusterIndex, PrimitiveList, RecordedDirtyRegion, SurfaceIndex, RetainedTiles, RasterConfig}; +use crate::prim_store::backdrop::BackdropDataHandle; use crate::prim_store::borders::{ImageBorderDataHandle, NormalBorderDataHandle}; use crate::prim_store::gradient::{GRADIENT_FP_STOPS, GradientCacheKey, GradientStopKey}; use crate::prim_store::gradient::{LinearGradientPrimitive, LinearGradientDataHandle, RadialGradientDataHandle}; use crate::prim_store::image::{ImageDataHandle, ImageInstance, VisibleImageTile, YuvImageDataHandle}; use crate::prim_store::line_dec::LineDecorationDataHandle; use crate::prim_store::picture::PictureDataHandle; use crate::prim_store::text_run::{TextRunDataHandle, TextRunPrimitive}; #[cfg(debug_assertions)] @@ -49,16 +50,17 @@ use std::{cmp, fmt, hash, ops, u32, usiz use std::sync::atomic::{AtomicUsize, Ordering}; use crate::storage; use crate::texture_cache::TEXTURE_REGION_DIMENSIONS; use crate::util::{MatrixHelpers, MaxRect, Recycler}; use crate::util::{clamp_to_scale_factor, pack_as_float, project_rect, raster_rect_to_device_pixels}; use crate::internal_types::{LayoutPrimitiveInfo, Filter}; use smallvec::SmallVec; +pub mod backdrop; pub mod borders; pub mod gradient; pub mod image; pub mod line_dec; pub mod picture; pub mod text_run; pub mod interned; @@ -266,17 +268,17 @@ pub struct DeferredResolve { #[derive(Debug, Copy, Clone, PartialEq)] pub struct ClipTaskIndex(pub u16); impl ClipTaskIndex { pub const INVALID: ClipTaskIndex = ClipTaskIndex(0); } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, MallocSizeOf, Ord, PartialOrd)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct PictureIndex(pub usize); impl GpuCacheHandle { pub fn as_int(&self, gpu_cache: &GpuCache) -> i32 { gpu_cache.get_address(self).as_int() } @@ -1320,16 +1322,20 @@ pub enum PrimitiveInstanceKind { data_handle: RadialGradientDataHandle, visible_tiles_range: GradientTileRange, }, /// Clear out a rect, used for special effects. Clear { /// Handle to the common interned data for this primitive. data_handle: PrimitiveDataHandle, }, + /// Render a portion of a specified backdrop. + Backdrop { + data_handle: BackdropDataHandle, + }, /// These are non-visual instances. They are used during the /// visibility pass to allow pushing/popping a clip chain /// without the presence of a stacking context / picture. /// TODO(gw): In some ways this seems like a hack, in some /// ways it seems reasonable. We should discuss /// other potential methods for non-visual items /// without the need for a grouping picture. PushClipChain, @@ -1536,16 +1542,19 @@ impl PrimitiveInstance { data_handle.uid() } PrimitiveInstanceKind::TextRun { data_handle, .. } => { data_handle.uid() } PrimitiveInstanceKind::YuvImage { data_handle, .. } => { data_handle.uid() } + PrimitiveInstanceKind::Backdrop { data_handle, .. } => { + data_handle.uid() + } PrimitiveInstanceKind::PushClipChain | PrimitiveInstanceKind::PopClipChain => { unreachable!(); } } } } @@ -1949,16 +1958,53 @@ impl PrimitiveStore { if prim_instance.is_chased() { if pic.unsnapped_local_rect != pic.snapped_local_rect { println!("\tsnapped from {:?} to {:?}", pic.unsnapped_local_rect, pic.snapped_local_rect); } } (pic.raster_config.is_none(), false, pic.snapped_local_rect, shadow_rect) } + PrimitiveInstanceKind::Backdrop { data_handle } => { + // The actual size and clip rect of this primitive are determined by computing the bounding + // box of the projected rect of the backdrop-filter element onto the backdrop. + let prim_data = &mut frame_state.data_stores.backdrop[data_handle]; + let spatial_node_index = prim_data.kind.spatial_node_index; + + // We cannot use the relative transform between the backdrop and the element because + // that doesn't take into account any projection transforms that both spatial nodes are children of. + // Instead, we first project from the element to the world space and get a flattened 2D bounding rect + // in the screen space, we then map this rect from the world space to the backdrop space to get the + // proper bounding box where the backdrop-filter needs to be processed. + + let prim_to_world_mapper = SpaceMapper::new_with_target( + ROOT_SPATIAL_NODE_INDEX, + spatial_node_index, + LayoutRect::max_rect(), + frame_context.clip_scroll_tree, + ); + + let backdrop_to_world_mapper = SpaceMapper::new_with_target( + ROOT_SPATIAL_NODE_INDEX, + prim_instance.spatial_node_index, + LayoutRect::max_rect(), + frame_context.clip_scroll_tree, + ); + + // First map to the screen and get a flattened rect + let prim_rect = prim_to_world_mapper.map(&prim_data.kind.border_rect).unwrap_or_else(LayoutRect::zero); + // Backwards project the flattened rect onto the backdrop + let prim_rect = backdrop_to_world_mapper.unmap(&prim_rect).unwrap_or_else(LayoutRect::zero); + + prim_instance.prim_origin = prim_rect.origin; + prim_data.common.prim_size = prim_rect.size; + prim_instance.local_clip_rect = prim_rect; + + (false, true, prim_rect, LayoutRect::zero()) + } _ => { let prim_data = &frame_state.data_stores.as_common_data(&prim_instance); let prim_rect = LayoutRect::new( prim_instance.prim_origin, prim_data.prim_size, ); @@ -2183,16 +2229,17 @@ impl PrimitiveStore { PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } => debug_colors::ORANGE, PrimitiveInstanceKind::Rectangle { .. } => ColorF { r: 0.8, g: 0.8, b: 0.8, a: 0.5 }, PrimitiveInstanceKind::YuvImage { .. } => debug_colors::BLUE, PrimitiveInstanceKind::Image { .. } => debug_colors::BLUE, PrimitiveInstanceKind::LinearGradient { .. } => debug_colors::PINK, PrimitiveInstanceKind::RadialGradient { .. } => debug_colors::PINK, PrimitiveInstanceKind::Clear { .. } => debug_colors::CYAN, + PrimitiveInstanceKind::Backdrop { .. } => debug_colors::MEDIUMAQUAMARINE, }; if debug_color.a != 0.0 { let debug_rect = clipped_world_rect * frame_context.global_device_pixel_scale; frame_state.scratch.push_debug_rect(debug_rect, debug_color); } } let vis_index = PrimitiveVisibilityIndex(frame_state.scratch.prim_info.len() as u32); @@ -2236,17 +2283,19 @@ impl PrimitiveStore { // and stretch size. Drop shadow filters also depend on the local rect // size for the extra GPU cache data handle. // TODO(gw): In future, if we support specifying a flag which gets the // stretch size from the segment rect in the shaders, we can // remove this invalidation here completely. if let Some(ref raster_config) = pic.raster_config { // Inflate the local bounding rect if required by the filter effect. // This inflaction factor is to be applied to the surface itself. - surface_rect = raster_config.composite_mode.inflate_picture_rect(surface_rect, surface.inflation_factor); + if pic.options.inflate_if_required { + surface_rect = raster_config.composite_mode.inflate_picture_rect(surface_rect, surface.inflation_factor); + } // Layout space for the picture is picture space from the // perspective of its child primitives. let pic_local_rect = surface_rect * Scale::new(1.0); if pic.snapped_local_rect != pic_local_rect { match raster_config.composite_mode { PictureCompositeMode::Filter(Filter::DropShadows(..)) => { for handle in &pic.extra_gpu_data_handles { @@ -2469,17 +2518,18 @@ impl PrimitiveStore { PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::LinearGradient { .. } | PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::PushClipChain | PrimitiveInstanceKind::PopClipChain | - PrimitiveInstanceKind::LineDecoration { .. } => { + PrimitiveInstanceKind::LineDecoration { .. } | + PrimitiveInstanceKind::Backdrop { .. } => { // These prims don't support opacity collapse } PrimitiveInstanceKind::Picture { pic_index, .. } => { let pic = &self.pictures[pic_index.0]; // If we encounter a picture that is a pass-through // (i.e. no composite mode), then we can recurse into // that to try and find a primitive to collapse to. @@ -2607,17 +2657,18 @@ impl PrimitiveStore { PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::Image { .. } | PrimitiveInstanceKind::LinearGradient { .. } | PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::PushClipChain | PrimitiveInstanceKind::PopClipChain | - PrimitiveInstanceKind::Clear { .. } => { + PrimitiveInstanceKind::Clear { .. } | + PrimitiveInstanceKind::Backdrop { .. } => { None } } }; let is_passthrough = match pic_info { Some((pic_context_for_children, mut pic_state_for_children, mut prim_list)) => { let is_passthrough = pic_context_for_children.is_passthrough; @@ -3284,16 +3335,31 @@ impl PrimitiveStore { ]); } ); } } else { prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID; } } + PrimitiveInstanceKind::Backdrop { data_handle } => { + let backdrop_pic_index = data_stores.backdrop[*data_handle].kind.pic_index; + + // Setup a dependency on the backdrop picture to ensure it is rendered prior to rendering this primitive. + let backdrop_surface_index = self.pictures[backdrop_pic_index.0].raster_config.as_ref().unwrap().surface_index; + if let Some(backdrop_tasks) = frame_state.surfaces[backdrop_surface_index.0].render_tasks { + let picture_task_id = frame_state.surfaces[pic_context.surface_index.0].render_tasks.as_ref().unwrap().port; + frame_state.render_tasks.add_dependency(picture_task_id, backdrop_tasks.root); + } else { + if prim_instance.is_chased() { + println!("\tBackdrop primitive culled because backdrop task was not assigned render tasks"); + } + prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID; + } + } PrimitiveInstanceKind::PushClipChain | PrimitiveInstanceKind::PopClipChain => {} }; } } fn write_segment<F>( segment_instance_index: SegmentInstanceIndex, @@ -3614,17 +3680,18 @@ impl PrimitiveInstance { PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::Clear { .. } | PrimitiveInstanceKind::LinearGradient { .. } | PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::PushClipChain | PrimitiveInstanceKind::PopClipChain | - PrimitiveInstanceKind::LineDecoration { .. } => { + PrimitiveInstanceKind::LineDecoration { .. } | + PrimitiveInstanceKind::Backdrop { .. } => { // These primitives don't support / need segments. return; } }; if *segment_instance_index == SegmentInstanceIndex::INVALID { let mut segments: SmallVec<[BrushSegment; 8]> = SmallVec::new(); @@ -3680,17 +3747,18 @@ impl PrimitiveInstance { unclipped: &DeviceRect, device_pixel_scale: DevicePixelScale, ) -> bool { let segments = match self.kind { PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::Clear { .. } | PrimitiveInstanceKind::PushClipChain | PrimitiveInstanceKind::PopClipChain | - PrimitiveInstanceKind::LineDecoration { .. } => { + PrimitiveInstanceKind::LineDecoration { .. } | + PrimitiveInstanceKind::Backdrop { .. } => { return false; } PrimitiveInstanceKind::Image { image_instance_index, .. } => { let segment_instance_index = prim_store .images[image_instance_index] .segment_instance_index; if segment_instance_index == SegmentInstanceIndex::UNUSED {
--- a/gfx/wr/webrender/src/profiler.rs +++ b/gfx/wr/webrender/src/profiler.rs @@ -575,16 +575,17 @@ impl BackendProfileCounters { linear_grad: ResourceProfileCounter::new("Interned linear gradients"), normal_border: ResourceProfileCounter::new("Interned normal borders"), picture: ResourceProfileCounter::new("Interned pictures"), radial_grad: ResourceProfileCounter::new("Interned radial gradients"), text_run: ResourceProfileCounter::new("Interned text runs"), yuv_image: ResourceProfileCounter::new("Interned YUV images"), clip: ResourceProfileCounter::new("Interned clips"), filter_data: ResourceProfileCounter::new("Interned filter data"), + backdrop: ResourceProfileCounter::new("Interned backdrops"), }, } } pub fn reset(&mut self) { self.total_time.reset(); self.ipc.total_time.reset(); self.ipc.build_time.reset();
--- a/gfx/wr/webrender/src/render_backend.rs +++ b/gfx/wr/webrender/src/render_backend.rs @@ -303,16 +303,20 @@ impl DataStores { PrimitiveInstanceKind::TextRun { data_handle, .. } => { let prim_data = &self.text_run[data_handle]; &prim_data.common } PrimitiveInstanceKind::YuvImage { data_handle, .. } => { let prim_data = &self.yuv_image[data_handle]; &prim_data.common } + PrimitiveInstanceKind::Backdrop { data_handle, .. } => { + let prim_data = &self.backdrop[data_handle]; + &prim_data.common + } PrimitiveInstanceKind::PushClipChain | PrimitiveInstanceKind::PopClipChain => { unreachable!(); } } } }
--- a/gfx/wr/webrender/src/render_task.rs +++ b/gfx/wr/webrender/src/render_task.rs @@ -326,17 +326,30 @@ impl RenderTaskGraph { let child_task_index = self.tasks[task_index].children[nth_child].index as usize; let child_pass_index = task_passes[child_task_index]; if child_pass_index == pass_index - 1 { // This should be the most common case. continue; } - if child_pass_index % 2 != pass_index % 2 { + // TODO: Picture tasks don't support having their dependency tasks redirected. + // Pictures store their respective render task(s) on their SurfaceInfo. + // We cannot blit the picture task here because we would need to update the + // surface's render tasks, but we don't have access to that info here. + // Also a surface may be expecting a picture task and not a blit task, so + // even if we could update the surface's render task(s), it might cause other issues. + // For now we mark the task to be saved rather than trying to redirect to a blit task. + let task_is_picture = if let RenderTaskKind::Picture(..) = self.tasks[task_index].kind { + true + } else { + false + }; + + if child_pass_index % 2 != pass_index % 2 || task_is_picture { // The tasks and its dependency aren't on the same targets, // but the dependency needs to be kept alive. self.tasks[child_task_index].mark_for_saving(); continue; } if let Some(blit_id) = task_redirects[child_task_index] { // We already resolved a similar conflict with a blit task, @@ -2164,17 +2177,18 @@ pub fn dump_render_tasks_as_svg( let task_index = task_id.index as usize; let task = &render_tasks.tasks[task_index]; let rect = layout.push_rectangle(node_height); let tx = rect.x + rect.w / 2.0; let ty = rect.y + 10.0; - let label = text(tx, ty, task.kind.as_str()); + let saved = if task.saved_index.is_some() { " (Saved)" } else { "" }; + let label = text(tx, ty, format!("{}{}", task.kind.as_str(), saved)); let size = text(tx, ty + 12.0, format!("{}", task.location.size())); nodes[task_index] = Some(Node { rect, label, size }); layout.advance(vertical_spacing); } pass_rects.push(layout.total_rectangle());
--- a/gfx/wr/webrender/src/scene.rs +++ b/gfx/wr/webrender/src/scene.rs @@ -1,17 +1,16 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch}; -use api::{FilterOp, TempFilterData, FilterData, FilterPrimitive, ComponentTransferFuncType}; -use api::{PipelineId, PropertyBinding, PropertyBindingId, ItemRange, MixBlendMode, StackingContext}; +use api::{PipelineId, PropertyBinding, PropertyBindingId, MixBlendMode, StackingContext}; use api::units::{LayoutSize, LayoutTransform}; -use crate::internal_types::{FastHashMap, Filter}; +use crate::internal_types::FastHashMap; use std::sync::Arc; /// Stores a map of the animated property bindings for the current display list. These /// can be used to animate the transform and/or opacity of a display list without /// re-submitting the display list itself. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct SceneProperties { @@ -193,80 +192,18 @@ impl Scene { } false } } pub trait StackingContextHelpers { fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>; - fn filter_ops_for_compositing( - &self, - input_filters: ItemRange<FilterOp>, - ) -> Vec<Filter>; - fn filter_datas_for_compositing( - &self, - input_filter_datas: &[TempFilterData], - ) -> Vec<FilterData>; - fn filter_primitives_for_compositing( - &self, - input_filter_primitives: ItemRange<FilterPrimitive>, - ) -> Vec<FilterPrimitive>; } impl StackingContextHelpers for StackingContext { fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> { match self.mix_blend_mode { MixBlendMode::Normal => None, _ => Some(self.mix_blend_mode), } } - - fn filter_ops_for_compositing( - &self, - input_filters: ItemRange<FilterOp>, - ) -> Vec<Filter> { - // TODO(gw): Now that we resolve these later on, - // we could probably make it a bit - // more efficient than cloning these here. - let mut filters = vec![]; - for filter in input_filters { - filters.push(filter.into()); - } - filters - } - - fn filter_datas_for_compositing( - &self, - input_filter_datas: &[TempFilterData], - ) -> Vec<FilterData> { - // TODO(gw): Now that we resolve these later on, - // we could probably make it a bit - // more efficient than cloning these here. - let mut filter_datas = vec![]; - for temp_filter_data in input_filter_datas { - let func_types : Vec<ComponentTransferFuncType> = temp_filter_data.func_types.iter().collect(); - debug_assert!(func_types.len() == 4); - filter_datas.push( FilterData { - func_r_type: func_types[0], - r_values: temp_filter_data.r_values.iter().collect(), - func_g_type: func_types[1], - g_values: temp_filter_data.g_values.iter().collect(), - func_b_type: func_types[2], - b_values: temp_filter_data.b_values.iter().collect(), - func_a_type: func_types[3], - a_values: temp_filter_data.a_values.iter().collect(), - }); - } - filter_datas - } - - fn filter_primitives_for_compositing( - &self, - input_filter_primitives: ItemRange<FilterPrimitive>, - ) -> Vec<FilterPrimitive> { - // Resolve these in the flattener? - // TODO(gw): Now that we resolve these later on, - // we could probably make it a bit - // more efficient than cloning these here. - input_filter_primitives.iter().map(|primitive| primitive.into()).collect() - } }
--- a/gfx/wr/webrender/src/scene_builder.rs +++ b/gfx/wr/webrender/src/scene_builder.rs @@ -13,16 +13,17 @@ use crate::capture::CaptureConfig; use crate::frame_builder::{FrameBuilderConfig, FrameBuilder}; use crate::clip_scroll_tree::ClipScrollTree; use crate::display_list_flattener::DisplayListFlattener; use crate::hit_test::HitTestingSceneStats; use crate::intern::{Internable, Interner, UpdateList}; use crate::internal_types::{FastHashMap, FastHashSet}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use crate::prim_store::PrimitiveStoreStats; +use crate::prim_store::backdrop::Backdrop; use crate::prim_store::borders::{ImageBorder, NormalBorderPrim}; use crate::prim_store::gradient::{LinearGradient, RadialGradient}; use crate::prim_store::image::{Image, YuvImage}; use crate::prim_store::line_dec::LineDecoration; use crate::prim_store::picture::Picture; use crate::prim_store::text_run::TextRun; use crate::resource_cache::{AsyncBlobImageInfo, FontInstanceMap}; use crate::render_backend::DocumentView;
--- a/gfx/wr/webrender/src/tiling.rs +++ b/gfx/wr/webrender/src/tiling.rs @@ -1315,17 +1315,19 @@ impl CompositeOps { filters, filter_datas, filter_primitives, mix_blend_mode, } } pub fn is_empty(&self) -> bool { - self.filters.is_empty() && self.filter_datas.is_empty() && self.mix_blend_mode.is_none() + self.filters.is_empty() && + self.filter_primitives.is_empty() && + self.mix_blend_mode.is_none() } } /// A rendering-oriented representation of the frame built by the render backend /// and presented to the renderer. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct Frame {
--- a/gfx/wr/webrender_api/src/api.rs +++ b/gfx/wr/webrender_api/src/api.rs @@ -881,16 +881,17 @@ macro_rules! enumerate_interners { image: Image, yuv_image: YuvImage, line_decoration: LineDecoration, linear_grad: LinearGradient, radial_grad: RadialGradient, picture: Picture, text_run: TextRun, filter_data: FilterDataIntern, + backdrop: Backdrop, } } } macro_rules! declare_interning_memory_report { ( $( $name:ident: $ty:ident, )+ ) => { #[repr(C)] #[derive(AddAssign, Clone, Debug, Default, Deserialize, Serialize)]
new file mode 100644 --- /dev/null +++ b/gfx/wr/wrench/reftests/filters/backdrop-filter-basic-ref.yaml @@ -0,0 +1,11 @@ + +# Tests that a basic invert backdrop-filter works +--- +root: + items: + - type: stacking-context + bounds: 0 0 0 0 + items: + - type: rect + color: [0, 255, 255, 1] + bounds: 0 0 256 256
new file mode 100644 --- /dev/null +++ b/gfx/wr/wrench/reftests/filters/backdrop-filter-basic.yaml @@ -0,0 +1,21 @@ +# Tests that a basic invert backdrop-filter works +--- +root: + items: + - type: stacking-context + bounds: 0 0 0 0 + items: + - type: rect + color: [255, 0, 0, 1] + bounds: 0 0 256 256 + - type: clip + id: 2 + bounds: 0 0 256 256 + clip-rect: 0 0 256 256 + - type: stacking-context + bounds: 0 0 0 0 + items: + - type: backdrop-filter + bounds: 0 0 256 256 + clip-node: 2 + filters: invert(1)
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..382171c2ae92000af8ba16378ea243b4ac6cc863 GIT binary patch literal 60370 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 LU6lr<XJP*X`ZYS(
new file mode 100644 --- /dev/null +++ b/gfx/wr/wrench/reftests/filters/backdrop-filter-perspective.yaml @@ -0,0 +1,28 @@ +# Tests that backdrop filter works with a perspective transform +--- +root: + items: + - type: stacking-context + bounds: 0 0 0 0 + perspective: 500 + items: + - type: rect + color: [255, 255, 255, 1] + bounds: 0 0 1024 1024 + - image: "firefox.png" + bounds: 0 0 256 256 + - type: stacking-context + bounds: 50 50 0 0 + transform: ["rotate-y(50)", "rotate-z(45)"] + items: + - type: clip + id: 2 + bounds: 0 0 100 100 + clip-rect: 0 0 100 100 + - type: stacking-context + bounds: 0 0 0 0 + items: + - type: backdrop-filter + bounds: 0 0 100 100 + clip-and-scroll: 2 + filters: invert(1)
--- a/gfx/wr/wrench/reftests/filters/reftest.list +++ b/gfx/wr/wrench/reftests/filters/reftest.list @@ -51,8 +51,10 @@ skip_on(android) == svg-filter-blend.yam skip_on(android,device) == svg-filter-color-matrix.yaml filter-color-matrix-ref.yaml # fails on Pixel2 platform(linux,mac) == draw_calls(8) color_targets(8) alpha_targets(0) svg-filter-blur.yaml filter-blur.png # Extra draw call is due to render task graph workaround platform(linux,mac) == svg-filter-drop-shadow.yaml svg-filter-drop-shadow.png == fuzzy(1,10000) svg-srgb-to-linear.yaml srgb-to-linear-ref.yaml platform(linux,mac) == fuzzy(4,28250) svg-filter-drop-shadow-rotate.yaml svg-filter-drop-shadow-rotate-ref.yaml platform(linux,mac) == svg-filter-blur-transforms.yaml svg-filter-blur-transforms.png platform(linux,mac) == svg-filter-drop-shadow-on-viewport-edge.yaml svg-filter-drop-shadow-on-viewport-edge.png platform(linux,mac) == svg-filter-drop-shadow-perspective.yaml svg-filter-drop-shadow-perspective.png +== backdrop-filter-basic.yaml backdrop-filter-basic-ref.yaml +platform(linux,mac) == backdrop-filter-perspective.yaml backdrop-filter-perspective.png