diff --git a/webrender/src/frame.rs b/webrender/src/frame.rs index 9cab06b093..7eb2251003 100644 --- a/webrender/src/frame.rs +++ b/webrender/src/frame.rs @@ -5,7 +5,6 @@ use app_units::Au; use fnv::FnvHasher; use internal_types::{ANGLE_FLOAT_TO_FIXED, AxisDirection}; -use internal_types::{CompositionOp}; use internal_types::{LowLevelFilterOp}; use internal_types::{RendererFrame}; use layer::Layer; @@ -14,7 +13,7 @@ use scene::Scene; use scroll_tree::{ScrollTree, ScrollStates}; use std::collections::HashMap; use std::hash::BuildHasherDefault; -use tiling::{AuxiliaryListsMap, FrameBuilder, FrameBuilderConfig, PrimitiveFlags}; +use tiling::{AuxiliaryListsMap, CompositeOps, FrameBuilder, FrameBuilderConfig, PrimitiveFlags}; use webrender_traits::{AuxiliaryLists, ClipRegion, ColorF, DisplayItem, Epoch, FilterOp}; use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, LayoutTransform}; use webrender_traits::{MixBlendMode, PipelineId, ScrollEventPhase, ScrollLayerId, ScrollLayerState}; @@ -59,84 +58,66 @@ impl DisplayListHelpers for Vec { } trait StackingContextHelpers { - fn needs_composition_operation_for_mix_blend_mode(&self) -> bool; - fn composition_operations(&self, auxiliary_lists: &AuxiliaryLists) -> Vec; + fn mix_blend_mode_for_compositing(&self) -> Option; + fn filter_ops_for_compositing(&self, auxiliary_lists: &AuxiliaryLists) -> Vec; } impl StackingContextHelpers for StackingContext { - fn needs_composition_operation_for_mix_blend_mode(&self) -> bool { + fn mix_blend_mode_for_compositing(&self) -> Option { match self.mix_blend_mode { - MixBlendMode::Normal => false, - MixBlendMode::Multiply | - MixBlendMode::Screen | - MixBlendMode::Overlay | - MixBlendMode::Darken | - MixBlendMode::Lighten | - MixBlendMode::ColorDodge | - MixBlendMode::ColorBurn | - MixBlendMode::HardLight | - MixBlendMode::SoftLight | - MixBlendMode::Difference | - MixBlendMode::Exclusion | - MixBlendMode::Hue | - MixBlendMode::Saturation | - MixBlendMode::Color | - MixBlendMode::Luminosity => true, + MixBlendMode::Normal => None, + _ => Some(self.mix_blend_mode), } } - fn composition_operations(&self, auxiliary_lists: &AuxiliaryLists) -> Vec { - let mut composition_operations = vec![]; - if self.needs_composition_operation_for_mix_blend_mode() { - composition_operations.push(CompositionOp::MixBlend(self.mix_blend_mode)); - } + fn filter_ops_for_compositing(&self, auxiliary_lists: &AuxiliaryLists) -> Vec { + let mut filters = vec![]; for filter in auxiliary_lists.filters(&self.filters) { match *filter { FilterOp::Blur(radius) => { - composition_operations.push(CompositionOp::Filter(LowLevelFilterOp::Blur( + filters.push(LowLevelFilterOp::Blur( radius, - AxisDirection::Horizontal))); - composition_operations.push(CompositionOp::Filter(LowLevelFilterOp::Blur( + AxisDirection::Horizontal)); + filters.push(LowLevelFilterOp::Blur( radius, - AxisDirection::Vertical))); + AxisDirection::Vertical)); } FilterOp::Brightness(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Brightness(Au::from_f32_px(amount)))); + filters.push( + LowLevelFilterOp::Brightness(Au::from_f32_px(amount))); } FilterOp::Contrast(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Contrast(Au::from_f32_px(amount)))); + filters.push( + LowLevelFilterOp::Contrast(Au::from_f32_px(amount))); } FilterOp::Grayscale(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Grayscale(Au::from_f32_px(amount)))); + filters.push( + LowLevelFilterOp::Grayscale(Au::from_f32_px(amount))); } FilterOp::HueRotate(angle) => { - composition_operations.push(CompositionOp::Filter( + filters.push( LowLevelFilterOp::HueRotate(f32::round( - angle * ANGLE_FLOAT_TO_FIXED) as i32))); + angle * ANGLE_FLOAT_TO_FIXED) as i32)); } FilterOp::Invert(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Invert(Au::from_f32_px(amount)))); + filters.push( + LowLevelFilterOp::Invert(Au::from_f32_px(amount))); } FilterOp::Opacity(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Opacity(Au::from_f32_px(amount)))); + filters.push( + LowLevelFilterOp::Opacity(Au::from_f32_px(amount))); } FilterOp::Saturate(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Saturate(Au::from_f32_px(amount)))); + filters.push( + LowLevelFilterOp::Saturate(Au::from_f32_px(amount))); } FilterOp::Sepia(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Sepia(Au::from_f32_px(amount)))); + filters.push( + LowLevelFilterOp::Sepia(Au::from_f32_px(amount))); } } } - - composition_operations + filters } } @@ -345,7 +326,7 @@ impl Frame { LayerToScrollTransform::identity(), pipeline_id, current_scroll_layer_id, - &[]); + CompositeOps::empty()); self.flatten_items(traversal, pipeline_id, @@ -378,18 +359,14 @@ impl Frame { let auxiliary_lists = self.pipeline_auxiliary_lists .get(&pipeline_id) .expect("No auxiliary lists?!"); - stacking_context.composition_operations(auxiliary_lists) + CompositeOps::new( + stacking_context.filter_ops_for_compositing(auxiliary_lists), + stacking_context.mix_blend_mode_for_compositing()) }; - // Detect composition operations that will make us invisible. - for composition_operation in &composition_operations { - match *composition_operation { - CompositionOp::Filter(LowLevelFilterOp::Opacity(Au(0))) => { - traversal.skip_current_stacking_context(); - return; - } - _ => {} - } + if composition_operations.will_make_invisible() { + traversal.skip_current_stacking_context(); + return; } let mut transform = @@ -428,7 +405,7 @@ impl Frame { transform, pipeline_id, scroll_layer_id, - &composition_operations); + CompositeOps::empty()); //Note: we don't use the original clip region here, // it's already processed by the layer we just pushed. @@ -448,7 +425,7 @@ impl Frame { transform, pipeline_id, scroll_layer_id, - &composition_operations); + composition_operations); self.flatten_items(traversal, pipeline_id, diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs index de0dabadee..a0d82ab915 100644 --- a/webrender/src/internal_types.rs +++ b/webrender/src/internal_types.rs @@ -19,7 +19,7 @@ use std::path::PathBuf; use std::sync::Arc; use tiling; use webrender_traits::{Epoch, ColorF, PipelineId, DeviceIntSize}; -use webrender_traits::{ImageFormat, MixBlendMode, NativeFontHandle}; +use webrender_traits::{ImageFormat, NativeFontHandle}; use webrender_traits::{ExternalImageId, ScrollLayerId, WebGLCommand}; // An ID for a texture that is owned by the @@ -460,9 +460,3 @@ pub enum LowLevelFilterOp { Saturate(Au), Sepia(Au), } - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum CompositionOp { - MixBlend(MixBlendMode), - Filter(LowLevelFilterOp), -} diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index 8fb0cba00d..93411a2783 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -7,7 +7,7 @@ use batch_builder::BorderSideHelpers; use fnv::FnvHasher; use frame::FrameId; use gpu_store::GpuStoreAddress; -use internal_types::{ANGLE_FLOAT_TO_FIXED, LowLevelFilterOp, CompositionOp}; +use internal_types::{ANGLE_FLOAT_TO_FIXED, LowLevelFilterOp}; use internal_types::{BatchTextures, CacheTextureId, SourceTexture}; use mask_cache::{ClipSource, MaskCacheInfo}; use prim_store::{PrimitiveGeometry, RectanglePrimitive, PrimitiveContainer}; @@ -1679,7 +1679,7 @@ pub struct StackingContext { local_rect: LayerRect, scroll_layer_id: ScrollLayerId, xf_rect: Option, - composite_kind: CompositeKind, + composite_ops: CompositeOps, clip_source: ClipSource, clip_cache_info: Option, } @@ -1704,39 +1704,41 @@ impl Default for PackedStackingContext { } } -#[derive(Debug, Copy, Clone)] -enum CompositeKind { - None, +#[derive(Debug, Clone)] +pub struct CompositeOps { // Requires only a single texture as input (e.g. most filters) - Simple(LowLevelFilterOp), + filters: Vec, // Requires two source textures (e.g. mix-blend-mode) - Complex(MixBlendMode), + mix_blend_mode: Option, } -impl CompositeKind { - fn new(composition_ops: &[CompositionOp]) -> CompositeKind { - if composition_ops.is_empty() { - return CompositeKind::None; +impl CompositeOps { + pub fn new(filters: Vec, mix_blend_mode: Option) -> CompositeOps { + CompositeOps { + filters: filters, + mix_blend_mode: mix_blend_mode } + } - match composition_ops.first().unwrap() { - &CompositionOp::Filter(filter_op) => { - match filter_op { - LowLevelFilterOp::Opacity(opacity) => { - let opacityf = opacity.to_f32_px(); - if opacityf == 1.0 { - CompositeKind::None - } else { - CompositeKind::Simple(LowLevelFilterOp::Opacity(opacity)) - } - } - other_filter => CompositeKind::Simple(other_filter), - } - } - &CompositionOp::MixBlend(mode) => { - CompositeKind::Complex(mode) + pub fn empty() -> CompositeOps { + CompositeOps { + filters: Vec::new(), + mix_blend_mode: None, + } + } + + pub fn count(&self) -> usize { + self.filters.len() + if self.mix_blend_mode.is_some() { 1 } else { 0 } + } + + pub fn will_make_invisible(&self) -> bool { + for op in &self.filters { + match op { + &LowLevelFilterOp::Opacity(Au(0)) => return true, + _ => {} } } + false } } @@ -1746,11 +1748,7 @@ impl StackingContext { } fn can_contribute_to_scene(&self) -> bool { - match self.composite_kind { - CompositeKind::None | CompositeKind::Complex(..) => true, - CompositeKind::Simple(LowLevelFilterOp::Opacity(opacity)) => opacity > Au(0), - CompositeKind::Simple(..) => true, - } + !self.composite_ops.will_make_invisible() } } @@ -1873,7 +1871,7 @@ impl FrameBuilder { transform: LayerToScrollTransform, pipeline_id: PipelineId, scroll_layer_id: ScrollLayerId, - composition_operations: &[CompositionOp]) { + composite_ops: CompositeOps) { let sc_index = StackingContextIndex(self.layer_store.len()); let clip_source = ClipSource::Region(clip_region.clone()); @@ -1887,7 +1885,7 @@ impl FrameBuilder { scroll_layer_id: scroll_layer_id, pipeline_id: pipeline_id, xf_rect: None, - composite_kind: CompositeKind::new(composition_operations), + composite_ops: composite_ops, clip_source: clip_source, clip_cache_info: clip_info, }; @@ -2601,18 +2599,16 @@ impl FrameBuilder { continue; } - match layer.composite_kind { - CompositeKind::None => {} - CompositeKind::Simple(..) | CompositeKind::Complex(..) => { - let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect; - let location = RenderTaskLocation::Dynamic(None, layer_rect.size); - let new_task = RenderTask::new_alpha_batch(next_task_index, - layer_rect.origin, - location); - next_task_index.0 += 1; - let prev_task = mem::replace(&mut current_task, new_task); - alpha_task_stack.push(prev_task); - } + let composite_count = layer.composite_ops.count(); + for _ in 0..composite_count { + let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect; + let location = RenderTaskLocation::Dynamic(None, layer_rect.size); + let new_task = RenderTask::new_alpha_batch(next_task_index, + layer_rect.origin, + location); + next_task_index.0 += 1; + let prev_task = mem::replace(&mut current_task, new_task); + alpha_task_stack.push(prev_task); } } PrimitiveRunCmd::PopStackingContext => { @@ -2623,28 +2619,25 @@ impl FrameBuilder { continue; } - match layer.composite_kind { - CompositeKind::None => {} - CompositeKind::Simple(info) => { - let mut prev_task = alpha_task_stack.pop().unwrap(); - let item = AlphaRenderItem::Blend(sc_index, current_task.id, info, next_z); - next_z += 1; - prev_task.as_alpha_batch().alpha_items.push(item); - prev_task.children.push(current_task); - current_task = prev_task; - } - CompositeKind::Complex(info) => { - let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect; - let readback_task = RenderTask::new_readback(sc_index, layer_rect); - - let mut prev_task = alpha_task_stack.pop().unwrap(); - let item = AlphaRenderItem::Composite(sc_index, readback_task.id, current_task.id, info, next_z); - next_z += 1; - prev_task.as_alpha_batch().alpha_items.push(item); - prev_task.children.push(current_task); - prev_task.children.push(readback_task); - current_task = prev_task; - } + for filter in &layer.composite_ops.filters { + let mut prev_task = alpha_task_stack.pop().unwrap(); + let item = AlphaRenderItem::Blend(sc_index, current_task.id, *filter, next_z); + next_z += 1; + prev_task.as_alpha_batch().alpha_items.push(item); + prev_task.children.push(current_task); + current_task = prev_task; + } + if let Some(mix_blend_mode) = layer.composite_ops.mix_blend_mode { + let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect; + let readback_task = RenderTask::new_readback(sc_index, layer_rect); + + let mut prev_task = alpha_task_stack.pop().unwrap(); + let item = AlphaRenderItem::Composite(sc_index, readback_task.id, current_task.id, mix_blend_mode, next_z); + next_z += 1; + prev_task.as_alpha_batch().alpha_items.push(item); + prev_task.children.push(current_task); + prev_task.children.push(readback_task); + current_task = prev_task; } } PrimitiveRunCmd::PrimitiveRun(first_prim_index, prim_count) => {