Bug 1656711. Support hardware accelerated <feGaussianBlur> SVG filters if the x and y radius are not equal with webrender. r=gw

Pretty straight forward, mostly just plumbing stuff through.

Differential Revision: https://phabricator.services.mozilla.com/D85666
This commit is contained in:
Timothy Nikkel 2020-08-02 21:33:50 +00:00
Родитель e210ecd37e
Коммит 9db06357a1
9 изменённых файлов: 42 добавлений и 36 удалений

Просмотреть файл

@ -70,7 +70,7 @@ const OPACITY_EPSILON: f32 = 0.001;
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum Filter {
Identity,
Blur(f32),
Blur(f32, f32),
Brightness(f32),
Contrast(f32),
Grayscale(f32),
@ -116,7 +116,7 @@ impl Filter {
pub fn is_noop(&self) -> bool {
match *self {
Filter::Identity => false, // this is intentional
Filter::Blur(length) => length == 0.0,
Filter::Blur(width, height) => width == 0.0 && height == 0.0,
Filter::Brightness(amount) => amount == 1.0,
Filter::Contrast(amount) => amount == 1.0,
Filter::Grayscale(amount) => amount == 0.0,
@ -179,7 +179,7 @@ impl From<FilterOp> for Filter {
fn from(op: FilterOp) -> Self {
match op {
FilterOp::Identity => Filter::Identity,
FilterOp::Blur(r) => Filter::Blur(r),
FilterOp::Blur(w, h) => Filter::Blur(w, h),
FilterOp::Brightness(b) => Filter::Brightness(b),
FilterOp::Contrast(c) => Filter::Contrast(c),
FilterOp::Grayscale(g) => Filter::Grayscale(g),

Просмотреть файл

@ -4138,9 +4138,10 @@ impl PictureCompositeMode {
let mut result_rect = picture_rect;
match self {
PictureCompositeMode::Filter(filter) => match filter {
Filter::Blur(blur_radius) => {
let inflation_factor = clamp_blur_radius(*blur_radius, scale_factors).ceil() * BLUR_SAMPLE_SCALE;
result_rect = picture_rect.inflate(inflation_factor, inflation_factor);
Filter::Blur(width, height) => {
let width_factor = clamp_blur_radius(*width, scale_factors).ceil() * BLUR_SAMPLE_SCALE;
let height_factor = clamp_blur_radius(*height, scale_factors).ceil() * BLUR_SAMPLE_SCALE;
result_rect = picture_rect.inflate(width_factor, height_factor);
},
Filter::DropShadows(shadows) => {
let mut max_inflation: f32 = 0.0;
@ -4158,8 +4159,9 @@ impl PictureCompositeMode {
let output_rect = match primitive.kind {
FilterPrimitiveKind::Blur(ref primitive) => {
let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect);
let inflation_factor = primitive.radius.round() * BLUR_SAMPLE_SCALE;
input.inflate(inflation_factor, inflation_factor)
let width_factor = primitive.width.round() * BLUR_SAMPLE_SCALE;
let height_factor = primitive.height.round() * BLUR_SAMPLE_SCALE;
input.inflate(width_factor, height_factor)
}
FilterPrimitiveKind::DropShadow(ref primitive) => {
let inflation_factor = primitive.shadow.blur_radius.ceil() * BLUR_SAMPLE_SCALE;
@ -4886,11 +4888,12 @@ impl PicturePrimitive {
}
let dep_info = match raster_config.composite_mode {
PictureCompositeMode::Filter(Filter::Blur(blur_radius)) => {
let blur_std_deviation = clamp_blur_radius(blur_radius, scale_factors) * device_pixel_scale.0;
PictureCompositeMode::Filter(Filter::Blur(width, height)) => {
let width_std_deviation = clamp_blur_radius(width, scale_factors) * device_pixel_scale.0;
let height_std_deviation = clamp_blur_radius(height, scale_factors) * device_pixel_scale.0;
let mut blur_std_deviation = DeviceSize::new(
blur_std_deviation * scale_factors.0,
blur_std_deviation * scale_factors.1
width_std_deviation * scale_factors.0,
height_std_deviation * scale_factors.1
);
let mut device_rect = if self.options.inflate_if_required {
let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor;
@ -5934,8 +5937,8 @@ impl PicturePrimitive {
let mut inflation_factor = 0.0;
if self.options.inflate_if_required {
match composite_mode {
PictureCompositeMode::Filter(Filter::Blur(blur_radius)) => {
let blur_radius = clamp_blur_radius(blur_radius, scale_factors);
PictureCompositeMode::Filter(Filter::Blur(width, height)) => {
let blur_radius = f32::max(clamp_blur_radius(width, scale_factors), clamp_blur_radius(height, scale_factors));
// The amount of extra space needed for primitives inside
// this picture to ensure the visibility check is correct.
inflation_factor = blur_radius * BLUR_SAMPLE_SCALE;
@ -5944,7 +5947,8 @@ impl PicturePrimitive {
let mut max = 0.0;
for primitive in primitives {
if let FilterPrimitiveKind::Blur(ref blur) = primitive.kind {
max = f32::max(max, blur.radius);
max = f32::max(max, blur.width);
max = f32::max(max, blur.height);
}
}
inflation_factor = clamp_blur_radius(max, scale_factors) * BLUR_SAMPLE_SCALE;

Просмотреть файл

@ -60,7 +60,7 @@ pub enum FilterPrimitiveKey {
Identity(ColorSpace, FilterPrimitiveInput),
Flood(ColorSpace, ColorU),
Blend(ColorSpace, MixBlendMode, FilterPrimitiveInput, FilterPrimitiveInput),
Blur(ColorSpace, Au, FilterPrimitiveInput),
Blur(ColorSpace, Au, Au, FilterPrimitiveInput),
Opacity(ColorSpace, Au, FilterPrimitiveInput),
ColorMatrix(ColorSpace, [Au; 20], FilterPrimitiveInput),
DropShadow(ColorSpace, (VectorKey, Au, ColorU), FilterPrimitiveInput),
@ -79,7 +79,7 @@ pub enum PictureCompositeKey {
Identity,
// FilterOp
Blur(Au),
Blur(Au, Au),
Brightness(Au),
Contrast(Au),
Grayscale(Au),
@ -140,7 +140,8 @@ impl From<Option<PictureCompositeMode>> for PictureCompositeKey {
}
Some(PictureCompositeMode::Filter(op)) => {
match op {
Filter::Blur(value) => PictureCompositeKey::Blur(Au::from_f32_px(value)),
Filter::Blur(width, height) =>
PictureCompositeKey::Blur(Au::from_f32_px(width), Au::from_f32_px(height)),
Filter::Brightness(value) => PictureCompositeKey::Brightness(Au::from_f32_px(value)),
Filter::Contrast(value) => PictureCompositeKey::Contrast(Au::from_f32_px(value)),
Filter::Grayscale(value) => PictureCompositeKey::Grayscale(Au::from_f32_px(value)),
@ -188,7 +189,8 @@ impl From<Option<PictureCompositeMode>> for PictureCompositeKey {
FilterPrimitiveKind::Identity(identity) => FilterPrimitiveKey::Identity(primitive.color_space, identity.input),
FilterPrimitiveKind::Blend(blend) => FilterPrimitiveKey::Blend(primitive.color_space, blend.mode, blend.input1, blend.input2),
FilterPrimitiveKind::Flood(flood) => FilterPrimitiveKey::Flood(primitive.color_space, flood.color.into()),
FilterPrimitiveKind::Blur(blur) => FilterPrimitiveKey::Blur(primitive.color_space, Au::from_f32_px(blur.radius), blur.input),
FilterPrimitiveKind::Blur(blur) =>
FilterPrimitiveKey::Blur(primitive.color_space, Au::from_f32_px(blur.width), Au::from_f32_px(blur.height), blur.input),
FilterPrimitiveKind::Opacity(opacity) =>
FilterPrimitiveKey::Opacity(primitive.color_space, Au::from_f32_px(opacity.opacity), opacity.input),
FilterPrimitiveKind::ColorMatrix(color_matrix) => {

Просмотреть файл

@ -946,7 +946,8 @@ impl RenderTask {
))
}
FilterPrimitiveKind::Blur(ref blur) => {
let blur_std_deviation = blur.radius * device_pixel_scale.0;
let width_std_deviation = blur.width * device_pixel_scale.0;
let height_std_deviation = blur.height * device_pixel_scale.0;
let input_task_id = get_task_input(
&blur.input,
filter_primitives,
@ -958,7 +959,7 @@ impl RenderTask {
);
RenderTask::new_blur(
DeviceSize::new(blur_std_deviation, blur_std_deviation),
DeviceSize::new(width_std_deviation, height_std_deviation),
// TODO: This is a hack to ensure that a blur task's input is always
// in the blur's previous pass.
render_tasks.add().init(RenderTask::new_svg_filter_primitive(

Просмотреть файл

@ -2329,7 +2329,7 @@ impl<'a> SceneBuilder<'a> {
// blur radius is 0, the code in Picture::prepare_for_render will
// detect this and mark the picture to be drawn directly into the
// parent picture, which avoids an intermediate surface and blur.
let blur_filter = Filter::Blur(std_deviation);
let blur_filter = Filter::Blur(std_deviation, std_deviation);
let composite_mode = if blur_filter.is_noop() {
None
} else {

Просмотреть файл

@ -934,7 +934,8 @@ impl FloodPrimitive {
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
pub struct BlurPrimitive {
pub input: FilterPrimitiveInput,
pub radius: f32,
pub width: f32,
pub height: f32,
}
#[repr(C)]
@ -1061,7 +1062,7 @@ pub enum FilterOp {
/// Filter that does no transformation of the colors, needed for
/// debug purposes only.
Identity,
Blur(f32),
Blur(f32, f32),
Brightness(f32),
Contrast(f32),
Grayscale(f32),

Просмотреть файл

@ -573,8 +573,8 @@ impl YamlHelper for Yaml {
("component-transfer", _, _) => {
Some(FilterOp::ComponentTransfer)
}
("blur", ref args, _) if args.len() == 1 => {
Some(FilterOp::Blur(args[0].parse().unwrap()))
("blur", ref args, _) if args.len() == 2 => {
Some(FilterOp::Blur(args[0].parse().unwrap(), args[1].parse().unwrap()))
}
("brightness", ref args, _) if args.len() == 1 => {
Some(FilterOp::Brightness(args[0].parse().unwrap()))
@ -729,7 +729,8 @@ impl YamlHelper for Yaml {
"blur" => {
FilterPrimitiveKind::Blur(BlurPrimitive {
input: self["in"].as_filter_input().unwrap(),
radius: self["radius"].as_f32().unwrap(),
width: self["width"].as_f32().unwrap(),
height: self["height"].as_f32().unwrap(),
})
}
"opacity" => {

Просмотреть файл

@ -230,13 +230,9 @@ bool FilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
const GaussianBlurAttributes& blur = attr.as<GaussianBlurAttributes>();
const Size& stdDev = blur.mStdDeviation;
if (stdDev.width != stdDev.height) {
return false;
}
float radius = stdDev.width;
if (radius != 0.0) {
aWrFilters.filters.AppendElement(wr::FilterOp::Blur(radius));
if (stdDev.width != 0.0 || stdDev.height != 0.0) {
aWrFilters.filters.AppendElement(
wr::FilterOp::Blur(stdDev.width, stdDev.height));
} else {
filterIsNoop = true;
}

Просмотреть файл

@ -1163,8 +1163,9 @@ bool SVGIntegrationUtils::CreateWebRenderCSSFilters(
// TODO(emilio): we should go directly from css pixels -> device pixels.
float appUnitsPerDevPixel =
aFrame->PresContext()->AppUnitsPerDevPixel();
wrFilters.AppendElement(wr::FilterOp::Blur(NSAppUnitsToFloatPixels(
filter.AsBlur().ToAppUnits(), appUnitsPerDevPixel)));
float radius = NSAppUnitsToFloatPixels(filter.AsBlur().ToAppUnits(),
appUnitsPerDevPixel);
wrFilters.AppendElement(wr::FilterOp::Blur(radius, radius));
break;
}
case StyleFilter::Tag::DropShadow: {