Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 38 additions & 61 deletions webrender/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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};
Expand Down Expand Up @@ -59,84 +58,66 @@ impl DisplayListHelpers for Vec<DisplayItem> {
}

trait StackingContextHelpers {
fn needs_composition_operation_for_mix_blend_mode(&self) -> bool;
fn composition_operations(&self, auxiliary_lists: &AuxiliaryLists) -> Vec<CompositionOp>;
fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
fn filter_ops_for_compositing(&self, auxiliary_lists: &AuxiliaryLists) -> Vec<LowLevelFilterOp>;
}

impl StackingContextHelpers for StackingContext {
fn needs_composition_operation_for_mix_blend_mode(&self) -> bool {
fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> {
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<CompositionOp> {
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<LowLevelFilterOp> {
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
}
}

Expand Down Expand Up @@ -345,7 +326,7 @@ impl Frame {
LayerToScrollTransform::identity(),
pipeline_id,
current_scroll_layer_id,
&[]);
CompositeOps::empty());

self.flatten_items(traversal,
pipeline_id,
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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.
Expand All @@ -448,7 +425,7 @@ impl Frame {
transform,
pipeline_id,
scroll_layer_id,
&composition_operations);
composition_operations);

self.flatten_items(traversal,
pipeline_id,
Expand Down
8 changes: 1 addition & 7 deletions webrender/src/internal_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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),
}
129 changes: 61 additions & 68 deletions webrender/src/tiling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -1679,7 +1679,7 @@ pub struct StackingContext {
local_rect: LayerRect,
scroll_layer_id: ScrollLayerId,
xf_rect: Option<TransformedRect>,
composite_kind: CompositeKind,
composite_ops: CompositeOps,
clip_source: ClipSource,
clip_cache_info: Option<MaskCacheInfo>,
}
Expand All @@ -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<LowLevelFilterOp>,
// Requires two source textures (e.g. mix-blend-mode)
Complex(MixBlendMode),
mix_blend_mode: Option<MixBlendMode>,
}

impl CompositeKind {
fn new(composition_ops: &[CompositionOp]) -> CompositeKind {
if composition_ops.is_empty() {
return CompositeKind::None;
impl CompositeOps {
pub fn new(filters: Vec<LowLevelFilterOp>, mix_blend_mode: Option<MixBlendMode>) -> 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
}
}

Expand All @@ -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()
}
}

Expand Down Expand Up @@ -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());
Expand All @@ -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,
};
Expand Down Expand Up @@ -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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need to separate task creation from task initialization (which is happening in PopStackingContext)? Could we have all the logic in one place (in the pop code) instead?

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 => {
Expand All @@ -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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think changing the Z makes sense here, given that we are rendering into the task cache and that's not supposed to use the depth test anyway.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Z is used here when drawing the blend item into the main scene.

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) => {
Expand Down