author | Noemi Erli <nerli@mozilla.com> |
Wed, 10 Jul 2019 23:27:36 +0300 | |
changeset 482271 | 27679131d486cb10ecb6337688db6e84cc8b48e4 |
parent 482270 | 1edf0457ac230fdbdb31fd621bb49c4188daa9fc |
child 482272 | 6484c07ff83649914781ddc9cfb70e98466cdd7a |
push id | 89666 |
push user | nerli@mozilla.com |
push date | Wed, 10 Jul 2019 20:28:04 +0000 |
treeherder | autoland@27679131d486 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1555483 |
milestone | 70.0a1 |
backs out | 8149efc1f8131d09db617e82c9e6fbde25cccd0c 917f800e4e43a0dc4799dd5893d4fa4b96454857 418839320ab5b103817da82d7582016c3cf8ccbe 134a51a0e03463d045ab71b79d251a91c70a8cd9 7c43dc769da78fe45d9caf3d5dbd0205f33aa156 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -2184,17 +2184,16 @@ pub extern "C" fn wr_dp_push_stacking_co .push_stacking_context(bounds.origin, wr_spatial_id, params.is_backface_visible, wr_clip_id, params.transform_style, params.mix_blend_mode, &filters, &r_filter_datas, - &[], glyph_raster_space, params.cache_tiles); result } #[no_mangle] pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState,
--- a/gfx/wr/examples/animation.rs +++ b/gfx/wr/examples/animation.rs @@ -66,17 +66,16 @@ impl App { ); builder.push_simple_stacking_context_with_filters( LayoutPoint::zero(), spatial_id, true, &filters, &[], - &[] ); let space_and_clip = SpaceAndClipInfo { spatial_id, clip_id: ClipId::root(pipeline_id), }; let clip_bounds = LayoutRect::new(LayoutPoint::zero(), bounds.size); let complex_clip = ComplexClipRegion {
deleted file mode 100644 --- a/gfx/wr/webrender/res/cs_svg_filter.glsl +++ /dev/null @@ -1,534 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -#include shared,prim_shared - -varying vec3 vInput1Uv; -varying vec3 vInput2Uv; -flat varying vec4 vInput1UvRect; -flat varying vec4 vInput2UvRect; -flat varying int vFilterInputCount; -flat varying int vFilterKind; -flat varying ivec4 vData; -flat varying vec4 vFilterData0; -flat varying vec4 vFilterData1; -flat varying float vFloat0; -flat varying mat3 vColorMat; -flat varying int vFuncs[4]; - -#define FILTER_BLEND 0 -#define FILTER_FLOOD 1 -#define FILTER_LINEAR_TO_SRGB 2 -#define FILTER_SRGB_TO_LINEAR 3 -#define FILTER_OPACITY 4 -#define FILTER_COLOR_MATRIX 5 -#define FILTER_DROP_SHADOW 6 -#define FILTER_OFFSET 7 -#define FILTER_COMPONENT_TRANSFER 8 -#define FILTER_IDENTITY 9 - -#ifdef WR_VERTEX_SHADER - -in int aFilterRenderTaskAddress; -in int aFilterInput1TaskAddress; -in int aFilterInput2TaskAddress; -in int aFilterKind; -in int aFilterInputCount; -in int aFilterGenericInt; -in ivec2 aFilterExtraDataAddress; - -struct FilterTask { - RenderTaskCommonData common_data; - vec3 user_data; -}; - -FilterTask fetch_filter_task(int address) { - RenderTaskData task_data = fetch_render_task_data(address); - - FilterTask task = FilterTask( - task_data.common_data, - task_data.user_data.xyz - ); - - return task; -} - -vec4 compute_uv_rect(RenderTaskCommonData task, vec2 texture_size) { - RectWithSize task_rect = task.task_rect; - - vec4 uvRect = vec4(task_rect.p0 + vec2(0.5), - task_rect.p0 + task_rect.size - vec2(0.5)); - uvRect /= texture_size.xyxy; - return uvRect; -} - -vec3 compute_uv(RenderTaskCommonData task, vec2 texture_size) { - RectWithSize task_rect = task.task_rect; - vec3 uv = vec3(0.0, 0.0, task.texture_layer_index); - - vec2 uv0 = task_rect.p0 / texture_size; - vec2 uv1 = floor(task_rect.p0 + task_rect.size) / texture_size; - uv.xy = mix(uv0, uv1, aPosition.xy); - - return uv; -} - -void main(void) { - FilterTask filter_task = fetch_filter_task(aFilterRenderTaskAddress); - RectWithSize target_rect = filter_task.common_data.task_rect; - - vec2 pos = target_rect.p0 + target_rect.size * aPosition.xy; - - RenderTaskCommonData input_1_task; - if (aFilterInputCount > 0) { - vec2 texture_size = vec2(textureSize(sColor0, 0).xy); - input_1_task = fetch_render_task_common_data(aFilterInput1TaskAddress); - vInput1UvRect = compute_uv_rect(input_1_task, texture_size); - vInput1Uv = compute_uv(input_1_task, texture_size); - } - - RenderTaskCommonData input_2_task; - if (aFilterInputCount > 1) { - vec2 texture_size = vec2(textureSize(sColor1, 0).xy); - input_2_task = fetch_render_task_common_data(aFilterInput2TaskAddress); - vInput2UvRect = compute_uv_rect(input_2_task, texture_size); - vInput2Uv = compute_uv(input_2_task, texture_size); - } - - vFilterInputCount = aFilterInputCount; - vFilterKind = aFilterKind; - - // This assignment is only used for component transfer filters but this - // assignment has to be done here and not in the component transfer case - // below because it doesn't get executed on Windows because of a suspected - // miscompile of this shader on Windows. See - // https://github.com/servo/webrender/wiki/Driver-issues#bug-1505871---assignment-to-varying-flat-arrays-inside-switch-statement-of-vertex-shader-suspected-miscompile-on-windows - // default: just to satisfy angle_shader_validation.rs which needs one - // default: for every switch, even in comments. - vFuncs[0] = (aFilterGenericInt >> 12) & 0xf; // R - vFuncs[1] = (aFilterGenericInt >> 8) & 0xf; // G - vFuncs[2] = (aFilterGenericInt >> 4) & 0xf; // B - vFuncs[3] = (aFilterGenericInt) & 0xf; // A - - switch (aFilterKind) { - case FILTER_BLEND: - vData = ivec4(aFilterGenericInt, 0, 0, 0); - break; - case FILTER_FLOOD: - vFilterData0 = fetch_from_gpu_cache_1_direct(aFilterExtraDataAddress); - break; - case FILTER_OPACITY: - vFloat0 = filter_task.user_data.x; - break; - case FILTER_COLOR_MATRIX: - vec4 mat_data[3] = fetch_from_gpu_cache_3_direct(aFilterExtraDataAddress); - vColorMat = mat3(mat_data[0].xyz, mat_data[1].xyz, mat_data[2].xyz); - vFilterData0 = fetch_from_gpu_cache_1_direct(aFilterExtraDataAddress + ivec2(4, 0)); - break; - case FILTER_DROP_SHADOW: - vFilterData0 = fetch_from_gpu_cache_1_direct(aFilterExtraDataAddress); - break; - case FILTER_OFFSET: - vec2 texture_size = vec2(textureSize(sColor0, 0).xy); - vFilterData0 = vec4(-filter_task.user_data.xy / texture_size, vec2(0.0)); - - RectWithSize task_rect = input_1_task.task_rect; - vec4 clipRect = vec4(task_rect.p0, task_rect.p0 + task_rect.size); - clipRect /= texture_size.xyxy; - vFilterData1 = clipRect; - break; - case FILTER_COMPONENT_TRANSFER: - vData = ivec4(aFilterExtraDataAddress, 0, 0); - break; - default: - break; - } - - gl_Position = uTransform * vec4(pos, 0.0, 1.0); -} -#endif - -#ifdef WR_FRAGMENT_SHADER - -#define COMPONENT_TRANSFER_IDENTITY 0 -#define COMPONENT_TRANSFER_TABLE 1 -#define COMPONENT_TRANSFER_DISCRETE 2 -#define COMPONENT_TRANSFER_LINEAR 3 -#define COMPONENT_TRANSFER_GAMMA 4 - -vec3 Multiply(vec3 Cb, vec3 Cs) { - return Cb * Cs; -} - -vec3 Screen(vec3 Cb, vec3 Cs) { - return Cb + Cs - (Cb * Cs); -} - -vec3 HardLight(vec3 Cb, vec3 Cs) { - vec3 m = Multiply(Cb, 2.0 * Cs); - vec3 s = Screen(Cb, 2.0 * Cs - 1.0); - vec3 edge = vec3(0.5, 0.5, 0.5); - return mix(m, s, step(edge, Cs)); -} - -// TODO: Worth doing with mix/step? Check GLSL output. -float ColorDodge(float Cb, float Cs) { - if (Cb == 0.0) - return 0.0; - else if (Cs == 1.0) - return 1.0; - else - return min(1.0, Cb / (1.0 - Cs)); -} - -// TODO: Worth doing with mix/step? Check GLSL output. -float ColorBurn(float Cb, float Cs) { - if (Cb == 1.0) - return 1.0; - else if (Cs == 0.0) - return 0.0; - else - return 1.0 - min(1.0, (1.0 - Cb) / Cs); -} - -float SoftLight(float Cb, float Cs) { - if (Cs <= 0.5) { - return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb); - } else { - float D; - - if (Cb <= 0.25) - D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb; - else - D = sqrt(Cb); - - return Cb + (2.0 * Cs - 1.0) * (D - Cb); - } -} - -vec3 Difference(vec3 Cb, vec3 Cs) { - return abs(Cb - Cs); -} - -vec3 Exclusion(vec3 Cb, vec3 Cs) { - return Cb + Cs - 2.0 * Cb * Cs; -} - -// These functions below are taken from the spec. -// There's probably a much quicker way to implement -// them in GLSL... -float Sat(vec3 c) { - return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b)); -} - -float Lum(vec3 c) { - vec3 f = vec3(0.3, 0.59, 0.11); - return dot(c, f); -} - -vec3 ClipColor(vec3 C) { - float L = Lum(C); - float n = min(C.r, min(C.g, C.b)); - float x = max(C.r, max(C.g, C.b)); - - if (n < 0.0) - C = L + (((C - L) * L) / (L - n)); - - if (x > 1.0) - C = L + (((C - L) * (1.0 - L)) / (x - L)); - - return C; -} - -vec3 SetLum(vec3 C, float l) { - float d = l - Lum(C); - return ClipColor(C + d); -} - -void SetSatInner(inout float Cmin, inout float Cmid, inout float Cmax, float s) { - if (Cmax > Cmin) { - Cmid = (((Cmid - Cmin) * s) / (Cmax - Cmin)); - Cmax = s; - } else { - Cmid = 0.0; - Cmax = 0.0; - } - Cmin = 0.0; -} - -vec3 SetSat(vec3 C, float s) { - if (C.r <= C.g) { - if (C.g <= C.b) { - SetSatInner(C.r, C.g, C.b, s); - } else { - if (C.r <= C.b) { - SetSatInner(C.r, C.b, C.g, s); - } else { - SetSatInner(C.b, C.r, C.g, s); - } - } - } else { - if (C.r <= C.b) { - SetSatInner(C.g, C.r, C.b, s); - } else { - if (C.g <= C.b) { - SetSatInner(C.g, C.b, C.r, s); - } else { - SetSatInner(C.b, C.g, C.r, s); - } - } - } - return C; -} - -vec3 Hue(vec3 Cb, vec3 Cs) { - return SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb)); -} - -vec3 Saturation(vec3 Cb, vec3 Cs) { - return SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb)); -} - -vec3 Color(vec3 Cb, vec3 Cs) { - return SetLum(Cs, Lum(Cb)); -} - -vec3 Luminosity(vec3 Cb, vec3 Cs) { - return SetLum(Cb, Lum(Cs)); -} - -const int BlendMode_Normal = 0; -const int BlendMode_Multiply = 1; -const int BlendMode_Screen = 2; -const int BlendMode_Overlay = 3; -const int BlendMode_Darken = 4; -const int BlendMode_Lighten = 5; -const int BlendMode_ColorDodge = 6; -const int BlendMode_ColorBurn = 7; -const int BlendMode_HardLight = 8; -const int BlendMode_SoftLight = 9; -const int BlendMode_Difference = 10; -const int BlendMode_Exclusion = 11; -const int BlendMode_Hue = 12; -const int BlendMode_Saturation = 13; -const int BlendMode_Color = 14; -const int BlendMode_Luminosity = 15; - -vec4 blend(vec4 Cs, vec4 Cb, int mode) { - vec4 result = vec4(1.0, 0.0, 0.0, 1.0); - - switch (mode) { - case BlendMode_Normal: - result.rgb = Cs.rgb; - break; - case BlendMode_Multiply: - result.rgb = Multiply(Cb.rgb, Cs.rgb); - break; - case BlendMode_Screen: - result.rgb = Screen(Cb.rgb, Cs.rgb); - break; - case BlendMode_Overlay: - // Overlay is inverse of Hardlight - result.rgb = HardLight(Cs.rgb, Cb.rgb); - break; - case BlendMode_Darken: - result.rgb = min(Cs.rgb, Cb.rgb); - break; - case BlendMode_Lighten: - result.rgb = max(Cs.rgb, Cb.rgb); - break; - case BlendMode_ColorDodge: - result.r = ColorDodge(Cb.r, Cs.r); - result.g = ColorDodge(Cb.g, Cs.g); - result.b = ColorDodge(Cb.b, Cs.b); - break; - case BlendMode_ColorBurn: - result.r = ColorBurn(Cb.r, Cs.r); - result.g = ColorBurn(Cb.g, Cs.g); - result.b = ColorBurn(Cb.b, Cs.b); - break; - case BlendMode_HardLight: - result.rgb = HardLight(Cb.rgb, Cs.rgb); - break; - case BlendMode_SoftLight: - result.r = SoftLight(Cb.r, Cs.r); - result.g = SoftLight(Cb.g, Cs.g); - result.b = SoftLight(Cb.b, Cs.b); - break; - case BlendMode_Difference: - result.rgb = Difference(Cb.rgb, Cs.rgb); - break; - case BlendMode_Exclusion: - result.rgb = Exclusion(Cb.rgb, Cs.rgb); - break; - case BlendMode_Hue: - result.rgb = Hue(Cb.rgb, Cs.rgb); - break; - case BlendMode_Saturation: - result.rgb = Saturation(Cb.rgb, Cs.rgb); - break; - case BlendMode_Color: - result.rgb = Color(Cb.rgb, Cs.rgb); - break; - case BlendMode_Luminosity: - result.rgb = Luminosity(Cb.rgb, Cs.rgb); - break; - default: break; - } - vec3 rgb = (1.0 - Cb.a) * Cs.rgb + Cb.a * result.rgb; - result = mix(vec4(Cb.rgb * Cb.a, Cb.a), vec4(rgb, 1.0), Cs.a); - return result; -} - -// Based on the Gecko's implementation in -// https://hg.mozilla.org/mozilla-central/file/91b4c3687d75/gfx/src/FilterSupport.cpp#l24 -// These could be made faster by sampling a lookup table stored in a float texture -// with linear interpolation. - -vec3 SrgbToLinear(vec3 color) { - vec3 c1 = color / 12.92; - vec3 c2 = pow(color / 1.055 + vec3(0.055 / 1.055), vec3(2.4)); - return if_then_else(lessThanEqual(color, vec3(0.04045)), c1, c2); -} - -vec3 LinearToSrgb(vec3 color) { - vec3 c1 = color * 12.92; - vec3 c2 = vec3(1.055) * pow(color, vec3(1.0 / 2.4)) - vec3(0.055); - return if_then_else(lessThanEqual(color, vec3(0.0031308)), c1, c2); -} - -// This function has to be factored out due to the following issue: -// https://github.com/servo/webrender/wiki/Driver-issues#bug-1532245---switch-statement-inside-control-flow-inside-switch-statement-fails-to-compile-on-some-android-phones -// (and now the words "default: default:" so angle_shader_validation.rs passes) -vec4 ComponentTransfer(vec4 colora) { - // We push a different amount of data to the gpu cache depending on the - // function type. - // Identity => 0 blocks - // Table/Discrete => 64 blocks (256 values) - // Linear => 1 block (2 values) - // Gamma => 1 block (3 values) - // We loop through the color components and increment the offset (for the - // next color component) into the gpu cache based on how many blocks that - // function type put into the gpu cache. - // Table/Discrete use a 256 entry look up table. - // Linear/Gamma are a simple calculation. - int offset = 0; - vec4 texel; - int k; - - for (int i = 0; i < 4; i++) { - switch (vFuncs[i]) { - case COMPONENT_TRANSFER_IDENTITY: - break; - case COMPONENT_TRANSFER_TABLE: - case COMPONENT_TRANSFER_DISCRETE: - // fetch value from lookup table - k = int(floor(colora[i]*255.0)); - texel = fetch_from_gpu_cache_1_direct(vData.xy + ivec2(offset + k/4, 0)); - colora[i] = clamp(texel[k % 4], 0.0, 1.0); - // offset plus 256/4 blocks - offset = offset + 64; - break; - case COMPONENT_TRANSFER_LINEAR: - // fetch the two values for use in the linear equation - texel = fetch_from_gpu_cache_1_direct(vData.xy + ivec2(offset, 0)); - colora[i] = clamp(texel[0] * colora[i] + texel[1], 0.0, 1.0); - // offset plus 1 block - offset = offset + 1; - break; - case COMPONENT_TRANSFER_GAMMA: - // fetch the three values for use in the gamma equation - texel = fetch_from_gpu_cache_1_direct(vData.xy + ivec2(offset, 0)); - colora[i] = clamp(texel[0] * pow(colora[i], texel[1]) + texel[2], 0.0, 1.0); - // offset plus 1 block - offset = offset + 1; - break; - default: - // shouldn't happen - break; - } - } - return colora; -} - -vec4 sampleInUvRect(sampler2DArray sampler, vec3 uv, vec4 uvRect) { - vec2 clamped = clamp(uv.xy, uvRect.xy, uvRect.zw); - return texture(sampler, vec3(clamped, uv.z), 0.0); -} - -void main(void) { - vec4 Ca = vec4(0.0, 0.0, 0.0, 0.0); - vec4 Cb = vec4(0.0, 0.0, 0.0, 0.0); - if (vFilterInputCount > 0) { - Ca = sampleInUvRect(sColor0, vInput1Uv, vInput1UvRect); - if (Ca.a != 0.0) { - Ca.rgb /= Ca.a; - } - } - if (vFilterInputCount > 1) { - Cb = sampleInUvRect(sColor1, vInput2Uv, vInput2UvRect); - if (Cb.a != 0.0) { - Cb.rgb /= Cb.a; - } - } - - vec4 result = vec4(1.0, 0.0, 0.0, 1.0); - - bool needsPremul = true; - - switch (vFilterKind) { - case FILTER_BLEND: - result = blend(Ca, Cb, vData.x); - needsPremul = false; - break; - case FILTER_FLOOD: - result = vFilterData0; - needsPremul = false; - break; - case FILTER_LINEAR_TO_SRGB: - result.rgb = LinearToSrgb(Ca.rgb); - result.a = Ca.a; - break; - case FILTER_SRGB_TO_LINEAR: - result.rgb = SrgbToLinear(Ca.rgb); - result.a = Ca.a; - break; - case FILTER_OPACITY: - result.rgb = Ca.rgb; - result.a = Ca.a * vFloat0; - break; - case FILTER_COLOR_MATRIX: - result.rgb = vColorMat * Ca.rgb + vFilterData0.rgb; - result.a = Ca.a; - break; - case FILTER_DROP_SHADOW: - vec4 shadow = vec4(vFilterData0.rgb, Cb.a * vFilterData0.a); - // Normal blend + source-over coposite - result = blend(Ca, shadow, BlendMode_Normal); - needsPremul = false; - break; - case FILTER_OFFSET: - vec2 offsetUv = vInput1Uv.xy + vFilterData0.xy; - result = sampleInUvRect(sColor0, vec3(offsetUv, vInput1Uv.z), vInput1UvRect); - result *= point_inside_rect(offsetUv, vFilterData1.xy, vFilterData1.zw); - needsPremul = false; - break; - case FILTER_COMPONENT_TRANSFER: - vec4 colora = Ca.a != 0.0 ? Ca / Ca.a : Ca; - result = ComponentTransfer(Ca); - break; - case FILTER_IDENTITY: - result = Ca; - break; - default: - break; - } - - if (needsPremul) { - result.rgb *= result.a; - } - - oFragColor = result; -} -#endif
--- a/gfx/wr/webrender/src/batch.rs +++ b/gfx/wr/webrender/src/batch.rs @@ -95,37 +95,16 @@ impl BatchTextures { } } pub fn color(texture: TextureSource) -> Self { BatchTextures { colors: [texture, texture, TextureSource::Invalid], } } - - pub fn is_compatible_with(&self, other: &BatchTextures) -> bool { - self.colors.iter().zip(other.colors.iter()).all(|(t1, t2)| textures_compatible(*t1, *t2)) - } - - pub fn combine_textures(&self, other: BatchTextures) -> Option<BatchTextures> { - if !self.is_compatible_with(&other) { - return None; - } - - let mut new_textures = BatchTextures::no_texture(); - for (i, (color, other_color)) in self.colors.iter().zip(other.colors.iter()).enumerate() { - // If these textures are compatible, for each source either both sources are invalid or only one is not invalid. - new_textures.colors[i] = if *color == TextureSource::Invalid { - *other_color - } else { - *color - }; - } - Some(new_textures) - } } #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BatchKey { pub kind: BatchKind, pub blend_mode: BlendMode, @@ -137,17 +116,20 @@ impl BatchKey { BatchKey { kind, blend_mode, textures, } } pub fn is_compatible_with(&self, other: &BatchKey) -> bool { - self.kind == other.kind && self.blend_mode == other.blend_mode && self.textures.is_compatible_with(&other.textures) + self.kind == other.kind && self.blend_mode == other.blend_mode && + textures_compatible(self.textures.colors[0], other.textures.colors[0]) && + textures_compatible(self.textures.colors[1], other.textures.colors[1]) && + textures_compatible(self.textures.colors[2], other.textures.colors[2]) } } #[inline] fn textures_compatible(t1: TextureSource, t2: TextureSource) -> bool { t1 == TextureSource::Invalid || t2 == TextureSource::Invalid || t1 == t2 } @@ -1653,50 +1635,16 @@ impl BatchBuilder { transform_kind, render_tasks, z_id, prim_info.clip_task_index, prim_vis_mask, ctx, ); } - PictureCompositeMode::SvgFilter(..) => { - let kind = BatchKind::Brush( - BrushBatchKind::Image(ImageBufferKind::Texture2DArray) - ); - let (uv_rect_address, textures) = render_tasks.resolve_surface( - surface_task.expect("bug: surface must be allocated by now"), - gpu_cache, - ); - let key = BatchKey::new( - kind, - non_segmented_blend_mode, - textures, - ); - let prim_header_index = prim_headers.push(&prim_header, z_id, [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Screen as i32, - get_shader_opacity(1.0), - 0, - ]); - - self.add_brush_instance_to_batches( - key, - batch_features, - bounding_rect, - z_id, - INVALID_SEGMENT_INDEX, - EdgeAaSegmentMask::empty(), - clip_task_address, - brush_flags, - prim_header_index, - uv_rect_address.as_int(), - prim_vis_mask, - ); - } } } None => { // If this picture is being drawn into an existing target (i.e. with // no composition operation), recurse and add to the current batch list. self.add_pic_to_batch( picture, ctx,
--- a/gfx/wr/webrender/src/display_list_flattener.rs +++ b/gfx/wr/webrender/src/display_list_flattener.rs @@ -1,16 +1,16 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * 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 api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter}; use api::{ClipId, ColorF, CommonItemProperties, ComplexClipRegion, RasterSpace}; use api::{DisplayItem, DisplayItemRef, ExtendMode, ExternalScrollId}; -use api::{FilterOp, FilterPrimitive, FontInstanceKey, GlyphInstance, GlyphOptions, GradientStop}; +use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, GradientStop}; use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, ColorDepth}; use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId}; use api::{PropertyBinding, ReferenceFrame, ReferenceFrameKind, ScrollFrameDisplayItem, ScrollSensitivity}; use api::{Shadow, SpaceAndClipInfo, SpatialId, StackingContext, StickyFrameDisplayItem}; use api::{ClipMode, PrimitiveKeyKind, TransformStyle, YuvColorSpace, YuvData, TempFilterData}; use api::units::*; use crate::clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore}; use crate::clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex}; @@ -791,31 +791,29 @@ impl<'a> DisplayListFlattener<'a> { &mut self, traversal: &mut BuiltDisplayListIter<'a>, pipeline_id: PipelineId, stacking_context: &StackingContext, spatial_node_index: SpatialNodeIndex, origin: LayoutPoint, filters: ItemRange<FilterOp>, filter_datas: &[TempFilterData], - filter_primitives: ItemRange<FilterPrimitive>, is_backface_visible: bool, apply_pipeline_clip: bool, ) { // Avoid doing unnecessary work for empty stacking contexts. if traversal.current_stacking_context_empty() { traversal.skip_current_stacking_context(); return; } let composition_operations = { CompositeOps::new( stacking_context.filter_ops_for_compositing(filters), stacking_context.filter_datas_for_compositing(filter_datas), - stacking_context.filter_primitives_for_compositing(filter_primitives), stacking_context.mix_blend_mode_for_compositing(), ) }; let clip_chain_id = match stacking_context.clip_id { Some(clip_id) => self.id_to_index_mapper.get_clip_chain_id(clip_id), None => ClipChainId::NONE, }; @@ -1177,17 +1175,16 @@ impl<'a> DisplayListFlattener<'a> { self.flatten_stacking_context( &mut subtraversal, pipeline_id, &info.stacking_context, space, info.origin, item.filters(), item.filter_datas(), - item.filter_primitives(), info.is_backface_visible, apply_pipeline_clip, ); return Some(subtraversal); } DisplayItem::PushReferenceFrame(ref info) => { let parent_space = self.get_space(&info.parent_spatial_id); let mut subtraversal = item.sub_iter(); @@ -1307,20 +1304,19 @@ impl<'a> DisplayListFlattener<'a> { let parent_space = self.get_space(&info.parent_spatial_id); self.flatten_sticky_frame( info, parent_space, ); } // Do nothing; these are dummy items for the display list parser - DisplayItem::SetGradientStops | - DisplayItem::SetFilterOps | - DisplayItem::SetFilterData | - DisplayItem::SetFilterPrimitives => {} + DisplayItem::SetGradientStops => {} + DisplayItem::SetFilterOps => {} + DisplayItem::SetFilterData => {} DisplayItem::PopReferenceFrame | DisplayItem::PopStackingContext => { unreachable!("Should have returned in parent method.") } DisplayItem::PushShadow(info) => { let clip_and_scroll = self.get_clip_and_scroll( &info.space_and_clip.clip_id, @@ -1976,81 +1972,16 @@ impl<'a> DisplayListFlattener<'a> { println!("\tis a composite picture for a stacking context with {:?}", filter); } // Run the optimize pass on this picture, to see if we can // collapse opacity and avoid drawing to an off-screen surface. self.prim_store.optimize_picture_if_possible(current_pic_index); } - if !stacking_context.composite_ops.filter_primitives.is_empty() { - let filter_datas = stacking_context.composite_ops.filter_datas.iter() - .map(|filter_data| filter_data.sanitize()) - .map(|filter_data| { - SFilterData { - r_func: SFilterDataComponent::from_functype_values( - filter_data.func_r_type, &filter_data.r_values), - g_func: SFilterDataComponent::from_functype_values( - filter_data.func_g_type, &filter_data.g_values), - b_func: SFilterDataComponent::from_functype_values( - filter_data.func_b_type, &filter_data.b_values), - a_func: SFilterDataComponent::from_functype_values( - filter_data.func_a_type, &filter_data.a_values), - } - }) - .collect(); - - // Sanitize filter inputs - for primitive in &mut stacking_context.composite_ops.filter_primitives { - primitive.sanitize(); - } - - let composite_mode = PictureCompositeMode::SvgFilter( - stacking_context.composite_ops.filter_primitives, - filter_datas, - ); - - let filter_pic_index = PictureIndex(self.prim_store.pictures - .alloc() - .init(PicturePrimitive::new_image( - Some(composite_mode.clone()), - Picture3DContext::Out, - None, - true, - stacking_context.is_backface_visible, - stacking_context.requested_raster_space, - PrimitiveList::new( - vec![cur_instance.clone()], - &self.interners, - ), - stacking_context.spatial_node_index, - None, - PictureOptions::default(), - )) - ); - - current_pic_index = filter_pic_index; - cur_instance = create_prim_instance( - current_pic_index, - Some(composite_mode).into(), - stacking_context.is_backface_visible, - ClipChainId::NONE, - stacking_context.spatial_node_index, - &mut self.interners, - ); - - if cur_instance.is_chased() { - println!("\tis a composite picture for a stacking context with an SVG filter"); - } - - // Run the optimize pass on this picture, to see if we can - // collapse opacity and avoid drawing to an off-screen surface. - self.prim_store.optimize_picture_if_possible(current_pic_index); - } - // Same for mix-blend-mode, except we can skip if this primitive is the first in the parent // stacking context. // From https://drafts.fxtf.org/compositing-1/#generalformula, the formula for blending is: // Cs = (1 - ab) x Cs + ab x Blend(Cb, Cs) // where // Cs = Source color // ab = Backdrop alpha // Cb = Backdrop color @@ -3127,21 +3058,16 @@ impl FlattenedStackingContext { return false; } // If there are filters / mix-blend-mode if !self.composite_ops.filters.is_empty() { return false; } - // If there are svg filters - if !self.composite_ops.filter_primitives.is_empty() { - return false; - } - // We can skip mix-blend modes if they are the first primitive in a stacking context, // see pop_stacking_context for a full explanation. if !self.composite_ops.mix_blend_mode.is_none() && !parent.primitives.is_empty() { return false; } // If backface visibility is explicitly set.
--- a/gfx/wr/webrender/src/filterdata.rs +++ b/gfx/wr/webrender/src/filterdata.rs @@ -117,44 +117,34 @@ impl From<SFilterDataKey> for SFilterDat fn from(item: SFilterDataKey) -> Self { SFilterDataTemplate { data: item.data, gpu_cache_handle: GpuCacheHandle::new(), } } } -impl SFilterData { - pub fn is_identity(&self) -> bool { - self.r_func == SFilterDataComponent::Identity - && self.g_func == SFilterDataComponent::Identity - && self.b_func == SFilterDataComponent::Identity - && self.a_func == SFilterDataComponent::Identity - } - - pub fn update(&self, mut request: GpuDataRequest) { - push_component_transfer_data(&self.r_func, &mut request); - push_component_transfer_data(&self.g_func, &mut request); - push_component_transfer_data(&self.b_func, &mut request); - push_component_transfer_data(&self.a_func, &mut request); - assert!(!self.is_identity()); - } -} - impl SFilterDataTemplate { /// Update the GPU cache for a given filter data template. This may be called multiple /// times per frame, by each primitive reference that refers to this interned /// template. The initial request call to the GPU cache ensures that work is only /// done if the cache entry is invalid (due to first use or eviction). pub fn update( &mut self, frame_state: &mut FrameBuildingState, ) { - if let Some(request) = frame_state.gpu_cache.request(&mut self.gpu_cache_handle) { - self.data.update(request); + if let Some(mut request) = frame_state.gpu_cache.request(&mut self.gpu_cache_handle) { + push_component_transfer_data(&self.data.r_func, &mut request); + push_component_transfer_data(&self.data.g_func, &mut request); + push_component_transfer_data(&self.data.b_func, &mut request); + push_component_transfer_data(&self.data.a_func, &mut request); + assert!(self.data.r_func != SFilterDataComponent::Identity + || self.data.g_func != SFilterDataComponent::Identity + || self.data.b_func != SFilterDataComponent::Identity + || self.data.a_func != SFilterDataComponent::Identity); } } } impl intern::Internable for FilterDataIntern { type Key = SFilterDataKey; type StoreData = SFilterDataTemplate; type InternData = ();
--- a/gfx/wr/webrender/src/gpu_types.rs +++ b/gfx/wr/webrender/src/gpu_types.rs @@ -104,30 +104,16 @@ pub struct BlurInstance { #[repr(C)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct ScalingInstance { pub task_address: RenderTaskAddress, pub src_task_address: RenderTaskAddress, } -#[derive(Debug)] -#[repr(C)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct SvgFilterInstance { - pub task_address: RenderTaskAddress, - pub input_1_task_address: RenderTaskAddress, - pub input_2_task_address: RenderTaskAddress, - pub kind: u16, - pub input_count: u16, - pub generic_int: u16, - pub extra_data_address: GpuCacheAddress, -} - #[derive(Copy, Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)] #[repr(C)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum BorderSegment { TopLeft, TopRight, BottomRight,
--- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -1,25 +1,24 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * 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 api::{MixBlendMode, PipelineId, PremultipliedColorF, FilterPrimitiveKind}; -use api::{PropertyBinding, PropertyBindingId, FilterPrimitive, FontRenderMode}; +use api::{MixBlendMode, PipelineId, PremultipliedColorF}; +use api::{PropertyBinding, PropertyBindingId, FontRenderMode}; use api::{DebugFlags, RasterSpace, ImageKey, ColorF}; use api::units::*; use crate::box_shadow::{BLUR_SAMPLE_SCALE}; use crate::clip::{ClipStore, ClipDataStore, ClipChainInstance}; use crate::clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace, CoordinateSystemId }; use crate::debug_colors; use euclid::{vec3, TypedPoint2D, TypedScale, TypedSize2D, Vector2D, TypedRect}; use euclid::approxeq::ApproxEq; -use crate::filterdata::SFilterData; use crate::frame_builder::{FrameVisibilityContext, FrameVisibilityState}; use crate::intern::ItemUid; use crate::internal_types::{FastHashMap, FastHashSet, PlaneSplitter, Filter}; use crate::frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState, PictureContext}; use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle}; use crate::gpu_types::UvRectKind; use plane_split::{Clipper, Polygon, Splitter}; use crate::prim_store::{SpaceMapper, PrimitiveVisibilityMask, PointKey, PrimitiveTemplateKind}; @@ -1569,76 +1568,16 @@ pub enum PictureCompositeMode { /// Apply a component transfer filter. ComponentTransferFilter(FilterDataHandle), /// Draw to intermediate surface, copy straight across. This /// is used for CSS isolation, and plane splitting. Blit(BlitReason), /// Used to cache a picture as a series of tiles. TileCache { }, - /// Apply an SVG filter - SvgFilter(Vec<FilterPrimitive>, Vec<SFilterData>), -} - -impl PictureCompositeMode { - pub fn inflate_picture_rect(&self, picture_rect: PictureRect, inflation_factor: f32) -> PictureRect { - let mut result_rect = picture_rect; - match self { - PictureCompositeMode::Filter(filter) => match filter { - Filter::Blur(_) => { - result_rect = picture_rect.inflate(inflation_factor, inflation_factor); - }, - Filter::DropShadows(shadows) => { - let mut max_inflation: f32 = 0.0; - for shadow in shadows { - let inflation_factor = shadow.blur_radius.round() * BLUR_SAMPLE_SCALE; - max_inflation = max_inflation.max(inflation_factor); - } - result_rect = picture_rect.inflate(max_inflation, max_inflation); - }, - _ => {} - } - PictureCompositeMode::SvgFilter(primitives, _) => { - let mut output_rects = Vec::with_capacity(primitives.len()); - for (cur_index, primitive) in primitives.iter().enumerate() { - 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) - } - FilterPrimitiveKind::DropShadow(ref primitive) => { - let inflation_factor = primitive.shadow.blur_radius.round() * BLUR_SAMPLE_SCALE; - let input = primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect); - let shadow_rect = input.inflate(inflation_factor, inflation_factor); - input.union(&shadow_rect.translate(&(primitive.shadow.offset * TypedScale::new(1.0)))) - } - FilterPrimitiveKind::Blend(ref primitive) => { - primitive.input1.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect) - .union(&primitive.input2.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect)) - } - FilterPrimitiveKind::Identity(ref primitive) => - primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect), - FilterPrimitiveKind::Opacity(ref primitive) => - primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect), - FilterPrimitiveKind::ColorMatrix(ref primitive) => - primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect), - FilterPrimitiveKind::ComponentTransfer(ref primitive) => - primitive.input.to_index(cur_index).map(|index| output_rects[index]).unwrap_or(picture_rect), - - FilterPrimitiveKind::Flood(..) => picture_rect, - }; - output_rects.push(output_rect); - result_rect = result_rect.union(&output_rect); - } - } - _ => {}, - } - result_rect - } } /// Enum value describing the place of a picture in a 3D context. #[derive(Clone, Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] pub enum Picture3DContext<C> { /// The picture is not a part of 3D context sub-hierarchy. Out, @@ -1994,18 +1933,17 @@ impl PicturePrimitive { pub fn can_use_segments(&self) -> bool { match self.raster_config { // TODO(gw): Support brush segment rendering for filter and mix-blend // shaders. It's possible this already works, but I'm just // applying this optimization to Blit mode for now. Some(RasterConfig { composite_mode: PictureCompositeMode::MixBlend(..), .. }) | Some(RasterConfig { composite_mode: PictureCompositeMode::Filter(..), .. }) | Some(RasterConfig { composite_mode: PictureCompositeMode::ComponentTransferFilter(..), .. }) | - Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { .. }, .. }) | - Some(RasterConfig { composite_mode: PictureCompositeMode::SvgFilter(..), .. }) | + Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { .. }, ..}) | None => { false } Some(RasterConfig { composite_mode: PictureCompositeMode::Blit(reason), ..}) => { reason == BlitReason::CLIP } } } @@ -2499,50 +2437,16 @@ impl PicturePrimitive { device_pixel_scale, PrimitiveVisibilityMask::all(), ); let render_task_id = frame_state.render_tasks.add(picture_task); Some((render_task_id, render_task_id)) } - PictureCompositeMode::SvgFilter(ref primitives, ref filter_datas) => { - let uv_rect_kind = calculate_uv_rect_kind( - &pic_rect, - &transform, - &clipped, - device_pixel_scale, - true, - ); - - let picture_task = RenderTask::new_picture( - RenderTaskLocation::Dynamic(None, clipped.size), - unclipped.size, - pic_index, - clipped.origin, - uv_rect_kind, - surface_spatial_node_index, - device_pixel_scale, - PrimitiveVisibilityMask::all(), - ); - - let picture_task_id = frame_state.render_tasks.add(picture_task); - - let filter_task_id = RenderTask::new_svg_filter( - primitives, - filter_datas, - &mut frame_state.render_tasks, - clipped.size, - uv_rect_kind, - picture_task_id, - device_pixel_scale, - ); - - Some((filter_task_id, picture_task_id)) - } }; if let Some((root, port)) = dep_info { frame_state.surfaces[raster_config.surface_index.0].render_tasks = Some(SurfaceRenderTasks { root, port, }); @@ -2586,18 +2490,17 @@ impl PicturePrimitive { Some(RasterConfig { ref composite_mode, .. }) => { let subpixel_mode = match composite_mode { PictureCompositeMode::TileCache { .. } => { self.tile_cache.as_ref().unwrap().subpixel_mode } PictureCompositeMode::Blit(..) | PictureCompositeMode::ComponentTransferFilter(..) | PictureCompositeMode::Filter(..) | - PictureCompositeMode::MixBlend(..) | - PictureCompositeMode::SvgFilter(..) => { + PictureCompositeMode::MixBlend(..) => { // TODO(gw): We can take advantage of the same logic that // exists in the opaque rect detection for tile // caches, to allow subpixel text on other surfaces // that can be detected as opaque. SubpixelMode::Deny } }; @@ -2833,40 +2736,24 @@ impl PicturePrimitive { if self.options.inflate_if_required { // The amount of extra space needed for primitives inside // this picture to ensure the visibility check is correct. BLUR_SAMPLE_SCALE * blur_radius } else { 0.0 } } - PictureCompositeMode::SvgFilter(ref primitives, _) if self.options.inflate_if_required => { - let mut max = 0.0; - for primitive in primitives { - if let FilterPrimitiveKind::Blur(ref blur) = primitive.kind { - max = f32::max(max, blur.radius * BLUR_SAMPLE_SCALE); - } - } - max - } _ => { 0.0 } }; - // Filters must be applied before transforms, to do this, we can mark this picture as establishing a raster root. - let has_svg_filter = if let PictureCompositeMode::SvgFilter(..) = composite_mode { - true - } else { - false - }; - - // Check if there is perspective or if an SVG filter is applied, and thus whether a new + // Check if there is perspective, and thus whether a new // rasterization root should be established. - let establishes_raster_root = has_svg_filter || frame_context.clip_scroll_tree + let establishes_raster_root = frame_context.clip_scroll_tree .get_relative_transform(surface_spatial_node_index, parent_raster_node_index) .is_perspective(); let surface = SurfaceInfo::new( surface_spatial_node_index, if establishes_raster_root { surface_spatial_node_index } else { @@ -2943,22 +2830,36 @@ impl PicturePrimitive { surface.rect = surface.rect.union(&cluster_rect); } } // If this picture establishes a surface, then map the surface bounding // rect into the parent surface coordinate space, and propagate that up // to the parent. if let Some(ref mut raster_config) = self.raster_config { - let surface = state.current_surface_mut(); - // Inflate the local bounding rect if required by the filter effect. - // This inflaction factor is to be applied to the surface itself. - surface.rect = raster_config.composite_mode.inflate_picture_rect(surface.rect, surface.inflation_factor); - - let mut surface_rect = surface.rect * TypedScale::new(1.0); + let mut surface_rect = { + let surface = state.current_surface_mut(); + // Inflate the local bounding rect if required by the filter effect. + // This inflaction factor is to be applied to the surface itsefl. + // TODO: in prepare_for_render we round before multiplying with the + // blur sample scale. Should we do this here as well? + let inflation_size = match raster_config.composite_mode { + PictureCompositeMode::Filter(Filter::Blur(_)) => surface.inflation_factor, + PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => { + let mut max = 0.0; + for shadow in shadows { + max = f32::max(max, shadow.blur_radius * BLUR_SAMPLE_SCALE); + } + max.ceil() + } + _ => 0.0, + }; + surface.rect = surface.rect.inflate(inflation_size, inflation_size); + surface.rect * TypedScale::new(1.0) + }; // Pop this surface from the stack let surface_index = state.pop_surface(); debug_assert_eq!(surface_index, raster_config.surface_index); // Snapping may change the local rect slightly, and as such should just be // considered an estimated size for determining if we need raster roots and // preparing the tile cache. @@ -3084,18 +2985,17 @@ impl PicturePrimitive { _ => {} } } PictureCompositeMode::ComponentTransferFilter(handle) => { let filter_data = &mut data_stores.filter_data[handle]; filter_data.update(frame_state); } PictureCompositeMode::MixBlend(..) | - PictureCompositeMode::Blit(_) | - PictureCompositeMode::SvgFilter(..) => {} + PictureCompositeMode::Blit(_) => {} } true } } // Calculate a single homogeneous screen-space UV for a picture. fn calculate_screen_uv(
--- a/gfx/wr/webrender/src/prim_store/mod.rs +++ b/gfx/wr/webrender/src/prim_store/mod.rs @@ -5,16 +5,17 @@ use api::{BorderRadius, ClipMode, ColorF}; use api::{ImageRendering, RepeatMode}; use api::{PremultipliedColorF, PropertyBinding, Shadow, GradientStop}; use api::{BoxShadowClipMode, LineStyle, LineOrientation, BorderStyle}; use api::{PrimitiveKeyKind}; use api::units::*; use crate::border::{get_max_scale_for_border, build_border_instances}; use crate::border::BorderSegmentCacheKey; +use crate::box_shadow::{BLUR_SAMPLE_SCALE}; use crate::clip::{ClipStore}; use crate::clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace}; use crate::clip::{ClipDataStore, ClipNodeFlags, ClipChainId, ClipChainInstance, ClipItem}; use crate::debug_colors; use crate::debug_render::DebugItem; use crate::display_list_flattener::{CreateShadow, IsVisible}; use euclid::{SideOffsets2D, TypedTransform3D, TypedRect, TypedScale, TypedSize2D, TypedPoint2D}; use euclid::approxeq::ApproxEq; @@ -2247,17 +2248,28 @@ impl PrimitiveStore { // and stretch size. Drop shadow filters also depend on the local rect // size for the extra GPU cache data handle. // TODO(gw): In future, if we support specifying a flag which gets the // stretch size from the segment rect in the shaders, we can // remove this invalidation here completely. if let Some(ref raster_config) = pic.raster_config { // Inflate the local bounding rect if required by the filter effect. // This inflaction factor is to be applied to the surface itself. - surface_rect = raster_config.composite_mode.inflate_picture_rect(surface_rect, surface.inflation_factor); + let inflation_size = match raster_config.composite_mode { + PictureCompositeMode::Filter(Filter::Blur(_)) => surface.inflation_factor, + PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => { + let mut max = 0.0; + for shadow in shadows { + max = f32::max(max, shadow.blur_radius * BLUR_SAMPLE_SCALE); + } + max.ceil() + } + _ => 0.0, + }; + surface_rect = surface_rect.inflate(inflation_size, inflation_size); // Layout space for the picture is picture space from the // perspective of its child primitives. let pic_local_rect = surface_rect * TypedScale::new(1.0); if pic.snapped_local_rect != pic_local_rect { match raster_config.composite_mode { PictureCompositeMode::Filter(Filter::DropShadows(..)) => { for handle in &pic.extra_gpu_data_handles {
--- a/gfx/wr/webrender/src/prim_store/picture.rs +++ b/gfx/wr/webrender/src/prim_store/picture.rs @@ -1,43 +1,28 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * 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 api::{ - ColorU, MixBlendMode, FilterPrimitiveInput, FilterPrimitiveKind, ColorSpace, + ColorU, MixBlendMode, PropertyBinding, PropertyBindingId, }; use api::units::{Au, LayoutSize, LayoutVector2D}; +use crate::intern::ItemUid; use crate::display_list_flattener::IsVisible; -use crate::filterdata::SFilterData; -use crate::intern::ItemUid; use crate::intern::{Internable, InternDebug, Handle as InternHandle}; use crate::internal_types::{LayoutPrimitiveInfo, Filter}; use crate::picture::PictureCompositeMode; use crate::prim_store::{ PrimKey, PrimKeyCommonData, PrimTemplate, PrimTemplateCommonData, PrimitiveInstanceKind, PrimitiveSceneData, PrimitiveStore, VectorKey, InternablePrimitive, }; -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, MallocSizeOf, PartialEq, Hash, Eq)] -pub enum FilterPrimitiveKey { - Identity(ColorSpace, FilterPrimitiveInput), - Flood(ColorSpace, ColorU), - Blend(ColorSpace, MixBlendMode, FilterPrimitiveInput, FilterPrimitiveInput), - Blur(ColorSpace, Au, FilterPrimitiveInput), - Opacity(ColorSpace, Au, FilterPrimitiveInput), - ColorMatrix(ColorSpace, [Au; 20], FilterPrimitiveInput), - DropShadow(ColorSpace, (VectorKey, Au, ColorU), FilterPrimitiveInput), - ComponentTransfer(ColorSpace, FilterPrimitiveInput, Vec<SFilterData>), -} - /// Represents a hashable description of how a picture primitive /// will be composited into its parent. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(Debug, Clone, MallocSizeOf, PartialEq, Hash, Eq)] pub enum PictureCompositeKey { // No visual compositing effect Identity, @@ -54,17 +39,16 @@ pub enum PictureCompositeKey { Saturate(Au), Sepia(Au), DropShadows(Vec<(VectorKey, Au, ColorU)>), ColorMatrix([Au; 20]), SrgbToLinear, LinearToSrgb, ComponentTransfer(ItemUid), Flood(ColorU), - SvgFilter(Vec<FilterPrimitiveKey>), // MixBlendMode Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, @@ -141,48 +125,16 @@ impl From<Option<PictureCompositeMode>> } Filter::ComponentTransfer => unreachable!(), Filter::Flood(color) => PictureCompositeKey::Flood(color.into()), } } Some(PictureCompositeMode::ComponentTransferFilter(handle)) => { PictureCompositeKey::ComponentTransfer(handle.uid()) } - Some(PictureCompositeMode::SvgFilter(filter_primitives, filter_data)) => { - PictureCompositeKey::SvgFilter(filter_primitives.into_iter().map(|primitive| { - match primitive.kind { - 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::Opacity(opacity) => - FilterPrimitiveKey::Opacity(primitive.color_space, Au::from_f32_px(opacity.opacity), opacity.input), - FilterPrimitiveKind::ColorMatrix(color_matrix) => { - let mut quantized_values: [Au; 20] = [Au(0); 20]; - for (value, result) in color_matrix.matrix.iter().zip(quantized_values.iter_mut()) { - *result = Au::from_f32_px(*value); - } - FilterPrimitiveKey::ColorMatrix(primitive.color_space, quantized_values, color_matrix.input) - } - FilterPrimitiveKind::DropShadow(drop_shadow) => { - FilterPrimitiveKey::DropShadow( - primitive.color_space, - ( - drop_shadow.shadow.offset.into(), - Au::from_f32_px(drop_shadow.shadow.blur_radius), - drop_shadow.shadow.color.into(), - ), - drop_shadow.input, - ) - } - FilterPrimitiveKind::ComponentTransfer(component_transfer) => - FilterPrimitiveKey::ComponentTransfer(primitive.color_space, component_transfer.input, filter_data.clone()), - } - }).collect()) - } Some(PictureCompositeMode::Blit(_)) | Some(PictureCompositeMode::TileCache { .. }) | None => { PictureCompositeKey::Identity } } } }
--- a/gfx/wr/webrender/src/render_task.rs +++ b/gfx/wr/webrender/src/render_task.rs @@ -1,25 +1,24 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * 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 api::{ImageDescriptor, ImageFormat, FilterPrimitive, FilterPrimitiveInput, FilterPrimitiveKind}; -use api::{LineStyle, LineOrientation, ClipMode, DirtyRect, MixBlendMode, ColorF, ColorSpace}; +use api::{ImageDescriptor, ImageFormat}; +use api::{LineStyle, LineOrientation, ClipMode, DirtyRect}; use api::units::*; #[cfg(feature = "pathfinder")] use api::FontRenderMode; use crate::border::BorderSegmentCacheKey; use crate::box_shadow::{BoxShadowCacheKey}; use crate::clip::{ClipDataStore, ClipItem, ClipStore, ClipNodeRange, ClipNodeFlags}; use crate::clip_scroll_tree::SpatialNodeIndex; use crate::device::TextureFilter; #[cfg(feature = "pathfinder")] use euclid::{TypedPoint2D, TypedVector2D}; -use crate::filterdata::SFilterData; use crate::frame_builder::FrameBuilderConfig; use crate::freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; use crate::glyph_rasterizer::GpuGlyphCacheKey; use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle}; use crate::gpu_types::{BorderInstance, ImageSource, UvRectKind, SnapOffsets}; use crate::internal_types::{CacheTextureId, FastHashMap, LayerIndex, SavedTargetIndex, TextureSource}; #[cfg(feature = "pathfinder")] use pathfinder_partitioner::mesh::Mesh; @@ -350,25 +349,25 @@ impl RenderTaskGraph { continue; } // Our dependency is an even number of passes behind, need // to insert a blit to ensure we don't read and write from // the same target. - let child_task_id = RenderTaskId { + let task_id = RenderTaskId { index: child_task_index as u32, #[cfg(debug_assertions)] frame_id: self.frame_id, }; let mut blit = RenderTask::new_blit( - self.tasks[child_task_index].location.size(), - BlitSource::RenderTask { task_id: child_task_id }, + self.tasks[task_index].location.size(), + BlitSource::RenderTask { task_id }, ); // Mark for saving if the blit is more than pass appart from // our task. if child_pass_index < pass_index - 2 { blit.mark_for_saving(); } @@ -378,17 +377,17 @@ impl RenderTaskGraph { frame_id: self.frame_id, }; self.tasks.push(blit); passes[child_pass_index as usize + 1].tasks.push(blit_id); self.tasks[task_index].children[nth_child] = blit_id; - task_redirects[child_task_index] = Some(blit_id); + task_redirects[task_index] = Some(blit_id); } } } pub fn get_task_address(&self, id: RenderTaskId) -> RenderTaskAddress { #[cfg(all(debug_assertions, not(feature = "replay")))] debug_assert_eq!(self.frame_id, id.frame_id); RenderTaskAddress(id.index as u16) @@ -614,43 +613,16 @@ pub struct LineDecorationTask { pub style: LineStyle, pub orientation: LineOrientation, pub local_size: LayoutSize, } #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub enum SvgFilterInfo { - Blend(MixBlendMode), - Flood(ColorF), - LinearToSrgb, - SrgbToLinear, - Opacity(f32), - ColorMatrix(Box<[f32; 20]>), - DropShadow(ColorF), - Offset(DeviceVector2D), - ComponentTransfer(SFilterData), - // TODO: This is used as a hack to ensure that a blur task's input is always in the blur's previous pass. - Identity, -} - -#[derive(Debug)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct SvgFilterTask { - pub info: SvgFilterInfo, - pub extra_gpu_cache_handle: Option<GpuCacheHandle>, - pub uv_rect_handle: GpuCacheHandle, - uv_rect_kind: UvRectKind, -} - -#[derive(Debug)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] pub struct RenderTaskData { pub data: [f32; FLOATS_PER_RENDER_TASK_INFO], } #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum RenderTaskKind { Picture(PictureTask), @@ -661,17 +633,16 @@ pub enum RenderTaskKind { #[allow(dead_code)] Glyph(GlyphTask), Readback(DeviceIntRect), Scaling(ScalingTask), Blit(BlitTask), Border(BorderTask), LineDecoration(LineDecorationTask), Gradient(GradientTask), - SvgFilter(SvgFilterTask), #[cfg(test)] Test(RenderTargetKind), } impl RenderTaskKind { pub fn as_str(&self) -> &'static str { match *self { RenderTaskKind::Picture(..) => "Picture", @@ -681,17 +652,16 @@ impl RenderTaskKind { RenderTaskKind::HorizontalBlur(..) => "HorizontalBlur", RenderTaskKind::Glyph(..) => "Glyph", RenderTaskKind::Readback(..) => "Readback", RenderTaskKind::Scaling(..) => "Scaling", RenderTaskKind::Blit(..) => "Blit", RenderTaskKind::Border(..) => "Border", RenderTaskKind::LineDecoration(..) => "LineDecoration", RenderTaskKind::Gradient(..) => "Gradient", - RenderTaskKind::SvgFilter(..) => "SvgFilter", #[cfg(test)] RenderTaskKind::Test(..) => "Test", } } } #[derive(Debug, Copy, Clone, PartialEq)] #[cfg_attr(feature = "capture", derive(Serialize))] @@ -1197,295 +1167,16 @@ impl RenderTask { RenderTaskKind::Scaling(ScalingTask { target_kind, uv_rect_kind, }), ClearMode::DontCare, ) } - pub fn new_svg_filter( - filter_primitives: &[FilterPrimitive], - filter_datas: &[SFilterData], - render_tasks: &mut RenderTaskGraph, - content_size: DeviceIntSize, - uv_rect_kind: UvRectKind, - original_task_id: RenderTaskId, - device_pixel_scale: DevicePixelScale, - ) -> RenderTaskId { - - if filter_primitives.is_empty() { - return original_task_id; - } - - // Resolves the input to a filter primitive - let get_task_input = | - input: &FilterPrimitiveInput, - filter_primitives: &[FilterPrimitive], - render_tasks: &mut RenderTaskGraph, - cur_index: usize, - outputs: &[RenderTaskId], - original: RenderTaskId, - color_space: ColorSpace, - | { - // TODO(cbrewster): Not sure we can assume that the original input is sRGB. - let (mut task_id, input_color_space) = match input.to_index(cur_index) { - Some(index) => (outputs[index], filter_primitives[index].color_space), - None => (original, ColorSpace::Srgb), - }; - - match (input_color_space, color_space) { - (ColorSpace::Srgb, ColorSpace::LinearRgb) => { - let task = RenderTask::new_svg_filter_primitive( - vec![task_id], - content_size, - uv_rect_kind, - SvgFilterInfo::SrgbToLinear, - ); - task_id = render_tasks.add(task); - }, - (ColorSpace::LinearRgb, ColorSpace::Srgb) => { - let task = RenderTask::new_svg_filter_primitive( - vec![task_id], - content_size, - uv_rect_kind, - SvgFilterInfo::LinearToSrgb, - ); - task_id = render_tasks.add(task); - }, - _ => {}, - } - - task_id - }; - - let mut outputs = vec![]; - let mut cur_filter_data = 0; - for (cur_index, primitive) in filter_primitives.iter().enumerate() { - let render_task_id = match primitive.kind { - FilterPrimitiveKind::Identity(ref identity) => { - // Identity does not create a task, it provides its input's render task - get_task_input( - &identity.input, - filter_primitives, - render_tasks, - cur_index, - &outputs, - original_task_id, - primitive.color_space - ) - } - FilterPrimitiveKind::Blend(ref blend) => { - let input_1_task_id = get_task_input( - &blend.input1, - filter_primitives, - render_tasks, - cur_index, - &outputs, - original_task_id, - primitive.color_space - ); - let input_2_task_id = get_task_input( - &blend.input2, - filter_primitives, - render_tasks, - cur_index, - &outputs, - original_task_id, - primitive.color_space - ); - - let task = RenderTask::new_svg_filter_primitive( - vec![input_1_task_id, input_2_task_id], - content_size, - uv_rect_kind, - SvgFilterInfo::Blend(blend.mode), - ); - render_tasks.add(task) - }, - FilterPrimitiveKind::Flood(ref flood) => { - let task = RenderTask::new_svg_filter_primitive( - vec![], - content_size, - uv_rect_kind, - SvgFilterInfo::Flood(flood.color), - ); - render_tasks.add(task) - } - FilterPrimitiveKind::Blur(ref blur) => { - let blur_std_deviation = blur.radius * device_pixel_scale.0; - let input_task_id = get_task_input( - &blur.input, - filter_primitives, - render_tasks, - cur_index, - &outputs, - original_task_id, - primitive.color_space - ); - - // TODO: This is a hack to ensure that a blur task's input is always in the blur's previous pass. - let svg_task = RenderTask::new_svg_filter_primitive( - vec![input_task_id], - content_size, - uv_rect_kind, - SvgFilterInfo::Identity, - ); - - RenderTask::new_blur( - DeviceSize::new(blur_std_deviation, blur_std_deviation), - render_tasks.add(svg_task), - render_tasks, - RenderTargetKind::Color, - ClearMode::Transparent, - None, - ) - } - FilterPrimitiveKind::Opacity(ref opacity) => { - let input_task_id = get_task_input( - &opacity.input, - filter_primitives, - render_tasks, - cur_index, - &outputs, - original_task_id, - primitive.color_space - ); - - let task = RenderTask::new_svg_filter_primitive( - vec![input_task_id], - content_size, - uv_rect_kind, - SvgFilterInfo::Opacity(opacity.opacity), - ); - render_tasks.add(task) - } - FilterPrimitiveKind::ColorMatrix(ref color_matrix) => { - let input_task_id = get_task_input( - &color_matrix.input, - filter_primitives, - render_tasks, - cur_index, - &outputs, - original_task_id, - primitive.color_space - ); - - let task = RenderTask::new_svg_filter_primitive( - vec![input_task_id], - content_size, - uv_rect_kind, - SvgFilterInfo::ColorMatrix(Box::new(color_matrix.matrix)), - ); - render_tasks.add(task) - } - FilterPrimitiveKind::DropShadow(ref drop_shadow) => { - let input_task_id = get_task_input( - &drop_shadow.input, - filter_primitives, - render_tasks, - cur_index, - &outputs, - original_task_id, - primitive.color_space - ); - - let blur_std_deviation = drop_shadow.shadow.blur_radius * device_pixel_scale.0; - let offset = drop_shadow.shadow.offset * LayoutToWorldScale::new(1.0) * device_pixel_scale; - - let offset_task = RenderTask::new_svg_filter_primitive( - vec![input_task_id], - content_size, - uv_rect_kind, - SvgFilterInfo::Offset(offset), - ); - let offset_task_id = render_tasks.add(offset_task); - - let blur_task_id = RenderTask::new_blur( - DeviceSize::new(blur_std_deviation, blur_std_deviation), - offset_task_id, - render_tasks, - RenderTargetKind::Color, - ClearMode::Transparent, - None, - ); - - let task = RenderTask::new_svg_filter_primitive( - vec![input_task_id, blur_task_id], - content_size, - uv_rect_kind, - SvgFilterInfo::DropShadow(drop_shadow.shadow.color), - ); - render_tasks.add(task) - } - FilterPrimitiveKind::ComponentTransfer(ref component_transfer) => { - let input_task_id = get_task_input( - &component_transfer.input, - filter_primitives, - render_tasks, - cur_index, - &outputs, - original_task_id, - primitive.color_space - ); - - let filter_data = &filter_datas[cur_filter_data]; - cur_filter_data += 1; - if filter_data.is_identity() { - input_task_id - } else { - let task = RenderTask::new_svg_filter_primitive( - vec![input_task_id], - content_size, - uv_rect_kind, - SvgFilterInfo::ComponentTransfer(filter_data.clone()), - ); - render_tasks.add(task) - } - } - }; - outputs.push(render_task_id); - } - - // The output of a filter is the output of the last primitive in the chain. - let mut render_task_id = *outputs.last().unwrap(); - - // Convert to sRGB if needed - if filter_primitives.last().unwrap().color_space == ColorSpace::LinearRgb { - let task = RenderTask::new_svg_filter_primitive( - vec![render_task_id], - content_size, - uv_rect_kind, - SvgFilterInfo::LinearToSrgb, - ); - render_task_id = render_tasks.add(task); - } - - render_task_id - } - - pub fn new_svg_filter_primitive( - tasks: Vec<RenderTaskId>, - target_size: DeviceIntSize, - uv_rect_kind: UvRectKind, - info: SvgFilterInfo, - ) -> Self { - RenderTask::with_dynamic_location( - target_size, - tasks, - RenderTaskKind::SvgFilter(SvgFilterTask { - extra_gpu_cache_handle: None, - uv_rect_handle: GpuCacheHandle::new(), - uv_rect_kind, - info, - }), - ClearMode::Transparent, - ) - } - #[cfg(feature = "pathfinder")] pub fn new_glyph( location: RenderTaskLocation, mesh: Mesh, origin: &DeviceIntPoint, subpixel_offset: &TypedPoint2D<f32, DevicePixel>, render_mode: FontRenderMode, embolden_amount: &TypedVector2D<f32, DevicePixel>, @@ -1520,20 +1211,16 @@ impl RenderTask { RenderTaskKind::HorizontalBlur(ref task) => { task.uv_rect_kind } RenderTaskKind::Scaling(ref task) => { task.uv_rect_kind } - RenderTaskKind::SvgFilter(ref task) => { - task.uv_rect_kind - } - RenderTaskKind::ClipRegion(..) | RenderTaskKind::Glyph(_) | RenderTaskKind::Border(..) | RenderTaskKind::Gradient(..) | RenderTaskKind::LineDecoration(..) | RenderTaskKind::Blit(..) => { UvRectKind::Rect } @@ -1595,25 +1282,16 @@ impl RenderTask { RenderTaskKind::Scaling(..) | RenderTaskKind::Border(..) | RenderTaskKind::LineDecoration(..) | RenderTaskKind::Gradient(..) | RenderTaskKind::Blit(..) => { [0.0; 3] } - - RenderTaskKind::SvgFilter(ref task) => { - match task.info { - SvgFilterInfo::Opacity(opacity) => [opacity, 0.0, 0.0], - SvgFilterInfo::Offset(offset) => [offset.x, offset.y, 0.0], - _ => [0.0; 3] - } - } - #[cfg(test)] RenderTaskKind::Test(..) => { unreachable!(); } }; let (mut target_rect, target_index) = self.get_target_rect(); // The primitives inside a fixed-location render task @@ -1641,19 +1319,16 @@ impl RenderTask { match self.kind { RenderTaskKind::Picture(ref info) => { gpu_cache.get_address(&info.uv_rect_handle) } RenderTaskKind::VerticalBlur(ref info) | RenderTaskKind::HorizontalBlur(ref info) => { gpu_cache.get_address(&info.uv_rect_handle) } - RenderTaskKind::SvgFilter(ref info) => { - gpu_cache.get_address(&info.uv_rect_handle) - } RenderTaskKind::ClipRegion(..) | RenderTaskKind::Readback(..) | RenderTaskKind::Scaling(..) | RenderTaskKind::Blit(..) | RenderTaskKind::Border(..) | RenderTaskKind::CacheMask(..) | RenderTaskKind::Gradient(..) | RenderTaskKind::LineDecoration(..) | @@ -1713,41 +1388,48 @@ impl RenderTask { RenderTargetIndex(layer as usize), ) } } } pub fn target_kind(&self) -> RenderTargetKind { match self.kind { - RenderTaskKind::LineDecoration(..) | - RenderTaskKind::Readback(..) | - RenderTaskKind::Glyph(..) | - RenderTaskKind::Border(..) | - RenderTaskKind::Gradient(..) | - RenderTaskKind::Picture(..) | - RenderTaskKind::Blit(..) | - RenderTaskKind::SvgFilter(..) => { - RenderTargetKind::Color - } + RenderTaskKind::Readback(..) => RenderTargetKind::Color, + + RenderTaskKind::LineDecoration(..) => RenderTargetKind::Color, RenderTaskKind::ClipRegion(..) | RenderTaskKind::CacheMask(..) => { RenderTargetKind::Alpha } RenderTaskKind::VerticalBlur(ref task_info) | RenderTaskKind::HorizontalBlur(ref task_info) => { task_info.target_kind } + RenderTaskKind::Glyph(..) => { + RenderTargetKind::Color + } + RenderTaskKind::Scaling(ref task_info) => { task_info.target_kind } + RenderTaskKind::Border(..) | + RenderTaskKind::Gradient(..) | + RenderTaskKind::Picture(..) => { + RenderTargetKind::Color + } + + RenderTaskKind::Blit(..) => { + RenderTargetKind::Color + } + #[cfg(test)] RenderTaskKind::Test(kind) => kind, } } pub fn write_gpu_blocks( &mut self, gpu_cache: &mut GpuCache, @@ -1757,19 +1439,16 @@ impl RenderTask { let (cache_handle, uv_rect_kind) = match self.kind { RenderTaskKind::HorizontalBlur(ref mut info) | RenderTaskKind::VerticalBlur(ref mut info) => { (&mut info.uv_rect_handle, info.uv_rect_kind) } RenderTaskKind::Picture(ref mut info) => { (&mut info.uv_rect_handle, info.uv_rect_kind) } - RenderTaskKind::SvgFilter(ref mut info) => { - (&mut info.uv_rect_handle, info.uv_rect_kind) - } RenderTaskKind::Readback(..) | RenderTaskKind::Scaling(..) | RenderTaskKind::Blit(..) | RenderTaskKind::ClipRegion(..) | RenderTaskKind::Border(..) | RenderTaskKind::CacheMask(..) | RenderTaskKind::Gradient(..) | RenderTaskKind::LineDecoration(..) | @@ -1789,43 +1468,16 @@ impl RenderTask { p0, p1, texture_layer: target_index.0 as f32, user_data: [0.0; 3], uv_rect_kind, }; image_source.write_gpu_blocks(&mut request); } - - if let RenderTaskKind::SvgFilter(ref mut filter_task) = self.kind { - match filter_task.info { - SvgFilterInfo::ColorMatrix(ref matrix) => { - let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(|| GpuCacheHandle::new()); - if let Some(mut request) = gpu_cache.request(handle) { - for i in 0..5 { - request.push([matrix[i*4], matrix[i*4+1], matrix[i*4+2], matrix[i*4+3]]); - } - } - } - SvgFilterInfo::DropShadow(color) | - SvgFilterInfo::Flood(color) => { - let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(|| GpuCacheHandle::new()); - if let Some(mut request) = gpu_cache.request(handle) { - request.push(color.to_array()); - } - } - SvgFilterInfo::ComponentTransfer(ref data) => { - let handle = filter_task.extra_gpu_cache_handle.get_or_insert_with(|| GpuCacheHandle::new()); - if let Some(request) = gpu_cache.request(handle) { - data.update(request); - } - } - _ => {}, - } - } } #[cfg(feature = "debugger")] pub fn print_with<T: PrintTreePrinter>(&self, pt: &mut T, tree: &RenderTaskGraph) -> bool { match self.kind { RenderTaskKind::Picture(ref task) => { pt.new_level(format!("Picture of {:?}", task.pic_index)); } @@ -1863,28 +1515,23 @@ impl RenderTask { pt.add_item(format!("source: {:?}", task.source)); } RenderTaskKind::Glyph(..) => { pt.new_level("Glyph".to_owned()); } RenderTaskKind::Gradient(..) => { pt.new_level("Gradient".to_owned()); } - RenderTaskKind::SvgFilter(ref task) => { - pt.new_level("SvgFilter".to_owned()); - pt.add_item(format!("primitive: {:?}", task.info)); - } #[cfg(test)] RenderTaskKind::Test(..) => { pt.new_level("Test".to_owned()); } } pt.add_item(format!("clear to: {:?}", self.clear_mode)); - pt.add_item(format!("dimensions: {:?}", self.location.size())); for &child_id in &self.children { if tree[child_id].print_with(pt, tree) { pt.add_item(format!("self: {:?}", child_id)) } } pt.end_level();
--- a/gfx/wr/webrender/src/renderer.rs +++ b/gfx/wr/webrender/src/renderer.rs @@ -58,17 +58,17 @@ use crate::device::query::GpuTimer; use euclid::{rect, Transform3D, TypedScale}; use crate::frame_builder::{ChasePrimitive, FrameBuilderConfig}; use gleam::gl; use crate::glyph_rasterizer::{GlyphFormat, GlyphRasterizer}; use crate::gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList}; use crate::gpu_cache::{GpuCacheDebugChunk, GpuCacheDebugCmd}; #[cfg(feature = "pathfinder")] use crate::gpu_glyph_renderer::GpuGlyphRenderer; -use crate::gpu_types::{PrimitiveHeaderI, PrimitiveHeaderF, ScalingInstance, SvgFilterInstance, TransformData, ResolveInstanceData}; +use crate::gpu_types::{PrimitiveHeaderI, PrimitiveHeaderF, ScalingInstance, TransformData, ResolveInstanceData}; use crate::internal_types::{TextureSource, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError}; use crate::internal_types::{CacheTextureId, DebugOutput, FastHashMap, FastHashSet, LayerIndex, RenderedDocument, ResultMsg}; use crate::internal_types::{TextureCacheAllocationKind, TextureCacheUpdate, TextureUpdateList, TextureUpdateSource}; use crate::internal_types::{RenderTargetInfo, SavedTargetIndex}; use malloc_size_of::MallocSizeOfOps; use crate::picture::{RecordedDirtyRegion, TILE_SIZE_WIDTH, TILE_SIZE_HEIGHT}; use crate::prim_store::DeferredResolve; use crate::profiler::{BackendProfileCounters, FrameProfileCounters, TimeProfileCounter, @@ -215,20 +215,16 @@ const GPU_SAMPLER_TAG_ALPHA: GpuProfileT const GPU_SAMPLER_TAG_OPAQUE: GpuProfileTag = GpuProfileTag { label: "Opaque Pass", color: debug_colors::BLACK, }; const GPU_SAMPLER_TAG_TRANSPARENT: GpuProfileTag = GpuProfileTag { label: "Transparent Pass", color: debug_colors::BLACK, }; -const GPU_TAG_SVG_FILTER: GpuProfileTag = GpuProfileTag { - label: "SvgFilter", - color: debug_colors::LEMONCHIFFON, -}; /// The clear color used for the texture cache when the debug display is enabled. /// We use a shade of blue so that we can still identify completely blue items in /// the texture cache. const TEXTURE_CACHE_DBG_CLEAR_COLOR: [f32; 4] = [0.0, 0.0, 0.8, 1.0]; impl BatchKind { #[cfg(feature = "debugger")] @@ -661,63 +657,16 @@ pub(crate) mod desc { VertexAttribute { name: "aRect", count: 4, kind: VertexAttributeKind::F32, }, ], }; - pub const SVG_FILTER: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[ - VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - ], - instance_attributes: &[ - VertexAttribute { - name: "aFilterRenderTaskAddress", - count: 1, - kind: VertexAttributeKind::U16, - }, - VertexAttribute { - name: "aFilterInput1TaskAddress", - count: 1, - kind: VertexAttributeKind::U16, - }, - VertexAttribute { - name: "aFilterInput2TaskAddress", - count: 1, - kind: VertexAttributeKind::U16, - }, - VertexAttribute { - name: "aFilterKind", - count: 1, - kind: VertexAttributeKind::U16, - }, - VertexAttribute { - name: "aFilterInputCount", - count: 1, - kind: VertexAttributeKind::U16, - }, - VertexAttribute { - name: "aFilterGenericInt", - count: 1, - kind: VertexAttributeKind::U16, - }, - VertexAttribute { - name: "aFilterExtraDataAddress", - count: 2, - kind: VertexAttributeKind::U16, - }, - ], - }; - pub const VECTOR_STENCIL: VertexDescriptor = VertexDescriptor { vertex_attributes: &[ VertexAttribute { name: "aPosition", count: 2, kind: VertexAttributeKind::F32, }, ], @@ -805,17 +754,16 @@ pub(crate) enum VertexArrayKind { Clip, VectorStencil, VectorCover, Border, Scale, LineDecoration, Gradient, Resolve, - SvgFilter, } #[derive(Clone, Debug, PartialEq)] pub enum GraphicsApi { OpenGL, } #[derive(Clone, Debug)] @@ -1099,35 +1047,18 @@ impl TextureResolver { .expect(&format!("BUG: External image should be resolved by now")); device.bind_external_texture(sampler, texture); } TextureSource::TextureCache(index) => { let texture = &self.texture_cache_map[&index]; device.bind_texture(sampler, texture); } TextureSource::RenderTaskCache(saved_index) => { - if saved_index.0 < self.saved_targets.len() { - let texture = &self.saved_targets[saved_index.0]; - device.bind_texture(sampler, texture) - } else { - // Check if this saved index is referring to a the prev pass - if Some(saved_index) == self.prev_pass_color.as_ref().and_then(|at| at.saved_index) { - let texture = match self.prev_pass_color { - Some(ref at) => &at.texture, - None => &self.dummy_cache_texture, - }; - device.bind_texture(sampler, texture); - } else if Some(saved_index) == self.prev_pass_color.as_ref().and_then(|at| at.saved_index) { - let texture = match self.prev_pass_alpha { - Some(ref at) => &at.texture, - None => &self.dummy_cache_texture, - }; - device.bind_texture(sampler, texture); - } - } + let texture = &self.saved_targets[saved_index.0]; + device.bind_texture(sampler, texture) } } } // Get the real (OpenGL) texture ID for a given source texture. // For a texture cache texture, the IDs are stored in a vector // map for fast access. fn resolve(&self, texture_id: &TextureSource) -> Option<&Texture> { @@ -1656,17 +1587,16 @@ pub struct RendererVAOs { prim_vao: VAO, blur_vao: VAO, clip_vao: VAO, border_vao: VAO, line_vao: VAO, scale_vao: VAO, gradient_vao: VAO, resolve_vao: VAO, - svg_filter_vao: VAO, } /// The renderer is responsible for submitting to the GPU the work prepared by the /// RenderBackend. /// /// We have a separate `Renderer` instance for each instance of WebRender (generally /// one per OS window), and all instances share the same thread. @@ -2004,17 +1934,16 @@ impl Renderer { let blur_vao = device.create_vao_with_new_instances(&desc::BLUR, &prim_vao); let clip_vao = device.create_vao_with_new_instances(&desc::CLIP, &prim_vao); let border_vao = device.create_vao_with_new_instances(&desc::BORDER, &prim_vao); let scale_vao = device.create_vao_with_new_instances(&desc::SCALE, &prim_vao); let line_vao = device.create_vao_with_new_instances(&desc::LINE, &prim_vao); let gradient_vao = device.create_vao_with_new_instances(&desc::GRADIENT, &prim_vao); let resolve_vao = device.create_vao_with_new_instances(&desc::RESOLVE, &prim_vao); - let svg_filter_vao = device.create_vao_with_new_instances(&desc::SVG_FILTER, &prim_vao); let texture_cache_upload_pbo = device.create_pbo(); let texture_resolver = TextureResolver::new(&mut device); let prim_header_f_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32); let prim_header_i_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAI32); let transforms_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32); let render_task_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32); @@ -2235,17 +2164,16 @@ impl Renderer { prim_vao, blur_vao, clip_vao, border_vao, scale_vao, gradient_vao, resolve_vao, line_vao, - svg_filter_vao, }, transforms_texture, prim_header_i_texture, prim_header_f_texture, render_task_texture, pipeline_info: PipelineInfo::default(), dither_matrix_texture, external_image_handler: None, @@ -2578,21 +2506,16 @@ impl Renderer { "Vertical Blur", target.vertical_blurs.len(), ); debug_target.add( debug_server::BatchKind::Cache, "Horizontal Blur", target.horizontal_blurs.len(), ); - debug_target.add( - debug_server::BatchKind::Cache, - "SVG Filters", - target.svg_filters.iter().map(|(_, batch)| batch.len()).sum(), - ); for alpha_batch_container in &target.alpha_batch_containers { for batch in alpha_batch_container.opaque_batches.iter().rev() { debug_target.add( debug_server::BatchKind::Opaque, batch.key.kind.debug_name(), batch.instances.len(), ); @@ -3447,43 +3370,16 @@ impl Renderer { self.draw_instanced_batch( &scalings, VertexArrayKind::Scale, &BatchTextures::color(source), stats, ); } - fn handle_svg_filters( - &mut self, - textures: &BatchTextures, - svg_filters: &[SvgFilterInstance], - projection: &Transform3D<f32>, - stats: &mut RendererStats, - ) { - if svg_filters.is_empty() { - return; - } - - let _timer = self.gpu_profile.start_timer(GPU_TAG_SVG_FILTER); - - self.shaders.borrow_mut().cs_svg_filter.bind( - &mut self.device, - &projection, - &mut self.renderer_errors - ); - - self.draw_instanced_batch( - &svg_filters, - VertexArrayKind::SvgFilter, - textures, - stats, - ); - } - fn draw_picture_cache_target( &mut self, target: &PictureCacheTarget, draw_target: DrawTarget, content_origin: DeviceIntPoint, projection: &Transform3D<f32>, render_tasks: &RenderTaskGraph, stats: &mut RendererStats, @@ -3842,25 +3738,16 @@ impl Renderer { self.handle_scaling( &target.scalings, TextureSource::PrevPassColor, projection, stats, ); - for (ref textures, ref filters) in &target.svg_filters { - self.handle_svg_filters( - textures, - filters, - projection, - stats, - ); - } - for alpha_batch_container in &target.alpha_batch_containers { self.draw_alpha_batch_container( alpha_batch_container, draw_target, content_origin, framebuffer_kind, projection, render_tasks, @@ -5222,17 +5109,16 @@ impl Renderer { self.device.delete_vao(self.vaos.prim_vao); self.device.delete_vao(self.vaos.resolve_vao); self.device.delete_vao(self.vaos.clip_vao); self.device.delete_vao(self.vaos.gradient_vao); self.device.delete_vao(self.vaos.blur_vao); self.device.delete_vao(self.vaos.line_vao); self.device.delete_vao(self.vaos.border_vao); self.device.delete_vao(self.vaos.scale_vao); - self.device.delete_vao(self.vaos.svg_filter_vao); self.debug.deinit(&mut self.device); for (_, target) in self.output_targets { self.device.delete_fbo(target.fbo_id); } if let Ok(shaders) = Rc::try_unwrap(self.shaders) { shaders.into_inner().deinit(&mut self.device); @@ -6046,17 +5932,16 @@ fn get_vao<'a>(vertex_array_kind: Vertex VertexArrayKind::Blur => &vaos.blur_vao, VertexArrayKind::VectorStencil => &gpu_glyph_renderer.vector_stencil_vao, VertexArrayKind::VectorCover => &gpu_glyph_renderer.vector_cover_vao, VertexArrayKind::Border => &vaos.border_vao, VertexArrayKind::Scale => &vaos.scale_vao, VertexArrayKind::LineDecoration => &vaos.line_vao, VertexArrayKind::Gradient => &vaos.gradient_vao, VertexArrayKind::Resolve => &vaos.resolve_vao, - VertexArrayKind::SvgFilter => &vaos.svg_filter_vao, } } #[cfg(not(feature = "pathfinder"))] fn get_vao<'a>(vertex_array_kind: VertexArrayKind, vaos: &'a RendererVAOs, _: &'a GpuGlyphRenderer) -> &'a VAO { @@ -6065,17 +5950,16 @@ fn get_vao<'a>(vertex_array_kind: Vertex VertexArrayKind::Clip => &vaos.clip_vao, VertexArrayKind::Blur => &vaos.blur_vao, VertexArrayKind::VectorStencil | VertexArrayKind::VectorCover => unreachable!(), VertexArrayKind::Border => &vaos.border_vao, VertexArrayKind::Scale => &vaos.scale_vao, VertexArrayKind::LineDecoration => &vaos.line_vao, VertexArrayKind::Gradient => &vaos.gradient_vao, VertexArrayKind::Resolve => &vaos.resolve_vao, - VertexArrayKind::SvgFilter => &vaos.svg_filter_vao, } } #[derive(Clone, Copy, PartialEq)] enum FramebufferKind { Main, Other, }
--- a/gfx/wr/webrender/src/scene.rs +++ b/gfx/wr/webrender/src/scene.rs @@ -1,14 +1,14 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * 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 api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch}; -use api::{FilterOp, TempFilterData, FilterData, FilterPrimitive, ComponentTransferFuncType}; +use api::{FilterOp, TempFilterData, FilterData, ComponentTransferFuncType}; use api::{PipelineId, PropertyBinding, PropertyBindingId, ItemRange, MixBlendMode, StackingContext}; use api::units::{LayoutSize, LayoutTransform}; use crate::internal_types::{FastHashMap, Filter}; use std::sync::Arc; /// Stores a map of the animated property bindings for the current display list. These /// can be used to animate the transform and/or opacity of a display list without /// re-submitting the display list itself. @@ -201,20 +201,16 @@ pub trait StackingContextHelpers { fn filter_ops_for_compositing( &self, input_filters: ItemRange<FilterOp>, ) -> Vec<Filter>; fn filter_datas_for_compositing( &self, input_filter_datas: &[TempFilterData], ) -> Vec<FilterData>; - fn filter_primitives_for_compositing( - &self, - input_filter_primitives: ItemRange<FilterPrimitive>, - ) -> Vec<FilterPrimitive>; } impl StackingContextHelpers for StackingContext { fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> { match self.mix_blend_mode { MixBlendMode::Normal => None, _ => Some(self.mix_blend_mode), } @@ -253,20 +249,9 @@ impl StackingContextHelpers for Stacking func_b_type: func_types[2], b_values: temp_filter_data.b_values.iter().collect(), func_a_type: func_types[3], a_values: temp_filter_data.a_values.iter().collect(), }); } filter_datas } - - fn filter_primitives_for_compositing( - &self, - input_filter_primitives: ItemRange<FilterPrimitive>, - ) -> Vec<FilterPrimitive> { - // Resolve these in the flattener? - // TODO(gw): Now that we resolve these later on, - // we could probably make it a bit - // more efficient than cloning these here. - input_filter_primitives.iter().map(|primitive| primitive.into()).collect() - } }
--- a/gfx/wr/webrender/src/shade.rs +++ b/gfx/wr/webrender/src/shade.rs @@ -187,17 +187,16 @@ impl LazilyCompiledShader { VertexArrayKind::Gradient => &desc::GRADIENT, VertexArrayKind::Blur => &desc::BLUR, VertexArrayKind::Clip => &desc::CLIP, VertexArrayKind::VectorStencil => &desc::VECTOR_STENCIL, VertexArrayKind::VectorCover => &desc::VECTOR_COVER, VertexArrayKind::Border => &desc::BORDER, VertexArrayKind::Scale => &desc::SCALE, VertexArrayKind::Resolve => &desc::RESOLVE, - VertexArrayKind::SvgFilter => &desc::SVG_FILTER, }; device.link_program(program, vertex_descriptor)?; device.bind_program(program); match self.kind { ShaderKind::ClipCache => { device.bind_shader_samplers( &program, @@ -507,17 +506,16 @@ pub struct Shaders { // of these shaders are then used by the primitive shaders. pub cs_blur_a8: LazilyCompiledShader, pub cs_blur_rgba8: LazilyCompiledShader, pub cs_border_segment: LazilyCompiledShader, pub cs_border_solid: LazilyCompiledShader, pub cs_scale: LazilyCompiledShader, pub cs_line_decoration: LazilyCompiledShader, pub cs_gradient: LazilyCompiledShader, - pub cs_svg_filter: LazilyCompiledShader, // Brush shaders brush_solid: BrushShader, brush_image: Vec<Option<BrushShader>>, brush_fast_image: Vec<Option<BrushShader>>, brush_blend: BrushShader, brush_mix_blend: BrushShader, brush_yuv_image: Vec<Option<BrushShader>>, @@ -630,24 +628,16 @@ impl Shaders { let cs_blur_rgba8 = LazilyCompiledShader::new( ShaderKind::Cache(VertexArrayKind::Blur), "cs_blur", &["COLOR_TARGET"], device, options.precache_flags, )?; - let cs_svg_filter = LazilyCompiledShader::new( - ShaderKind::Cache(VertexArrayKind::SvgFilter), - "cs_svg_filter", - &[], - device, - options.precache_flags, - )?; - let cs_clip_rectangle_slow = LazilyCompiledShader::new( ShaderKind::ClipCache, "cs_clip_rectangle", &[], device, options.precache_flags, )?; @@ -851,17 +841,16 @@ impl Shaders { Ok(Shaders { cs_blur_a8, cs_blur_rgba8, cs_border_segment, cs_line_decoration, cs_gradient, cs_border_solid, cs_scale, - cs_svg_filter, brush_solid, brush_image, brush_fast_image, brush_blend, brush_mix_blend, brush_yuv_image, brush_radial_gradient, brush_linear_gradient, @@ -936,17 +925,16 @@ impl Shaders { } } } pub fn deinit(self, device: &mut Device) { self.cs_scale.deinit(device); self.cs_blur_a8.deinit(device); self.cs_blur_rgba8.deinit(device); - self.cs_svg_filter.deinit(device); self.brush_solid.deinit(device); self.brush_blend.deinit(device); self.brush_mix_blend.deinit(device); self.brush_radial_gradient.deinit(device); self.brush_linear_gradient.deinit(device); self.cs_clip_rectangle_slow.deinit(device); self.cs_clip_rectangle_fast.deinit(device); self.cs_clip_box_shadow.deinit(device);
--- a/gfx/wr/webrender/src/tiling.rs +++ b/gfx/wr/webrender/src/tiling.rs @@ -1,37 +1,37 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * 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 api::{ColorF, BorderStyle, FilterPrimitive, MixBlendMode, PipelineId, PremultipliedColorF}; +use api::{ColorF, BorderStyle, MixBlendMode, PipelineId, PremultipliedColorF}; use api::{DocumentLayer, FilterData, ImageFormat, LineOrientation}; use api::units::*; #[cfg(feature = "pathfinder")] use api::FontRenderMode; -use crate::batch::{AlphaBatchBuilder, AlphaBatchContainer, BatchTextures, ClipBatcher, resolve_image, BatchBuilder}; +use crate::batch::{AlphaBatchBuilder, AlphaBatchContainer, ClipBatcher, resolve_image, BatchBuilder}; use crate::clip::ClipStore; use crate::clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX}; use crate::debug_render::DebugItem; use crate::device::{Texture}; #[cfg(feature = "pathfinder")] use euclid::{TypedPoint2D, TypedVector2D}; use crate::frame_builder::FrameGlobalResources; -use crate::gpu_cache::{GpuCache, GpuCacheAddress}; -use crate::gpu_types::{BorderInstance, SvgFilterInstance, BlurDirection, BlurInstance, PrimitiveHeaders, ScalingInstance}; +use crate::gpu_cache::{GpuCache}; +use crate::gpu_types::{BorderInstance, BlurDirection, BlurInstance, PrimitiveHeaders, ScalingInstance}; use crate::gpu_types::{TransformData, TransformPalette, ZBufferIdGenerator}; use crate::internal_types::{CacheTextureId, FastHashMap, SavedTargetIndex, TextureSource, Filter}; #[cfg(feature = "pathfinder")] use pathfinder_partitioner::mesh::Mesh; use crate::picture::{RecordedDirtyRegion, SurfaceInfo}; use crate::prim_store::gradient::GRADIENT_FP_STOPS; use crate::prim_store::{PrimitiveStore, DeferredResolve, PrimitiveScratchBuffer, PrimitiveVisibilityMask}; use crate::profiler::FrameProfileCounters; use crate::render_backend::{DataStores, FrameId}; -use crate::render_task::{BlitSource, RenderTaskAddress, RenderTaskId, RenderTaskKind, SvgFilterTask, SvgFilterInfo}; +use crate::render_task::{BlitSource, RenderTaskAddress, RenderTaskId, RenderTaskKind}; use crate::render_task::{BlurTask, ClearMode, GlyphTask, RenderTaskLocation, RenderTaskGraph, ScalingTask}; use crate::resource_cache::ResourceCache; use std::{cmp, usize, f32, i32, mem}; use crate::texture_allocator::{ArrayAllocationTracker, FreeRectSlice}; const STYLE_SOLID: i32 = ((BorderStyle::Solid as i32) << 8) | ((BorderStyle::Solid as i32) << 16); const STYLE_MASK: i32 = 0x00FF_FF00; @@ -356,17 +356,16 @@ pub struct GlyphJob; #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct ColorRenderTarget { pub alpha_batch_containers: Vec<AlphaBatchContainer>, // List of blur operations to apply for this render target. pub vertical_blurs: Vec<BlurInstance>, pub horizontal_blurs: Vec<BlurInstance>, pub readbacks: Vec<DeviceIntRect>, pub scalings: Vec<ScalingInstance>, - pub svg_filters: Vec<(BatchTextures, Vec<SvgFilterInstance>)>, pub blits: Vec<BlitJob>, // List of frame buffer outputs for this render target. pub outputs: Vec<FrameOutput>, alpha_tasks: Vec<RenderTaskId>, screen_size: DeviceIntSize, // Track the used rect of the render target, so that // we can set a scissor rect and only clear to the // used portion of the target as an optimization. @@ -379,17 +378,16 @@ impl RenderTarget for ColorRenderTarget _: bool, ) -> Self { ColorRenderTarget { alpha_batch_containers: Vec::new(), vertical_blurs: Vec::new(), horizontal_blurs: Vec::new(), readbacks: Vec::new(), scalings: Vec::new(), - svg_filters: Vec::new(), blits: Vec::new(), outputs: Vec::new(), alpha_tasks: Vec::new(), screen_size, used_rect: DeviceIntRect::zero(), } } @@ -530,27 +528,16 @@ impl RenderTarget for ColorRenderTarget // store the information necessary to do the copy. if let Some(pipeline_id) = pic.frame_output_pipeline_id { self.outputs.push(FrameOutput { pipeline_id, task_id, }); } } - RenderTaskKind::SvgFilter(ref task_info) => { - task_info.add_instances( - &mut self.svg_filters, - render_tasks, - &task_info.info, - task_id, - task.children.get(0).cloned(), - task.children.get(1).cloned(), - task_info.extra_gpu_cache_handle.map(|handle| gpu_cache.get_address(&handle)), - ) - } RenderTaskKind::ClipRegion(..) | RenderTaskKind::Border(..) | RenderTaskKind::CacheMask(..) | RenderTaskKind::Gradient(..) | RenderTaskKind::LineDecoration(..) => { panic!("Should not be added to color target!"); } RenderTaskKind::Glyph(..) => { @@ -694,18 +681,17 @@ impl RenderTarget for AlphaRenderTarget match task.kind { RenderTaskKind::Readback(..) | RenderTaskKind::Picture(..) | RenderTaskKind::Blit(..) | RenderTaskKind::Border(..) | RenderTaskKind::LineDecoration(..) | RenderTaskKind::Gradient(..) | - RenderTaskKind::Glyph(..) | - RenderTaskKind::SvgFilter(..) => { + RenderTaskKind::Glyph(..) => { panic!("BUG: should not be added to alpha target!"); } RenderTaskKind::VerticalBlur(ref info) => { info.add_instances( &mut self.vertical_blurs, BlurDirection::Vertical, render_tasks.get_task_address(task_id), render_tasks.get_task_address(task.children[0]), @@ -905,18 +891,17 @@ impl TextureCacheRenderTarget { start_stop: [task_info.start_point, task_info.end_point], }); } RenderTaskKind::VerticalBlur(..) | RenderTaskKind::Picture(..) | RenderTaskKind::ClipRegion(..) | RenderTaskKind::CacheMask(..) | RenderTaskKind::Readback(..) | - RenderTaskKind::Scaling(..) | - RenderTaskKind::SvgFilter(..) => { + RenderTaskKind::Scaling(..) => { panic!("BUG: unexpected task kind for texture cache target"); } #[cfg(test)] RenderTaskKind::Test(..) => {} } } #[cfg(feature = "pathfinder")] @@ -1342,33 +1327,28 @@ impl RenderPass { } } #[derive(Debug, Clone, Default)] pub struct CompositeOps { // Requires only a single texture as input (e.g. most filters) pub filters: Vec<Filter>, pub filter_datas: Vec<FilterData>, - pub filter_primitives: Vec<FilterPrimitive>, // Requires two source textures (e.g. mix-blend-mode) pub mix_blend_mode: Option<MixBlendMode>, } impl CompositeOps { - pub fn new( - filters: Vec<Filter>, - filter_datas: Vec<FilterData>, - filter_primitives: Vec<FilterPrimitive>, - mix_blend_mode: Option<MixBlendMode> - ) -> Self { + pub fn new(filters: Vec<Filter>, + filter_datas: Vec<FilterData>, + mix_blend_mode: Option<MixBlendMode>) -> Self { CompositeOps { filters, filter_datas, - filter_primitives, mix_blend_mode, } } pub fn is_empty(&self) -> bool { self.filters.is_empty() && self.filter_datas.is_empty() && self.mix_blend_mode.is_none() } } @@ -1454,105 +1434,8 @@ impl ScalingTask { let instance = ScalingInstance { task_address, src_task_address, }; instances.push(instance); } } - -impl SvgFilterTask { - fn add_instances( - &self, - instances: &mut Vec<(BatchTextures, Vec<SvgFilterInstance>)>, - render_tasks: &RenderTaskGraph, - filter: &SvgFilterInfo, - task_id: RenderTaskId, - input_1_task: Option<RenderTaskId>, - input_2_task: Option<RenderTaskId>, - extra_data_address: Option<GpuCacheAddress>, - ) { - let mut textures = BatchTextures::no_texture(); - - if let Some(saved_index) = input_1_task.map(|id| &render_tasks[id].saved_index) { - textures.colors[0] = match saved_index { - Some(saved_index) => TextureSource::RenderTaskCache(*saved_index), - None => TextureSource::PrevPassColor, - }; - } - - if let Some(saved_index) = input_2_task.map(|id| &render_tasks[id].saved_index) { - textures.colors[1] = match saved_index { - Some(saved_index) => TextureSource::RenderTaskCache(*saved_index), - None => TextureSource::PrevPassColor, - }; - } - - let kind = match filter { - SvgFilterInfo::Blend(..) => 0, - SvgFilterInfo::Flood(..) => 1, - SvgFilterInfo::LinearToSrgb => 2, - SvgFilterInfo::SrgbToLinear => 3, - SvgFilterInfo::Opacity(..) => 4, - SvgFilterInfo::ColorMatrix(..) => 5, - SvgFilterInfo::DropShadow(..) => 6, - SvgFilterInfo::Offset(..) => 7, - SvgFilterInfo::ComponentTransfer(..) => 8, - SvgFilterInfo::Identity => 9, - }; - - let input_count = match filter { - SvgFilterInfo::Flood(..) => 0, - - SvgFilterInfo::LinearToSrgb | - SvgFilterInfo::SrgbToLinear | - SvgFilterInfo::Opacity(..) | - SvgFilterInfo::ColorMatrix(..) | - SvgFilterInfo::Offset(..) | - SvgFilterInfo::ComponentTransfer(..) | - SvgFilterInfo::Identity => 1, - - // Not techincally a 2 input filter, but we have 2 inputs here: original content & blurred content. - SvgFilterInfo::DropShadow(..) | - SvgFilterInfo::Blend(..) => 2, - }; - - let generic_int = match filter { - SvgFilterInfo::Blend(mode) => *mode as u16, - SvgFilterInfo::ComponentTransfer(data) => - ((data.r_func.to_int() << 12 | - data.g_func.to_int() << 8 | - data.b_func.to_int() << 4 | - data.a_func.to_int()) as u16), - - SvgFilterInfo::LinearToSrgb | - SvgFilterInfo::SrgbToLinear | - SvgFilterInfo::Flood(..) | - SvgFilterInfo::Opacity(..) | - SvgFilterInfo::ColorMatrix(..) | - SvgFilterInfo::DropShadow(..) | - SvgFilterInfo::Offset(..) | - SvgFilterInfo::Identity => 0, - }; - - let instance = SvgFilterInstance { - task_address: render_tasks.get_task_address(task_id), - input_1_task_address: input_1_task.map(|id| render_tasks.get_task_address(id)).unwrap_or(RenderTaskAddress(0)), - input_2_task_address: input_2_task.map(|id| render_tasks.get_task_address(id)).unwrap_or(RenderTaskAddress(0)), - kind, - input_count, - generic_int, - extra_data_address: extra_data_address.unwrap_or(GpuCacheAddress::INVALID), - }; - - for (ref mut batch_textures, ref mut batch) in instances.iter_mut() { - if let Some(combined_textures) = batch_textures.combine_textures(textures) { - batch.push(instance); - // Update the batch textures to the newly combined batch textures - *batch_textures = combined_textures; - return; - } - } - - instances.push((textures, vec![instance])); - } -}
--- a/gfx/wr/webrender/tests/angle_shader_validation.rs +++ b/gfx/wr/webrender/tests/angle_shader_validation.rs @@ -59,20 +59,16 @@ const SHADERS: &[Shader] = &[ Shader { name: "cs_gradient", features: CACHE_FEATURES, }, Shader { name: "cs_border_solid", features: CACHE_FEATURES, }, - Shader { - name: "cs_svg_filter", - features: CACHE_FEATURES, - }, // Prim shaders Shader { name: "ps_split_composite", features: PRIM_FEATURES, }, Shader { name: "ps_text_run", features: &[ "", "GLYPH_TRANSFORM" ],
--- a/gfx/wr/webrender_api/src/display_item.rs +++ b/gfx/wr/webrender_api/src/display_item.rs @@ -116,17 +116,16 @@ pub enum DisplayItem { PushReferenceFrame(ReferenceFrameDisplayListItem), PushStackingContext(PushStackingContextDisplayItem), // These marker items indicate an array of data follows, to be used for the // next non-marker item. SetGradientStops, SetFilterOps, SetFilterData, - SetFilterPrimitives, // These marker items terminate a scope introduced by a previous item. PopReferenceFrame, PopStackingContext, PopAllShadows, } /// This is a "complete" version of the DisplayItem, with all implicit trailing @@ -155,17 +154,16 @@ pub enum DebugDisplayItem { StickyFrame(StickyFrameDisplayItem), Iframe(IframeDisplayItem), PushReferenceFrame(ReferenceFrameDisplayListItem), PushStackingContext(PushStackingContextDisplayItem), SetGradientStops(Vec<GradientStop>), SetFilterOps(Vec<FilterOp>), SetFilterData(FilterData), - SetFilterPrimitives(Vec<FilterPrimitive>), PopReferenceFrame, PopStackingContext, PopAllShadows, } #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct ClipDisplayItem { @@ -635,17 +633,17 @@ pub struct PushStackingContextDisplayIte #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct StackingContext { pub transform_style: TransformStyle, pub mix_blend_mode: MixBlendMode, pub clip_id: Option<ClipId>, pub raster_space: RasterSpace, /// True if picture caching should be used on this stacking context. pub cache_tiles: bool, -} // IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>, filter_primitives: Vec<FilterPrimitive> +} // IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData> #[repr(u8)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub enum TransformStyle { Flat = 0, Preserve3D = 1, } @@ -674,17 +672,17 @@ impl RasterSpace { match *self { RasterSpace::Local(scale) => Some(scale), RasterSpace::Screen => None, } } } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub enum MixBlendMode { Normal = 0, Multiply = 1, Screen = 2, Overlay = 3, Darken = 4, Lighten = 5, ColorDodge = 6, @@ -694,182 +692,16 @@ pub enum MixBlendMode { Difference = 10, Exclusion = 11, Hue = 12, Saturation = 13, Color = 14, Luminosity = 15, } -/// An input to a SVG filter primitive. -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] -pub enum ColorSpace { - Srgb, - LinearRgb, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] -pub enum FilterPrimitiveInput { - /// The input is the original graphic that the filter is being applied to. - Original, - /// The input is the output of the previous filter primitive in the filter primitive chain. - Previous, - /// The input is the output of the filter primitive at the given index in the filter primitive chain. - OutputOfPrimitiveIndex(usize), -} - -impl FilterPrimitiveInput { - /// Gets the index of the input. - /// Returns `None` if the source graphic is the input. - pub fn to_index(self, cur_index: usize) -> Option<usize> { - match self { - FilterPrimitiveInput::Previous if cur_index > 0 => Some(cur_index - 1), - FilterPrimitiveInput::OutputOfPrimitiveIndex(index) => Some(index), - _ => None, - } - } -} - -#[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct BlendPrimitive { - pub input1: FilterPrimitiveInput, - pub input2: FilterPrimitiveInput, - pub mode: MixBlendMode, -} - -#[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct FloodPrimitive { - pub color: ColorF, -} - -impl FloodPrimitive { - pub fn sanitize(&mut self) { - self.color.r = self.color.r.min(1.0).max(0.0); - self.color.g = self.color.g.min(1.0).max(0.0); - self.color.b = self.color.b.min(1.0).max(0.0); - self.color.a = self.color.a.min(1.0).max(0.0); - } -} - -#[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct BlurPrimitive { - pub input: FilterPrimitiveInput, - pub radius: f32, -} - -impl BlurPrimitive { - pub fn sanitize(&mut self) { - self.radius = self.radius.min(MAX_BLUR_RADIUS); - } -} - -#[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct OpacityPrimitive { - pub input: FilterPrimitiveInput, - pub opacity: f32, -} - -impl OpacityPrimitive { - pub fn sanitize(&mut self) { - self.opacity = self.opacity.min(1.0).max(0.0); - } -} - -/// cbindgen:derive-eq=false -#[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct ColorMatrixPrimitive { - pub input: FilterPrimitiveInput, - pub matrix: [f32; 20], -} - -#[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct DropShadowPrimitive { - pub input: FilterPrimitiveInput, - pub shadow: Shadow, -} - -impl DropShadowPrimitive { - pub fn sanitize(&mut self) { - self.shadow.blur_radius = self.shadow.blur_radius.min(MAX_BLUR_RADIUS); - } -} - -#[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct ComponentTransferPrimitive { - pub input: FilterPrimitiveInput, - // Component transfer data is stored in FilterData. -} - -#[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct IdentityPrimitive { - pub input: FilterPrimitiveInput, -} - -/// See: https://github.com/eqrion/cbindgen/issues/9 -/// cbindgen:derive-eq=false -#[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub enum FilterPrimitiveKind { - Identity(IdentityPrimitive), - Blend(BlendPrimitive), - Flood(FloodPrimitive), - Blur(BlurPrimitive), - // TODO: Support animated opacity? - Opacity(OpacityPrimitive), - /// cbindgen:derive-eq=false - ColorMatrix(ColorMatrixPrimitive), - DropShadow(DropShadowPrimitive), - ComponentTransfer(ComponentTransferPrimitive), -} - -impl FilterPrimitiveKind { - pub fn sanitize(&mut self) { - match self { - FilterPrimitiveKind::Flood(flood) => flood.sanitize(), - FilterPrimitiveKind::Blur(blur) => blur.sanitize(), - FilterPrimitiveKind::Opacity(opacity) => opacity.sanitize(), - FilterPrimitiveKind::DropShadow(drop_shadow) => drop_shadow.sanitize(), - - // No sanitization needed. - FilterPrimitiveKind::Identity(..) | - FilterPrimitiveKind::Blend(..) | - FilterPrimitiveKind::ColorMatrix(..) | - // Component transfer's filter data is sanitized separately. - FilterPrimitiveKind::ComponentTransfer(..) => {} - } - } -} - -/// SVG Filter Primitive. -/// See: https://github.com/eqrion/cbindgen/issues/9 -/// cbindgen:derive-eq=false -#[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct FilterPrimitive { - pub kind: FilterPrimitiveKind, - pub color_space: ColorSpace, -} - -impl FilterPrimitive { - pub fn sanitize(&mut self) { - self.kind.sanitize(); - } -} - -/// CSS filter. #[repr(C)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub enum FilterOp { /// Filter that does no transformation of the colors, needed for /// debug purposes only. Identity, Blur(f32), Brightness(f32), @@ -1325,17 +1157,16 @@ impl DisplayItem { DisplayItem::PopAllShadows => "pop_all_shadows", DisplayItem::PopReferenceFrame => "pop_reference_frame", DisplayItem::PopStackingContext => "pop_stacking_context", DisplayItem::PushShadow(..) => "push_shadow", DisplayItem::PushReferenceFrame(..) => "push_reference_frame", DisplayItem::PushStackingContext(..) => "push_stacking_context", DisplayItem::SetFilterOps => "set_filter_ops", DisplayItem::SetFilterData => "set_filter_data", - DisplayItem::SetFilterPrimitives => "set_filter_primitives", DisplayItem::RadialGradient(..) => "radial_gradient", DisplayItem::Rectangle(..) => "rectangle", DisplayItem::ScrollFrame(..) => "scroll_frame", DisplayItem::SetGradientStops => "set_gradient_stops", DisplayItem::StickyFrame(..) => "sticky_frame", DisplayItem::Text(..) => "text", DisplayItem::YuvImage(..) => "yuv_image", }
--- a/gfx/wr/webrender_api/src/display_list.rs +++ b/gfx/wr/webrender_api/src/display_list.rs @@ -126,17 +126,16 @@ pub struct BuiltDisplayListDescriptor { pub struct BuiltDisplayListIter<'a> { list: &'a BuiltDisplayList, data: &'a [u8], cur_item: di::DisplayItem, cur_stops: ItemRange<'a, di::GradientStop>, cur_glyphs: ItemRange<'a, GlyphInstance>, cur_filters: ItemRange<'a, di::FilterOp>, cur_filter_data: Vec<TempFilterData<'a>>, - cur_filter_primitives: ItemRange<'a, di::FilterPrimitive>, cur_clip_chain_items: ItemRange<'a, di::ClipId>, cur_complex_clip: ItemRange<'a, di::ComplexClipRegion>, peeking: Peek, /// Should just be initialized but never populated in release builds debug_stats: DebugStats, } /// Internal info used for more detailed analysis of serialized display lists @@ -293,17 +292,16 @@ impl<'a> BuiltDisplayListIter<'a> { BuiltDisplayListIter { list, data, cur_item: di::DisplayItem::PopStackingContext, cur_stops: ItemRange::default(), cur_glyphs: ItemRange::default(), cur_filters: ItemRange::default(), cur_filter_data: Vec::new(), - cur_filter_primitives: ItemRange::default(), cur_clip_chain_items: ItemRange::default(), cur_complex_clip: ItemRange::default(), peeking: Peek::NotPeeking, debug_stats: DebugStats { last_addr: data.as_ptr() as usize, stats: HashMap::default(), } } @@ -332,18 +330,17 @@ impl<'a> BuiltDisplayListIter<'a> { self.cur_complex_clip = ItemRange::default(); self.cur_clip_chain_items = ItemRange::default(); loop { self.next_raw()?; match self.cur_item { SetGradientStops | SetFilterOps | - SetFilterData | - SetFilterPrimitives => { + SetFilterData => { // These are marker items for populating other display items, don't yield them. continue; } _ => { break; } } } @@ -389,20 +386,16 @@ impl<'a> BuiltDisplayListIter<'a> { let data = *self.cur_filter_data.last().unwrap(); self.debug_stats.log_slice("set_filter_data.func_types", &data.func_types); self.debug_stats.log_slice("set_filter_data.r_values", &data.r_values); self.debug_stats.log_slice("set_filter_data.g_values", &data.g_values); self.debug_stats.log_slice("set_filter_data.b_values", &data.b_values); self.debug_stats.log_slice("set_filter_data.a_values", &data.a_values); } - SetFilterPrimitives => { - self.cur_filter_primitives = skip_slice::<di::FilterPrimitive>(&mut self.data); - self.debug_stats.log_slice("set_filter_primitives.primitives", &self.cur_filter_primitives); - } ClipChain(_) => { self.cur_clip_chain_items = skip_slice::<di::ClipId>(&mut self.data); self.debug_stats.log_slice("clip_chain.clip_ids", &self.cur_clip_chain_items); } Clip(_) | ScrollFrame(_) => { self.cur_complex_clip = skip_slice::<di::ComplexClipRegion>(&mut self.data); let name = if let Clip(_) = self.cur_item { "clip.complex_clips" @@ -504,20 +497,16 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> { pub fn filters(&self) -> ItemRange<di::FilterOp> { self.iter.cur_filters } pub fn filter_datas(&self) -> &Vec<TempFilterData> { &self.iter.cur_filter_data } - pub fn filter_primitives(&self) -> ItemRange<di::FilterPrimitive> { - self.iter.cur_filter_primitives - } - pub fn clip_chain_items(&self) -> ItemRange<di::ClipId> { self.iter.cur_clip_chain_items } pub fn display_list(&self) -> &BuiltDisplayList { self.iter.display_list() } @@ -608,19 +597,16 @@ impl Serialize for BuiltDisplayList { func_g_type: func_types[1], g_values: temp_filter_data.g_values.iter().collect(), func_b_type: func_types[2], b_values: temp_filter_data.b_values.iter().collect(), func_a_type: func_types[3], a_values: temp_filter_data.a_values.iter().collect(), }) }, - Real::SetFilterPrimitives => Debug::SetFilterPrimitives( - item.iter.cur_filter_primitives.iter().collect() - ), Real::SetGradientStops => Debug::SetGradientStops( item.iter.cur_stops.iter().collect() ), Real::StickyFrame(v) => Debug::StickyFrame(v), Real::Rectangle(v) => Debug::Rectangle(v), Real::ClearRectangle(v) => Debug::ClearRectangle(v), Real::HitTest(v) => Debug::HitTest(v), Real::Line(v) => Debug::Line(v), @@ -709,20 +695,16 @@ impl<'de> Deserialize<'de> for BuiltDisp filter_data.func_a_type].to_vec(); DisplayListBuilder::push_iter_impl(&mut temp, func_types); DisplayListBuilder::push_iter_impl(&mut temp, filter_data.r_values); DisplayListBuilder::push_iter_impl(&mut temp, filter_data.g_values); DisplayListBuilder::push_iter_impl(&mut temp, filter_data.b_values); DisplayListBuilder::push_iter_impl(&mut temp, filter_data.a_values); Real::SetFilterData }, - Debug::SetFilterPrimitives(filter_primitives) => { - DisplayListBuilder::push_iter_impl(&mut temp, filter_primitives); - Real::SetFilterPrimitives - } Debug::SetGradientStops(stops) => { DisplayListBuilder::push_iter_impl(&mut temp, stops); Real::SetGradientStops }, Debug::Rectangle(v) => Real::Rectangle(v), Debug::ClearRectangle(v) => Real::ClearRectangle(v), Debug::HitTest(v) => Real::HitTest(v), @@ -1438,17 +1420,16 @@ impl DisplayListBuilder { origin: LayoutPoint, spatial_id: di::SpatialId, is_backface_visible: bool, clip_id: Option<di::ClipId>, transform_style: di::TransformStyle, mix_blend_mode: di::MixBlendMode, filters: &[di::FilterOp], filter_datas: &[di::FilterData], - filter_primitives: &[di::FilterPrimitive], raster_space: di::RasterSpace, cache_tiles: bool, ) { if filters.len() > 0 { self.push_item(&di::DisplayItem::SetFilterOps); self.push_iter(filters); } @@ -1459,21 +1440,16 @@ impl DisplayListBuilder { self.push_item(&di::DisplayItem::SetFilterData); self.push_iter(&func_types); self.push_iter(&filter_data.r_values); self.push_iter(&filter_data.g_values); self.push_iter(&filter_data.b_values); self.push_iter(&filter_data.a_values); } - if !filter_primitives.is_empty() { - self.push_item(&di::DisplayItem::SetFilterPrimitives); - self.push_iter(filter_primitives); - } - let item = di::DisplayItem::PushStackingContext(di::PushStackingContextDisplayItem { origin, spatial_id, is_backface_visible, stacking_context: di::StackingContext { transform_style, mix_blend_mode, clip_id, @@ -1487,39 +1463,37 @@ impl DisplayListBuilder { /// Helper for examples/ code. pub fn push_simple_stacking_context( &mut self, origin: LayoutPoint, spatial_id: di::SpatialId, is_backface_visible: bool, ) { - self.push_simple_stacking_context_with_filters(origin, spatial_id, is_backface_visible, &[], &[], &[]); + self.push_simple_stacking_context_with_filters(origin, spatial_id, is_backface_visible, &[], &[]); } /// Helper for examples/ code. pub fn push_simple_stacking_context_with_filters( &mut self, origin: LayoutPoint, spatial_id: di::SpatialId, is_backface_visible: bool, filters: &[di::FilterOp], filter_datas: &[di::FilterData], - filter_primitives: &[di::FilterPrimitive], ) { self.push_stacking_context( origin, spatial_id, is_backface_visible, None, di::TransformStyle::Flat, di::MixBlendMode::Normal, filters, filter_datas, - filter_primitives, di::RasterSpace::Screen, /* cache_tiles = */ false, ); } pub fn pop_stacking_context(&mut self) { self.push_item(&di::DisplayItem::PopStackingContext); }
rename from gfx/wr/wrench/reftests/filters/svg-filter-flood-ref.yaml rename to gfx/wr/wrench/reftests/filters/filter-flood-ref.yaml
rename from gfx/wr/wrench/reftests/filters/svg-filter-flood.yaml rename to gfx/wr/wrench/reftests/filters/filter-flood.yaml
--- a/gfx/wr/wrench/reftests/filters/reftest.list +++ b/gfx/wr/wrench/reftests/filters/reftest.list @@ -39,19 +39,9 @@ platform(linux,mac) == filter-drop-shado == iframe-dropshadow.yaml iframe-dropshadow-ref.yaml skip_on(android) == filter-mix-blend-mode.yaml filter-mix-blend-mode-ref.yaml # Android debug: GL error 502 at blit_framebuffer (emulator) or draw_elements_instanced (Pixel2); Android opt: fails == fuzzy(3,20000) srgb-to-linear.yaml srgb-to-linear-ref.yaml != srgb-to-linear-2.yaml srgb-to-linear-ref.yaml != filter-blur-huge.yaml blank.yaml != filter-drop-shadow-huge.yaml blank.yaml == filter-blur-scaled.yaml filter-blur-scaled-ref.yaml skip_on(android) == filter-blur-scaled-xonly.yaml filter-blur-scaled-xonly.png # fails on Android emulator and Pixel2 -skip_on(android,emulator) == svg-filter-component-transfer.yaml filter-component-transfer-ref.yaml # fails on Android emulator -== svg-filter-flood.yaml svg-filter-flood-ref.yaml -skip_on(android) == svg-filter-blend.yaml svg-filter-blend-ref.yaml -skip_on(android,device) == svg-filter-color-matrix.yaml filter-color-matrix-ref.yaml # fails on Pixel2 -platform(linux,mac) == draw_calls(8) color_targets(8) alpha_targets(0) svg-filter-blur.yaml filter-blur.png # Extra draw call is due to render task graph workaround -platform(linux,mac) == svg-filter-drop-shadow.yaml svg-filter-drop-shadow.png -== fuzzy(1,10000) svg-srgb-to-linear.yaml srgb-to-linear-ref.yaml -platform(linux,mac) == fuzzy(4,28250) svg-filter-drop-shadow-rotate.yaml svg-filter-drop-shadow-rotate-ref.yaml -platform(linux,mac) == svg-filter-blur-transforms.yaml svg-filter-blur-transforms.png -platform(linux,mac) == svg-filter-drop-shadow-on-viewport-edge.yaml svg-filter-drop-shadow-on-viewport-edge.png -platform(linux,mac) == svg-filter-drop-shadow-perspective.yaml svg-filter-drop-shadow-perspective.png +== filter-flood.yaml filter-flood-ref.yaml
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-blend-ref.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -root: - items: - - type: stacking-context - bounds: [0, 0, 50, 250] - items: - - type: rect - bounds: [0, 0, 50, 50] - color: [0, 255, 0, 1] - - type: rect - bounds: [0, 50, 50, 50] - color: [40, 20, 2, 1] - - type: rect - bounds: [0, 100, 50, 50] - color: [20, 10, 155, 1] - - type: rect - bounds: [0, 150, 50, 50] - color: [255, 222, 156, 1] - - type: rect - bounds: [0, 200, 50, 50] - color: [255, 245, 151, 1]
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-blend.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# Tests various blend modes using the blend filter primitive. ---- -root: - items: - - type: stacking-context - bounds: [0, 0, 50, 250] - filter-primitives: - - type: flood - color: [255, 255, 255, 1] - color-space: srgb - - type: blend - in1: original - in2: 0 - color-space: srgb - blend-mode: difference - items: - - type: rect - bounds: [0, 0, 50, 50] - color: [255, 0, 255, 1] - - - type: stacking-context - bounds: [0, 0, 50, 250] - filter-primitives: - - type: flood - color: [51, 51, 51, 1] - color-space: srgb - - type: blend - in1: original - in2: 0 - color-space: srgb - blend-mode: multiply - items: - - type: rect - bounds: [0, 50, 50, 50] - color: [200, 100, 10, 1] - - - type: stacking-context - bounds: [0, 0, 50, 250] - filter-primitives: - - type: flood - color: [255, 10, 156, 1] - color-space: srgb - - type: blend - in1: original - in2: 0 - color-space: srgb - blend-mode: darken - items: - - type: rect - bounds: [0, 100, 50, 50] - color: [20, 222, 155, 1] - - - type: stacking-context - bounds: [0, 0, 50, 250] - filter-primitives: - - type: flood - color: [255, 10, 156, 1] - color-space: srgb - - type: blend - in1: original - in2: 0 - color-space: srgb - blend-mode: lighten - items: - - type: rect - bounds: [0, 150, 50, 50] - color: [20, 222, 155, 1] - - - type: stacking-context - bounds: [0, 0, 50, 250] - filter-primitives: - - type: flood - color: [255, 10, 156, 1] - color-space: srgb - - type: blend - in1: original - in2: 0 - color-space: srgb - blend-mode: exclusion - items: - - type: rect - bounds: [0, 200, 50, 50] - color: [0, 255, 24, 1]
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-blur-transforms.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -root: - items: - - type: stacking-context - bounds: [0, 100, 300, 300] - transform: scale-x(0.1) rotate-z(45) - filter-primitives: - - type: blur - radius: 10 - in: previous - color-space: srgb - items: - - type: rect - color: red - bounds: 0 0 256 256
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-blur.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -root: - items: - - type: stacking-context - bounds: [100, 100, 300, 300] - filter-primitives: - - type: blur - radius: 10 - in: previous - color-space: srgb - items: - - image: "firefox.png" - bounds: 20 20 256 256
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-color-matrix.yaml +++ /dev/null @@ -1,54 +0,0 @@ ---- -root: - items: - - type: stacking-context - bounds: [0, 0, 120, 120] - items: - - type: rect - bounds: [0, 0, 120, 120] - color: [0, 0, 0, 1] - - type: stacking-context - bounds: [10, 10, 50, 50] - filter-primitives: - - type: color-matrix - in: previous - color-space: srgb - matrix: [0.393, 0.686, 0.534, 0, - 0.189, 0.168, 0.131, 0, - 0.349, 0.272, 0, 0, - 0, 0, 0, 1, - 0, 0, 0, 0] - items: - - type: rect - bounds: [0, 0, 50, 50] - color: [255, 0, 0, 1] - - type: stacking-context - bounds: [10, 60, 50, 50] - filter-primitives: - - type: color-matrix - in: previous - color-space: srgb - matrix: [-1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, -1, 0, - 0, 0, 0, 1, - 1, 1, 1, 0] - items: - - type: rect - bounds: [0, 0, 50, 50] - color: [0, 255, 0, 1] - - type: stacking-context - bounds: [60, 10, 50, 50] - filter-primitives: - - type: color-matrix - in: previous - color-space: srgb - matrix: [0, 0, 1, 0, - 0, 1, 0, 0, - 1, 0, 0, 0, - 0, 0, 0, 1, - 0, 0, 0, 0] - items: - - type: rect - bounds: [0, 0, 50, 50] - color: [0, 0, 255, 1]
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-component-transfer.yaml +++ /dev/null @@ -1,128 +0,0 @@ ---- -root: - items: - - type: stacking-context - bounds: [0, 0, 50, 250] - items: - - type: stacking-context - bounds: [0, 0, 50, 50] - filter-primitives: - - type: component-transfer - color-space: srgb - in: previous - filter-datas: - - - - Identity - - Identity - - Identity - - Identity - - [] - - [] - - [] - - [] - items: - - type: rect - bounds: [0, 0, 50, 50] - color: [255, 0, 255, 1] - - type: stacking-context - bounds: [0, 50, 50, 50] - filter-primitives: - - type: component-transfer - color-space: srgb - in: previous - filter-datas: - - - - Table - - Table - - Table - - Identity - - - "1" - - "1" - - "0" - - "0" - - - "0" - - "0" - - "1" - - "1" - - - "0" - - "1" - - "1" - - "0" - - [] - items: - - type: rect - bounds: [0, 0, 50, 50] - color: [173, 255, 47, 1] - - type: stacking-context - bounds: [0, 100, 50, 50] - filter-primitives: - - type: component-transfer - color-space: srgb - in: previous - filter-datas: - - - - Discrete - - Discrete - - Discrete - - Identity - - - "1" - - "1" - - "0" - - "0" - - - "0" - - "0" - - "1" - - "1" - - - "0" - - "1" - - "1" - - "0" - - [] - items: - - type: rect - bounds: [0, 0, 50, 50] - color: [0, 255, 255, 1] - - type: stacking-context - bounds: [0, 150, 50, 50] - filter-primitives: - - type: component-transfer - color-space: srgb - in: previous - filter-datas: - - - - Linear - - Linear - - Linear - - Identity - - - "0.5" - - "0.25" - - - "0.5" - - "0" - - - "0.5" - - "0.5" - - [] - items: - - type: rect - bounds: [0, 0, 50, 50] - color: [255, 255, 0, 1] - - type: stacking-context - bounds: [0, 200, 50, 50] - filter-primitives: - - type: component-transfer - color-space: srgb - in: previous - filter-datas: - - - - Gamma - - Gamma - - Gamma - - Identity - - - "2" - - "5" - - "-1" - - - "2" - - "3" - - "0" - - - "2" - - "1" - - "-1.75" - - [] - items: - - type: rect - bounds: [0, 0, 50, 50] - color: [135, 206, 235, 1]
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-drop-shadow-on-viewport-edge.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -root: - items: - - type: stacking-context - bounds: [10, 10, 400, 400] - filter-primitives: - - type: drop-shadow - offset: [10, 10] - radius: 20 - color: [255, 0, 0, 1] - in: previous - color-space: srgb - items: - - type: rect - bounds: 0 0 256 256 - color: green
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-drop-shadow-perspective.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Tests SVG drop shadows with perspective transforms ---- -root: - items: - - type: stacking-context - perspective: 100 - perspective-origin: 100 50 - items: - - type: "stacking-context" - transform-origin: 0 250 - transform: rotate-x(15) - filter-primitives: - - type: drop-shadow - color: red - offset: [20, 20] - radius: 10 - in: previous - color-space: srgb - items: - - type: rect - color: blue - bounds: 0 0 200 200
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-drop-shadow-rotate-ref.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Tests SVG drop shadows with transforms ---- -root: - items: - - type: stacking-context - bounds: [100, 100, 400, 400] - filters: drop-shadow([73, 73], 20, [255, 0, 0, 1]) - transform: rotate-z(45) - items: - - image: "firefox.png" - bounds: 0 0 256 256
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-drop-shadow-rotate.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# Tests SVG drop shadows with transforms ---- -root: - items: - - type: stacking-context - bounds: [100, 100, 400, 400] - transform: rotate-z(45) - filter-primitives: - - type: drop-shadow - in: previous - offset: [73, 73] - radius: 20 - color: [255, 0, 0, 1] - color-space: srgb - items: - - image: "firefox.png" - bounds: 0 0 256 256
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-filter-drop-shadow.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Tests that SVG drop shadows are working properly ---- -root: - items: - - type: stacking-context - bounds: [100, 100, 400, 400] - filter-primitives: - - type: drop-shadow - in: previous - offset: [73, 73] - radius: 20 - color: [255, 0, 0, 1] - color-space: srgb - items: - - image: "firefox.png" - bounds: 0 0 256 256
deleted file mode 100644 --- a/gfx/wr/wrench/reftests/filters/svg-srgb-to-linear.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# this test ensures that a sRGB -> linear-RGB -> sRGB results in no change (with exception to rounding error) ---- -root: - items: - - type: stacking-context - bounds: [0, 0, 300, 100] - filter-primitives: - - type: identity - in: previous - color-space: linear-rgb - items: - - type: rect - bounds: [100, 0, 100, 100] - color: [200, 200, 200, 1.0] - - type: rect - bounds: [100, 0, 100, 100] - color: [100, 100, 100, 1.0] - - type: rect - bounds: [200, 0, 100, 100] - color: [50, 50, 50, 1.0]
--- a/gfx/wr/wrench/reftests/mask/reftest.list +++ b/gfx/wr/wrench/reftests/mask/reftest.list @@ -5,12 +5,12 @@ skip_on(android,emulator) == nested-mask != mask.yaml green.yaml == aligned-layer-rect.yaml aligned-layer-rect-ref.yaml == mask-transformed-to-empty-rect.yaml mask-transformed-to-empty-rect-ref.yaml platform(linux,mac) == rounded-corners.yaml rounded-corners.png != mask.yaml out-of-bounds.yaml platform(linux,mac) fuzzy(1,17500) color_targets(3) alpha_targets(1) == mask-atomicity.yaml mask-atomicity-ref.yaml platform(linux,mac) fuzzy(1,17500) == mask-atomicity-tiling.yaml mask-atomicity-ref.yaml platform(linux,mac) == mask-perspective.yaml mask-perspective.png -skip_on(android,emulator) == fuzzy(1,7) mask-perspective-tiling.yaml mask-perspective.yaml # Android emulator: GL error 502 at tex_sub_image_3d_pbo, fails on opt +skip_on(android,emulator) == fuzzy(1,6) mask-perspective-tiling.yaml mask-perspective.yaml # Android emulator: GL error 502 at tex_sub_image_3d_pbo, fails on opt platform(linux,mac) == checkerboard.yaml checkerboard.png skip_on(android) == checkerboard.yaml checkerboard-tiling.yaml # Android emulator: GL error 502 at blit_framebuffer, fails on opt emulator and on a Pixel2 == missing-mask.yaml missing-mask-ref.yaml
--- a/gfx/wr/wrench/src/yaml_frame_reader.rs +++ b/gfx/wr/wrench/src/yaml_frame_reader.rs @@ -1876,28 +1876,26 @@ impl YamlFrameReader { if let Some(size) = yaml["scroll-offset"].as_point() { let external_id = ExternalScrollId(0, dl.pipeline_id); self.scroll_offsets.insert(external_id, LayoutPoint::new(size.x, size.y)); } } let filters = yaml["filters"].as_vec_filter_op().unwrap_or(vec![]); let filter_datas = yaml["filter-datas"].as_vec_filter_data().unwrap_or(vec![]); - let filter_primitives = yaml["filter-primitives"].as_vec_filter_primitive().unwrap_or(vec![]); dl.push_stacking_context( bounds.origin, *self.spatial_id_stack.last().unwrap(), info.is_backface_visible, clip_node_id, transform_style, mix_blend_mode, &filters, &filter_datas, - &filter_primitives, raster_space, cache_tiles, ); if !yaml["items"].is_badvalue() { self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]); }
--- a/gfx/wr/wrench/src/yaml_frame_writer.rs +++ b/gfx/wr/wrench/src/yaml_frame_writer.rs @@ -67,24 +67,16 @@ fn color_to_string(value: ColorF) -> Str value.r * 255.0, value.g * 255.0, value.b * 255.0, value.a ) } } -fn filter_input_to_string(input: FilterPrimitiveInput) -> String { - match input { - FilterPrimitiveInput::Original => "original".into(), - FilterPrimitiveInput::Previous => "previous".into(), - FilterPrimitiveInput::OutputOfPrimitiveIndex(index) => index.to_string(), - } -} - fn color_node(parent: &mut Table, key: &str, value: ColorF) { yaml_node(parent, key, Yaml::String(color_to_string(value))); } fn point_node<U>(parent: &mut Table, key: &str, value: &TypedPoint2D<f32, U>) { f32_vec_node(parent, key, &[value.x, value.y]); } @@ -135,20 +127,16 @@ fn f32_node(parent: &mut Table, key: &st fn bool_node(parent: &mut Table, key: &str, value: bool) { yaml_node(parent, key, Yaml::Boolean(value)); } fn table_node(parent: &mut Table, key: &str, value: Table) { yaml_node(parent, key, Yaml::Hash(value)); } -fn filter_input_node(parent: &mut Table, key: &str, value: FilterPrimitiveInput) { - yaml_node(parent, key, Yaml::String(filter_input_to_string(value))); -} - fn string_vec_yaml(value: &[String], check_unique: bool) -> Yaml { if !value.is_empty() && check_unique && array_elements_are_same(value) { Yaml::String(value[0].clone()) } else { Yaml::Array(value.iter().map(|v| Yaml::String(v.clone())).collect()) } } @@ -260,17 +248,16 @@ fn shadow_parameters(shadow: &Shadow) -> } fn write_stacking_context( parent: &mut Table, sc: &StackingContext, properties: &SceneProperties, filter_iter: impl IntoIterator<Item = FilterOp>, filter_data_iter: &[TempFilterData], - filter_primitive_iter: impl IntoIterator<Item = FilterPrimitive>, ) { enum_node(parent, "transform-style", sc.transform_style); let raster_space = match sc.raster_space { RasterSpace::Local(scale) => { format!("local({})", scale) } RasterSpace::Screen => { @@ -357,68 +344,16 @@ fn write_stacking_context( Yaml::Array(g_values), Yaml::Array(b_values), Yaml::Array(a_values), ].to_vec(); filter_datas.push(Yaml::Array(avec)); } yaml_node(parent, "filter-datas", Yaml::Array(filter_datas)); - - // filter primitives - let mut filter_primitives = vec![]; - for filter_primitive in filter_primitive_iter { - let mut table = new_table(); - match filter_primitive.kind { - FilterPrimitiveKind::Identity(identity_primitive) => { - yaml_node(&mut table, "type", Yaml::String("identity".into())); - filter_input_node(&mut table, "in", identity_primitive.input); - } - FilterPrimitiveKind::Blend(blend_primitive) => { - yaml_node(&mut table, "type", Yaml::String("blend".into())); - filter_input_node(&mut table, "in1", blend_primitive.input1); - filter_input_node(&mut table, "in2", blend_primitive.input2); - enum_node(&mut table, "mode", blend_primitive.mode); - } - FilterPrimitiveKind::Flood(flood_primitive) => { - yaml_node(&mut table, "type", Yaml::String("flood".into())); - color_node(&mut table, "color", flood_primitive.color); - } - FilterPrimitiveKind::Blur(blur_primitive) => { - yaml_node(&mut table, "type", Yaml::String("blur".into())); - filter_input_node(&mut table, "in", blur_primitive.input); - f32_node(&mut table, "radius", blur_primitive.radius); - } - FilterPrimitiveKind::Opacity(opacity_primitive) => { - yaml_node(&mut table, "type", Yaml::String("opacity".into())); - filter_input_node(&mut table, "in", opacity_primitive.input); - f32_node(&mut table, "opacity", opacity_primitive.opacity); - } - FilterPrimitiveKind::ColorMatrix(color_matrix_primitive) => { - yaml_node(&mut table, "type", Yaml::String("color-matrix".into())); - filter_input_node(&mut table, "in", color_matrix_primitive.input); - f32_vec_node(&mut table, "matrix", &color_matrix_primitive.matrix); - } - FilterPrimitiveKind::DropShadow(drop_shadow_primitive) => { - yaml_node(&mut table, "type", Yaml::String("drop-shadow".into())); - filter_input_node(&mut table, "in", drop_shadow_primitive.input); - vector_node(&mut table, "offset", &drop_shadow_primitive.shadow.offset); - color_node(&mut table, "color", drop_shadow_primitive.shadow.color); - f32_node(&mut table, "radius", drop_shadow_primitive.shadow.blur_radius); - } - FilterPrimitiveKind::ComponentTransfer(component_transfer_primitive) => { - yaml_node(&mut table, "type", Yaml::String("component-transfer".into())); - filter_input_node(&mut table, "in", component_transfer_primitive.input); - } - } - enum_node(&mut table, "color-space", filter_primitive.color_space); - filter_primitives.push(Yaml::Hash(table)); - } - - yaml_node(parent, "filter-primitives", Yaml::Array(filter_primitives)); } #[cfg(target_os = "macos")] fn native_font_handle_to_yaml( rsrc: &mut ResourceGenerator, handle: &NativeFontHandle, parent: &mut yaml_rust::yaml::Hash, path_opt: &mut Option<PathBuf>, @@ -1225,17 +1160,16 @@ impl YamlFrameWriter { point_node(&mut v, "origin", &item.origin); bool_node(&mut v, "backface-visible", item.is_backface_visible); write_stacking_context( &mut v, &item.stacking_context, &scene.properties, base.filters(), base.filter_datas(), - base.filter_primitives(), ); let mut sub_iter = base.sub_iter(); self.write_display_list(&mut v, display_list, scene, &mut sub_iter, clip_id_mapper); continue_traversal = Some(sub_iter); } DisplayItem::PushReferenceFrame(item) => { str_node(&mut v, "type", "reference-frame"); @@ -1338,21 +1272,19 @@ impl YamlFrameWriter { Yaml::Real(item.previously_applied_offset.y.to_string()), ]; yaml_node(&mut v, "previously-applied-offset", Yaml::Array(applied)); } DisplayItem::PopReferenceFrame | DisplayItem::PopStackingContext => return, - DisplayItem::SetGradientStops | - DisplayItem::SetFilterOps | - DisplayItem::SetFilterData | - DisplayItem::SetFilterPrimitives => panic!("dummy item yielded?"), - + DisplayItem::SetGradientStops => panic!("dummy item yielded?"), + DisplayItem::SetFilterOps => panic!("dummy item yielded?"), + DisplayItem::SetFilterData => panic!("dummy item yielded?"), DisplayItem::PushShadow(item) => { str_node(&mut v, "type", "shadow"); vector_node(&mut v, "offset", &item.shadow.offset); color_node(&mut v, "color", item.shadow.color); f32_node(&mut v, "blur-radius", item.shadow.blur_radius); } DisplayItem::PopAllShadows => { str_node(&mut v, "type", "pop-all-shadows");
--- a/gfx/wr/wrench/src/yaml_helper.rs +++ b/gfx/wr/wrench/src/yaml_helper.rs @@ -33,20 +33,16 @@ pub trait YamlHelper { fn as_transform_style(&self) -> Option<TransformStyle>; fn as_raster_space(&self) -> Option<RasterSpace>; fn as_clip_mode(&self) -> Option<ClipMode>; fn as_mix_blend_mode(&self) -> Option<MixBlendMode>; fn as_filter_op(&self) -> Option<FilterOp>; fn as_vec_filter_op(&self) -> Option<Vec<FilterOp>>; fn as_filter_data(&self) -> Option<FilterData>; fn as_vec_filter_data(&self) -> Option<Vec<FilterData>>; - fn as_filter_input(&self) -> Option<FilterPrimitiveInput>; - fn as_filter_primitive(&self) -> Option<FilterPrimitive>; - fn as_vec_filter_primitive(&self) -> Option<Vec<FilterPrimitive>>; - fn as_color_space(&self) -> Option<ColorSpace>; } fn string_to_color(color: &str) -> Option<ColorF> { match color { "red" => Some(ColorF::new(1.0, 0.0, 0.0, 1.0)), "green" => Some(ColorF::new(0.0, 1.0, 0.0, 1.0)), "blue" => Some(ColorF::new(0.0, 0.0, 1.0, 1.0)), "white" => Some(ColorF::new(1.0, 1.0, 1.0, 1.0)), @@ -151,24 +147,16 @@ define_string_enum!( Identity = "Identity", Table = "Table", Discrete = "Discrete", Linear = "Linear", Gamma = "Gamma" ] ); -define_string_enum!( - ColorSpace, - [ - Srgb = "srgb", - LinearRgb = "linear-rgb" - ] -); - // Rotate around `axis` by `degrees` angle fn make_rotation( origin: &LayoutPoint, degrees: f32, axis_x: f32, axis_y: f32, axis_z: f32, ) -> LayoutTransform { @@ -681,115 +669,16 @@ impl YamlHelper for Yaml { } } } } } None } - fn as_filter_input(&self) -> Option<FilterPrimitiveInput> { - if let Some(input) = self.as_str() { - match input { - "original" => Some(FilterPrimitiveInput::Original), - "previous" => Some(FilterPrimitiveInput::Previous), - _ => None, - } - } else if let Some(index) = self.as_i64() { - if index >= 0 { - Some(FilterPrimitiveInput::OutputOfPrimitiveIndex(index as usize)) - } else { - panic!("Filter input index cannot be negative"); - } - } else { - panic!("Invalid filter input"); - } - } - fn as_vec_filter_data(&self) -> Option<Vec<FilterData>> { if let Some(v) = self.as_vec() { Some(v.iter().map(|x| x.as_filter_data().unwrap()).collect()) } else { self.as_filter_data().map(|data| vec![data]) } } - - fn as_filter_primitive(&self) -> Option<FilterPrimitive> { - if let Some(filter_type) = self["type"].as_str() { - let kind = match filter_type { - "identity" => { - FilterPrimitiveKind::Identity(IdentityPrimitive { - input: self["in"].as_filter_input().unwrap(), - }) - } - "blend" => { - FilterPrimitiveKind::Blend(BlendPrimitive { - input1: self["in1"].as_filter_input().unwrap(), - input2: self["in2"].as_filter_input().unwrap(), - mode: self["blend-mode"].as_mix_blend_mode().unwrap(), - }) - } - "flood" => { - FilterPrimitiveKind::Flood(FloodPrimitive { - color: self["color"].as_colorf().unwrap(), - }) - } - "blur" => { - FilterPrimitiveKind::Blur(BlurPrimitive { - input: self["in"].as_filter_input().unwrap(), - radius: self["radius"].as_f32().unwrap(), - }) - } - "opacity" => { - FilterPrimitiveKind::Opacity(OpacityPrimitive { - input: self["in"].as_filter_input().unwrap(), - opacity: self["opacity"].as_f32().unwrap(), - }) - } - "color-matrix" => { - let m: Vec<f32> = self["matrix"].as_vec_f32().unwrap(); - let mut matrix: [f32; 20] = [0.0; 20]; - matrix.clone_from_slice(&m); - - FilterPrimitiveKind::ColorMatrix(ColorMatrixPrimitive { - input: self["in"].as_filter_input().unwrap(), - matrix, - }) - } - "drop-shadow" => { - FilterPrimitiveKind::DropShadow(DropShadowPrimitive { - input: self["in"].as_filter_input().unwrap(), - shadow: Shadow { - offset: self["offset"].as_vector().unwrap(), - color: self["color"].as_colorf().unwrap(), - blur_radius: self["radius"].as_f32().unwrap(), - } - }) - } - "component-transfer" => { - FilterPrimitiveKind::ComponentTransfer(ComponentTransferPrimitive { - input: self["in"].as_filter_input().unwrap(), - }) - } - _ => return None, - }; - - Some(FilterPrimitive { - kind, - color_space: self["color-space"].as_color_space().unwrap_or(ColorSpace::LinearRgb), - }) - } else { - None - } - } - - fn as_vec_filter_primitive(&self) -> Option<Vec<FilterPrimitive>> { - if let Some(v) = self.as_vec() { - Some(v.iter().map(|x| x.as_filter_primitive().unwrap()).collect()) - } else { - self.as_filter_primitive().map(|data| vec![data]) - } - } - - fn as_color_space(&self) -> Option<ColorSpace> { - self.as_str().and_then(|x| StringEnum::from_str(x)) - } }