Skip to content

Commit

Permalink
Bug 1917493 - Enable quad box shadows on a subset of outset box-shado…
Browse files Browse the repository at this point in the history
…ws r=gfx-reviewers,nical

We'll incrementally enable it on a wider range of content once we
resolve the unrelated pre-existing timing-related intermittent failures
that are tickled by these changes.

Differential Revision: https://phabricator.services.mozilla.com/D221413
  • Loading branch information
Glenn Watson authored and web-flow committed Sep 22, 2024
1 parent 1ffff3a commit e63e790
Show file tree
Hide file tree
Showing 9 changed files with 294 additions and 20 deletions.
106 changes: 103 additions & 3 deletions webrender/src/box_shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,7 @@ impl<'a> SceneBuilder<'a> {
// box-shadow support will be added to this path as a follow up.
if is_root_coord_system &&
clip_mode == BoxShadowClipMode::Outset &&
blur_radius < 32.0 &&
false {
blur_radius < 32.0 {
// Make sure corners don't overlap.
ensure_no_corner_overlap(&mut shadow_radius, shadow_rect.size());

Expand Down Expand Up @@ -446,7 +445,7 @@ impl<'a> SceneBuilder<'a> {

let inner_shadow_rect = shadow_rect.inflate(-sig3, -sig3);
let outer_shadow_rect = shadow_rect.inflate( sig3, sig3);
let inner_shadow_rect = extract_inner_rect_k(&inner_shadow_rect, &shadow_radius, 0.5).unwrap_or(LayoutRect::zero());
let inner_shadow_rect = extract_inner_rect_k(&inner_shadow_rect, &shadow_radius, 1.0).unwrap_or(LayoutRect::zero());

let prim = BoxShadow {
color: color.into(),
Expand Down Expand Up @@ -581,3 +580,104 @@ fn adjust_radius_for_box_shadow(border_radius: f32, spread_amount: f32) -> f32 {
0.0
}
}

pub struct BoxShadowSegment {
pub color: ColorF,
pub blur_radius: f32,
pub clip: ClipDataHandle,
pub pattern_rect: LayoutRect,
}

impl PatternBuilder for BoxShadowSegment {
fn build(
&self,
_sub_rect: Option<DeviceRect>,
ctx: &crate::pattern::PatternBuilderContext,
state: &mut crate::pattern::PatternBuilderState,
) -> Pattern {
let raster_spatial_node_index = ctx.spatial_tree.root_reference_frame_index();

let task_size = self.pattern_rect.size().cast_unit().to_i32();
let content_origin = self.pattern_rect.min.cast_unit();
let scale_factor = DevicePixelScale::new(1.0);
let uv_rect_kind = UvRectKind::Rect;

let blur_radius = self.blur_radius * scale_factor.0;
let clips_range = state.clip_store.push_clip_instance(self.clip);
let color_pattern = Pattern::color(self.color);

let pattern_prim_address_f = quad::write_prim_blocks(
&mut state.frame_gpu_data.f32,
self.pattern_rect,
self.pattern_rect,
color_pattern.base_color,
color_pattern.texture_input.task_id,
&[],
ScaleOffset::identity(),
);

let pattern_task_id = state.rg_builder.add().init(RenderTask::new_dynamic(
task_size,
RenderTaskKind::Prim(PrimTask {
pattern: color_pattern.kind,
pattern_input: color_pattern.shader_input,
raster_spatial_node_index,
device_pixel_scale: DevicePixelScale::new(1.0),
content_origin,
prim_address_f: pattern_prim_address_f,
transform_id: TransformPaletteId::IDENTITY,
edge_flags: EdgeAaSegmentMask::empty(),
quad_flags: QuadFlags::APPLY_RENDER_TASK_CLIP | QuadFlags::IGNORE_DEVICE_PIXEL_SCALE,
prim_needs_scissor_rect: false,
texture_input: color_pattern.texture_input.task_id,
}),
));

let masks = MaskSubPass {
clip_node_range: clips_range,
prim_spatial_node_index: raster_spatial_node_index,
prim_address_f: pattern_prim_address_f,
};

let task = state.rg_builder.get_task_mut(pattern_task_id);
task.add_sub_pass(SubPass::Masks { masks });

let blur_task_v = state.rg_builder.add().init(RenderTask::new_dynamic(
task_size,
RenderTaskKind::VerticalBlur(BlurTask {
blur_std_deviation: blur_radius,
target_kind: RenderTargetKind::Color,
blur_region: task_size,
}),
));
state.rg_builder.add_dependency(blur_task_v, pattern_task_id);

let blur_task_h = state.rg_builder.add().init(RenderTask::new_dynamic(
task_size,
RenderTaskKind::HorizontalBlur(BlurTask {
blur_std_deviation: blur_radius,
target_kind: RenderTargetKind::Color,
blur_region: task_size,
}),
).with_uv_rect_kind(uv_rect_kind));
state.rg_builder.add_dependency(blur_task_h, blur_task_v);

Pattern::texture(
blur_task_h,
self.color,
)
}

fn get_base_color(
&self,
_ctx: &crate::pattern::PatternBuilderContext,
) -> ColorF {
self.color
}

fn use_shared_pattern(
&self,
) -> bool {
false
}
}
30 changes: 30 additions & 0 deletions webrender/src/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,33 @@ impl Pattern {
}
}
}

// A reusable pattern builder for a segment of a larger primitive that can be
// drawn as a solid color
pub struct SolidColorSegment {
pub color: ColorF,
}

impl PatternBuilder for SolidColorSegment {
fn build(
&self,
_sub_rect: Option<DeviceRect>,
_ctx: &crate::pattern::PatternBuilderContext,
_state: &mut crate::pattern::PatternBuilderState,
) -> Pattern {
Pattern::color(self.color)
}

fn get_base_color(
&self,
_ctx: &crate::pattern::PatternBuilderContext,
) -> ColorF {
self.color
}

fn use_shared_pattern(
&self,
) -> bool {
true
}
}
178 changes: 161 additions & 17 deletions webrender/src/prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ use api::{BoxShadowClipMode, BorderStyle, ClipMode};
use api::units::*;
use euclid::Scale;
use smallvec::SmallVec;
use crate::box_shadow::BoxShadowSegment;
use crate::composite::CompositorSurfaceKind;
use crate::command_buffer::{CommandBufferIndex, PrimitiveCommand};
use crate::image_tiling::{self, Repetition};
use crate::border::{get_max_scale_for_border, build_border_instances};
use crate::clip::{ClipStore, ClipNodeRange};
use crate::pattern::Pattern;
use crate::clip::{ClipNodeRange, ClipStore};
use crate::pattern::{Pattern, SolidColorSegment};
use crate::spatial_tree::{SpatialNodeIndex, SpatialTree};
use crate::clip::{ClipDataStore, ClipNodeFlags, ClipChainInstance, ClipItemKind};
use crate::frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState};
Expand Down Expand Up @@ -324,21 +325,164 @@ fn prepare_interned_prim_for_render(
PrimitiveInstanceKind::BoxShadow { data_handle } => {
let prim_data = &mut data_stores.box_shadow[*data_handle];

quad::prepare_quad(
prim_data,
&prim_data.kind.outer_shadow_rect,
prim_instance_index,
prim_spatial_node_index,
&prim_instance.vis.clip_chain,
device_pixel_scale,
frame_context,
pic_context,
targets,
&data_stores.clip,
frame_state,
pic_state,
scratch,
);
// If there isn't an inner shadow rect, draw as a single primitive
if prim_data.kind.inner_shadow_rect.is_empty() {
quad::prepare_quad(
prim_data,
&prim_data.kind.outer_shadow_rect,
prim_instance_index,
prim_spatial_node_index,
&prim_instance.vis.clip_chain,
device_pixel_scale,
frame_context,
pic_context,
targets,
&data_stores.clip,
frame_state,
pic_state,
scratch,
);
} else {
// If we have an inner shadow rect, draw that as a solid color
// segment, and box-shadow segments for the outer segments
let dirty_world_rect = frame_state.current_dirty_region().combined;

let inner_segment = SolidColorSegment {
color: prim_data.kind.color,
};

quad::prepare_quad(
&inner_segment,
&prim_data.kind.inner_shadow_rect,
prim_instance_index,
prim_spatial_node_index,
&prim_instance.vis.clip_chain,
device_pixel_scale,
frame_context,
pic_context,
targets,
&data_stores.clip,
frame_state,
pic_state,
scratch,
);

let p0 = prim_data.kind.outer_shadow_rect.min;
let p1 = prim_data.kind.inner_shadow_rect.min;
let p3 = prim_data.kind.outer_shadow_rect.max;
let p2 = prim_data.kind.inner_shadow_rect.max;

let outer_rects = [
// Corners
LayoutRect::new(
LayoutPoint::new(p0.x, p0.y),
LayoutPoint::new(p1.x, p1.y),
),
LayoutRect::new(
LayoutPoint::new(p2.x, p0.y),
LayoutPoint::new(p3.x, p1.y),
),
LayoutRect::new(
LayoutPoint::new(p2.x, p2.y),
LayoutPoint::new(p3.x, p3.y),
),
LayoutRect::new(
LayoutPoint::new(p0.x, p2.y),
LayoutPoint::new(p1.x, p3.y),
),

// Top + Bottom
LayoutRect::new(
LayoutPoint::new(p1.x, p0.y),
LayoutPoint::new(p2.x, p1.y),
),
LayoutRect::new(
LayoutPoint::new(p1.x, p2.y),
LayoutPoint::new(p2.x, p3.y),
),

// Left + Right
LayoutRect::new(
LayoutPoint::new(p0.x, p1.y),
LayoutPoint::new(p1.x, p2.y),
),
LayoutRect::new(
LayoutPoint::new(p2.x, p1.y),
LayoutPoint::new(p3.x, p2.y),
),
];

for (i, rect) in outer_rects.iter().enumerate() {
// Edge (non-corner) segments are the same across the
// entire axis, so we can draw a small portion of them
// and stretch when drawing the segment, to reduce
// number of blurred pixels, which is important for swgl.
let fixed_size = 4.0;

let pattern_rect = match i {
0 .. 4 => *rect,
4 .. 6 => {
LayoutRect::new(
rect.min,
LayoutPoint::new(rect.min.x + fixed_size, rect.max.y),
)
},
6 .. 8 => {
LayoutRect::new(
rect.min,
LayoutPoint::new(rect.max.x, rect.min.y + fixed_size),
)
}
_ => unreachable!(),
};

let shadow_segment = BoxShadowSegment {
color: prim_data.kind.color,
blur_radius: prim_data.kind.blur_radius,
clip: prim_data.kind.clip,
pattern_rect,
};

frame_state.clip_store.set_active_clips_from_clip_chain(
&prim_instance.vis.clip_chain,
prim_spatial_node_index,
&frame_context.spatial_tree,
&data_stores.clip,
);

if let Some(segment_clip_chain) = frame_state
.clip_store
.build_clip_chain_instance(
*rect,
&pic_state.map_local_to_pic,
&pic_state.map_pic_to_world,
&frame_context.spatial_tree,
frame_state.gpu_cache,
frame_state.resource_cache,
device_pixel_scale,
&dirty_world_rect,
&mut data_stores.clip,
frame_state.rg_builder,
false,
) {
quad::prepare_quad(
&shadow_segment,
rect,
prim_instance_index,
prim_spatial_node_index,
&segment_clip_chain,
device_pixel_scale,
frame_context,
pic_context,
targets,
&data_stores.clip,
frame_state,
pic_state,
scratch,
);
}
}
}

return;
}
Expand Down
Binary file modified wrench/reftests/boxshadow/box-shadow-border-radii.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wrench/reftests/boxshadow/box-shadow-cache.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wrench/reftests/boxshadow/box-shadow-huge-radius.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wrench/reftests/boxshadow/box-shadow-stretch-mode-x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wrench/reftests/boxshadow/box-shadow-suite-blur.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wrench/reftests/boxshadow/overlap1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit e63e790

Please sign in to comment.