diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 0102404bc8..28c49168dd 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -16,7 +16,7 @@ use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, Trans use internal_types::{FastHashMap, SavedTargetIndex, TextureSource}; use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureSurface}; use prim_store::{BrushKind, BrushPrimitive, DeferredResolve}; -use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveInstanceKind}; +use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveInstanceKind, PrimitiveStore}; use prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity}; use prim_store::{BrushSegment, BorderSource, ClipMaskKind, ClipTaskIndex, PrimitiveDetails}; use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree}; @@ -1261,7 +1261,9 @@ impl AlphaBatchBuilder { } match brush.kind { - BrushKind::Image { alpha_type, request, ref opacity_binding, ref visible_tiles, .. } if !visible_tiles.is_empty() => { + BrushKind::Image { alpha_type, request, opacity_binding_index, ref visible_tiles, .. } if !visible_tiles.is_empty() => { + let opacity_binding = ctx.prim_store.get_opacity_binding(opacity_binding_index); + for tile in visible_tiles { if let Some((batch_kind, textures, user_data, uv_rect_address)) = get_image_tile_params( ctx.resource_cache, @@ -1269,7 +1271,7 @@ impl AlphaBatchBuilder { deferred_resolves, request.with_tile(tile.tile_offset), alpha_type, - get_shader_opacity(opacity_binding.current), + get_shader_opacity(opacity_binding), ) { let prim_cache_address = gpu_cache.get_address(&tile.handle); let prim_header = PrimitiveHeader { @@ -1330,6 +1332,7 @@ impl AlphaBatchBuilder { gpu_cache, deferred_resolves, prim_instance, + ctx.prim_store, ) { let prim_header_index = prim_headers.push(&prim_header, z_id, params.prim_user_data); if prim_instance.is_chased() { @@ -1691,9 +1694,10 @@ impl BrushPrimitive { gpu_cache: &mut GpuCache, deferred_resolves: &mut Vec, prim_instance: &PrimitiveInstance, + prim_store: &PrimitiveStore, ) -> Option { match self.kind { - BrushKind::Image { alpha_type, request, ref source, ref opacity_binding, .. } => { + BrushKind::Image { alpha_type, request, ref source, opacity_binding_index, .. } => { let cache_item = match *source { ImageSource::Default => { resolve_image( @@ -1720,6 +1724,7 @@ impl BrushPrimitive { None } else { let textures = BatchTextures::color(cache_item.texture_id); + let opacity_binding = prim_store.get_opacity_binding(opacity_binding_index); Some(BrushBatchParameters::shared( BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)), @@ -1727,7 +1732,7 @@ impl BrushPrimitive { [ ShaderColorMode::Image as i32 | ((alpha_type as i32) << 16), RasterizationSpace::Local as i32, - get_shader_opacity(opacity_binding.current), + get_shader_opacity(opacity_binding), ], cache_item.uv_rect_handle.as_int(gpu_cache), )) @@ -1791,11 +1796,12 @@ impl BrushPrimitive { } } } - BrushKind::Solid { ref opacity_binding, .. } => { + BrushKind::Solid { opacity_binding_index, .. } => { + let opacity_binding = prim_store.get_opacity_binding(opacity_binding_index); Some(BrushBatchParameters::shared( BrushBatchKind::Solid, BatchTextures::no_texture(), - [get_shader_opacity(opacity_binding.current), 0, 0], + [get_shader_opacity(opacity_binding), 0, 0], 0, )) } diff --git a/webrender/src/border.rs b/webrender/src/border.rs index a7c7c07794..7472dae529 100644 --- a/webrender/src/border.rs +++ b/webrender/src/border.rs @@ -13,7 +13,6 @@ use gpu_types::{BorderInstance, BorderSegment, BrushFlags}; use prim_store::{BorderSegmentInfo, BrushKind, BrushPrimitive, BrushSegment, BrushSegmentVec}; use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain, BrushSegmentDescriptor}; use render_task::{RenderTaskCacheKey, RenderTaskCacheKeyKind}; -use smallvec::SmallVec; use util::{lerp, RectHelpers}; // Using 2048 as the maximum radius in device space before which we @@ -606,7 +605,7 @@ fn create_border_segments( rect: &LayoutRect, border: &NormalBorder, widths: &LayoutSideOffsets, - border_segments: &mut SmallVec<[BorderSegmentInfo; 8]>, + border_segments: &mut Vec, brush_segments: &mut BrushSegmentVec, ) { let local_size_tl = LayoutSize::new( @@ -938,7 +937,7 @@ fn add_corner_segment( segment: BorderSegment, edge_flags: EdgeAaSegmentMask, brush_segments: &mut BrushSegmentVec, - border_segments: &mut SmallVec<[BorderSegmentInfo; 8]>, + border_segments: &mut Vec, do_aa: bool, ) { if side0.color.a <= 0.0 && side1.color.a <= 0.0 { @@ -996,7 +995,7 @@ fn add_edge_segment( segment: BorderSegment, edge_flags: EdgeAaSegmentMask, brush_segments: &mut BrushSegmentVec, - border_segments: &mut SmallVec<[BorderSegmentInfo; 8]>, + border_segments: &mut Vec, do_aa: bool, ) { if side.color.a <= 0.0 { @@ -1121,7 +1120,7 @@ pub fn create_normal_border_prim( widths: LayoutSideOffsets, ) -> BrushPrimitive { let mut brush_segments = BrushSegmentVec::new(); - let mut border_segments = SmallVec::new(); + let mut border_segments = Vec::new(); create_border_segments( local_rect, diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index 8c373c05a1..6fdf882cc9 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -26,7 +26,7 @@ use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, Primitiv use prim_store::{BrushKind, BrushPrimitive, PrimitiveInstance, PrimitiveDataInterner, PrimitiveKeyKind}; use prim_store::{ImageSource, PrimitiveOpacity, PrimitiveKey, PrimitiveSceneData, PrimitiveInstanceKind}; use prim_store::{BorderSource, PrimitiveContainer, PrimitiveDataHandle, PrimitiveStore, PrimitiveStoreStats}; -use prim_store::{OpacityBinding, ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id}; +use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, OpacityBindingIndex}; use render_backend::{DocumentView}; use resource_cache::{FontInstanceMap, ImageRequest}; use scene::{Scene, ScenePipeline, StackingContextHelpers}; @@ -2015,7 +2015,7 @@ impl<'a> DisplayListFlattener<'a> { source: ImageSource::Default, sub_rect, visible_tiles: Vec::new(), - opacity_binding: OpacityBinding::new(), + opacity_binding_index: OpacityBindingIndex::INVALID, }, None, ); diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index ead7c5d41e..38fe38246a 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -681,7 +681,7 @@ pub struct BorderSegmentInfo { pub enum BorderSource { Image(ImageRequest), Border { - segments: SmallVec<[BorderSegmentInfo; 8]>, + segments: Vec, border: NormalBorder, widths: LayoutSideOffsets, }, @@ -690,7 +690,7 @@ pub enum BorderSource { pub enum BrushKind { Solid { color: ColorF, - opacity_binding: OpacityBinding, + opacity_binding_index: OpacityBindingIndex, }, Image { request: ImageRequest, @@ -700,7 +700,7 @@ pub enum BrushKind { color: ColorF, source: ImageSource, sub_rect: Option, - opacity_binding: OpacityBinding, + opacity_binding_index: OpacityBindingIndex, visible_tiles: Vec, }, YuvImage { @@ -762,7 +762,7 @@ impl BrushKind { pub fn new_solid(color: ColorF) -> BrushKind { BrushKind::Solid { color, - opacity_binding: OpacityBinding::new(), + opacity_binding_index: OpacityBindingIndex::INVALID, } } @@ -771,7 +771,7 @@ impl BrushKind { pub fn new_border( mut border: NormalBorder, widths: LayoutSideOffsets, - segments: SmallVec<[BorderSegmentInfo; 8]>, + segments: Vec, ) -> BrushKind { // FIXME(emilio): Is this the best place to do this? border.normalize(&widths); @@ -800,7 +800,7 @@ impl BrushKind { color, source: ImageSource::Default, sub_rect: None, - opacity_binding: OpacityBinding::new(), + opacity_binding_index: OpacityBindingIndex::INVALID, visible_tiles: Vec::new(), } } @@ -1911,6 +1911,8 @@ impl PrimitiveInstance { pub type GlyphKeyStorage = storage::Storage; pub type TextRunIndex = storage::Index; pub type TextRunStorage = storage::Storage; +pub type OpacityBindingIndex = storage::Index; +pub type OpacityBindingStorage = storage::Storage; /// Contains various vecs of data that is used only during frame building, /// where we want to recycle the memory each new display list, to avoid constantly @@ -1955,6 +1957,7 @@ pub struct PrimitiveStoreStats { primitive_count: usize, picture_count: usize, text_run_count: usize, + opacity_binding_count: usize, } impl PrimitiveStoreStats { @@ -1963,6 +1966,7 @@ impl PrimitiveStoreStats { primitive_count: 0, picture_count: 0, text_run_count: 0, + opacity_binding_count: 0, } } } @@ -1971,6 +1975,9 @@ pub struct PrimitiveStore { pub primitives: Vec, pub pictures: Vec, pub text_runs: TextRunStorage, + + /// List of animated opacity bindings for a primitive. + pub opacity_bindings: OpacityBindingStorage, } impl PrimitiveStore { @@ -1979,6 +1986,7 @@ impl PrimitiveStore { primitives: Vec::with_capacity(stats.primitive_count), pictures: Vec::with_capacity(stats.picture_count), text_runs: TextRunStorage::new(stats.text_run_count), + opacity_bindings: OpacityBindingStorage::new(stats.opacity_binding_count), } } @@ -1987,6 +1995,7 @@ impl PrimitiveStore { primitive_count: self.primitives.len(), picture_count: self.pictures.len(), text_run_count: self.text_runs.len(), + opacity_binding_count: self.opacity_bindings.len(), } } @@ -2047,6 +2056,17 @@ impl PrimitiveStore { PrimitiveIndex(prim_index) } + pub fn get_opacity_binding( + &self, + opacity_binding_index: OpacityBindingIndex, + ) -> f32 { + if opacity_binding_index == OpacityBindingIndex::INVALID { + 1.0 + } else { + self.opacity_bindings[opacity_binding_index].current + } + } + // Internal method that retrieves the primitive index of a primitive // that can be the target for collapsing parent opacity filters into. fn get_opacity_collapse_prim( @@ -2092,7 +2112,8 @@ impl PrimitiveStore { match brush.kind { // If we find a single rect or image, we can use that // as the primitive to collapse the opacity into. - BrushKind::Solid { .. } | BrushKind::Image { .. } => { + BrushKind::Solid { .. } | + BrushKind::Image { .. } => { return Some(prim_index) } BrushKind::Border { .. } | @@ -2136,8 +2157,12 @@ impl PrimitiveStore { // By this point, we know we should only have found a primitive // that supports opacity collapse. match brush.kind { - BrushKind::Solid { ref mut opacity_binding, .. } | - BrushKind::Image { ref mut opacity_binding, .. } => { + BrushKind::Solid { ref mut opacity_binding_index, .. } | + BrushKind::Image { ref mut opacity_binding_index, .. } => { + if *opacity_binding_index == OpacityBindingIndex::INVALID { + *opacity_binding_index = self.opacity_bindings.push(OpacityBinding::new()); + } + let opacity_binding = &mut self.opacity_bindings[*opacity_binding_index]; opacity_binding.push(binding); } BrushKind::YuvImage { .. } | @@ -2459,6 +2484,7 @@ impl PrimitiveStore { frame_context, frame_state, display_list, + &mut self.opacity_bindings, ); } } @@ -3070,6 +3096,7 @@ impl PrimitiveInstance { frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, display_list: &BuiltDisplayList, + opacity_bindings: &mut OpacityBindingStorage, ) { let mut is_tiled = false; @@ -3088,7 +3115,7 @@ impl PrimitiveInstance { color, ref mut tile_spacing, ref mut source, - ref mut opacity_binding, + opacity_binding_index, ref mut visible_tiles, .. } => { @@ -3100,7 +3127,11 @@ impl PrimitiveInstance { // Set if we need to request the source image from the cache this frame. if let Some(image_properties) = image_properties { is_tiled = image_properties.tiling.is_some(); - opacity_binding.update(frame_context.scene_properties); + let current_opacity = update_opacity_binding( + opacity_bindings, + opacity_binding_index, + frame_context.scene_properties, + ); if *tile_spacing != LayoutSize::zero() && !is_tiled { *source = ImageSource::Cache { @@ -3284,7 +3315,7 @@ impl PrimitiveInstance { } if is_opaque { - PrimitiveOpacity::from_alpha(opacity_binding.current * color.a) + PrimitiveOpacity::from_alpha(current_opacity * color.a) } else { PrimitiveOpacity::translucent() } @@ -3493,9 +3524,13 @@ impl PrimitiveInstance { PrimitiveOpacity::translucent() } } - BrushKind::Solid { ref color, ref mut opacity_binding, .. } => { - opacity_binding.update(frame_context.scene_properties); - PrimitiveOpacity::from_alpha(opacity_binding.current * color.a) + BrushKind::Solid { ref color, opacity_binding_index, .. } => { + let current_opacity = update_opacity_binding( + opacity_bindings, + opacity_binding_index, + frame_context.scene_properties, + ); + PrimitiveOpacity::from_alpha(current_opacity * color.a) } }; } @@ -3668,3 +3703,17 @@ fn get_line_decoration_sizes( } } } + +fn update_opacity_binding( + opacity_bindings: &mut OpacityBindingStorage, + opacity_binding_index: OpacityBindingIndex, + scene_properties: &SceneProperties, +) -> f32 { + if opacity_binding_index == OpacityBindingIndex::INVALID { + 1.0 + } else { + let binding = &mut opacity_bindings[opacity_binding_index]; + binding.update(scene_properties); + binding.current + } +} diff --git a/webrender/src/storage.rs b/webrender/src/storage.rs index 0966a9ecaf..5ee7ec14d3 100644 --- a/webrender/src/storage.rs +++ b/webrender/src/storage.rs @@ -2,7 +2,7 @@ * 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 std::{iter::Extend, ops, marker::PhantomData}; +use std::{iter::Extend, ops, marker::PhantomData, u32}; use util::recycle_vec; #[derive(Debug, Hash)] @@ -15,13 +15,22 @@ pub struct Index(u32, PhantomData); impl Clone for Index { fn clone(&self) -> Self { *self } } + impl Copy for Index {} +impl PartialEq for Index { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + impl Index { fn new(idx: usize) -> Self { debug_assert!(idx < u32::max_value() as usize); Index(idx as u32, PhantomData) } + + pub const INVALID: Index = Index(u32::MAX, PhantomData); } #[derive(Debug)]