From f5371109bc3993183826db7e495ff5351ee1cecb Mon Sep 17 00:00:00 2001 From: Eitan Isaacson Date: Fri, 5 Jan 2018 14:02:12 -0800 Subject: [PATCH] Introduce color matrix filter. --- webrender/res/ps_blend.glsl | 17 ++++++- webrender/src/batch.rs | 3 +- webrender/src/picture.rs | 18 +++++-- webrender/src/scene.rs | 9 +++- webrender_api/src/display_item.rs | 1 + .../filters/filter-color-matrix-ref.yaml | 21 ++++++++ .../reftests/filters/filter-color-matrix.yaml | 49 +++++++++++++++++++ wrench/reftests/filters/reftest.list | 1 + wrench/src/yaml_frame_writer.rs | 3 ++ wrench/src/yaml_helper.rs | 6 +++ 10 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 wrench/reftests/filters/filter-color-matrix-ref.yaml create mode 100644 wrench/reftests/filters/filter-color-matrix.yaml diff --git a/webrender/res/ps_blend.glsl b/webrender/res/ps_blend.glsl index 507a59dc29..565c91d0cf 100644 --- a/webrender/res/ps_blend.glsl +++ b/webrender/res/ps_blend.glsl @@ -9,6 +9,7 @@ flat varying vec4 vUvBounds; flat varying float vAmount; flat varying int vOp; flat varying mat4 vColorMat; +flat varying vec4 vColorOffset; #ifdef WR_VERTEX_SHADER void main(void) { @@ -50,6 +51,7 @@ void main(void) { vec4(lumG - lumG * oneMinusAmount, lumG + oneMinusLumG * oneMinusAmount, lumG - lumG * oneMinusAmount, 0.0), vec4(lumB - lumB * oneMinusAmount, lumB - lumB * oneMinusAmount, lumB + oneMinusLumB * oneMinusAmount, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + vColorOffset = vec4(0.0); break; } case 3: { @@ -60,6 +62,7 @@ void main(void) { vec4(lumG - lumG * c - lumG * s, lumG + oneMinusLumG * c + 0.140 * s, lumG - lumG * c + lumG * s, 0.0), vec4(lumB - lumB * c + oneMinusLumB * s, lumB - lumB * c - 0.283 * s, lumB + oneMinusLumB * c + lumB * s, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + vColorOffset = vec4(0.0); break; } case 5: { @@ -68,6 +71,7 @@ void main(void) { vec4(oneMinusAmount * lumG, oneMinusAmount * lumG + vAmount, oneMinusAmount * lumG, 0.0), vec4(oneMinusAmount * lumB, oneMinusAmount * lumB, oneMinusAmount * lumB + vAmount, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + vColorOffset = vec4(0.0); break; } case 6: { @@ -76,8 +80,19 @@ void main(void) { vec4(0.769 - 0.769 * oneMinusAmount, 0.686 + 0.314 * oneMinusAmount, 0.534 - 0.534 * oneMinusAmount, 0.0), vec4(0.189 - 0.189 * oneMinusAmount, 0.168 - 0.168 * oneMinusAmount, 0.131 + 0.869 * oneMinusAmount, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + vColorOffset = vec4(0.0); break; } + case 10: { + // Color Matrix + const int dataOffset = 2; // Offset in GPU cache where matrix starts + vec4 data[8] = fetch_from_resource_cache_8(ci.user_data2); + + vColorMat = mat4(data[dataOffset], data[dataOffset + 1], + data[dataOffset + 2], data[dataOffset + 3]); + vColorOffset = data[dataOffset + 4]; + break; + } } @@ -137,7 +152,7 @@ void main(void) { oFragColor = Opacity(Cs, vAmount); break; default: - oFragColor = vColorMat * Cs; + oFragColor = vColorMat * Cs + vColorOffset; } // Pre-multiply the alpha into the output value. diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 682249faf1..59cd6cb6b1 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -1043,6 +1043,7 @@ impl AlphaBatcher { FilterOp::Brightness(amount) => (7, amount), FilterOp::Opacity(_, amount) => (8, amount), FilterOp::DropShadow(..) => unreachable!(), + FilterOp::ColorMatrix(_) => (10, 0.0), }; let amount = (amount * 65535.0).round() as i32; @@ -1055,7 +1056,7 @@ impl AlphaBatcher { filter_mode, amount, z, - 0, + prim_cache_address.as_int(), 0, ); diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index 545d143bda..5ebcb8755e 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -595,9 +595,21 @@ impl PicturePrimitive { pub fn write_gpu_blocks(&self, request: &mut GpuDataRequest) { match self.kind { - PictureKind::TextShadow { .. } | - PictureKind::Image { .. } => { - request.push([0.0; 4]); + PictureKind::TextShadow { .. } => { + request.push([0.0; 4]) + } + PictureKind::Image { composite_mode, .. } => { + match composite_mode { + Some(PictureCompositeMode::Filter(FilterOp::ColorMatrix(m))) => { + // When we start pushing Image pictures through the brush path + // this may need to change as the number of GPU blocks written will + // need to be determinate. + for i in 0..5 { + request.push([m[i], m[i+5], m[i+10], m[i+15]]); + } + }, + _ => request.push([0.0; 4]), + } } PictureKind::BoxShadow { color, .. } => { request.push(color.premultiplied()); diff --git a/webrender/src/scene.rs b/webrender/src/scene.rs index 0ae9dadf40..16c77cb59c 100644 --- a/webrender/src/scene.rs +++ b/webrender/src/scene.rs @@ -171,7 +171,8 @@ impl FilterOpHelpers for FilterOp { FilterOp::Invert(..) | FilterOp::Saturate(..) | FilterOp::Sepia(..) | - FilterOp::DropShadow(..) => true, + FilterOp::DropShadow(..) | + FilterOp::ColorMatrix(..) => true, FilterOp::Opacity(_, amount) => { amount > OPACITY_EPSILON } @@ -191,6 +192,12 @@ impl FilterOpHelpers for FilterOp { FilterOp::Sepia(amount) => amount == 0.0, FilterOp::DropShadow(offset, blur, _) => { offset.x == 0.0 && offset.y == 0.0 && blur == 0.0 + }, + FilterOp::ColorMatrix(matrix) => { + matrix == [1.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 1.0, 0.0] } } } diff --git a/webrender_api/src/display_item.rs b/webrender_api/src/display_item.rs index 1701e8359d..90e83526c1 100644 --- a/webrender_api/src/display_item.rs +++ b/webrender_api/src/display_item.rs @@ -504,6 +504,7 @@ pub enum FilterOp { Saturate(f32), Sepia(f32), DropShadow(LayoutVector2D, f32, ColorF), + ColorMatrix([f32; 20]), } #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] diff --git a/wrench/reftests/filters/filter-color-matrix-ref.yaml b/wrench/reftests/filters/filter-color-matrix-ref.yaml new file mode 100644 index 0000000000..1cdd496f2e --- /dev/null +++ b/wrench/reftests/filters/filter-color-matrix-ref.yaml @@ -0,0 +1,21 @@ +--- +root: + items: + - type: stacking-context + bounds: [0, 0, 120, 120] + items: + - type: rect + bounds: [0, 0, 120, 120] + color: [0, 0, 0, 1] + - type: rect + bounds: [10, 10, 50, 50] + color: [100, 175, 136, 1] + - type: rect + bounds: [10, 60, 50, 50] + color: [255, 0, 255, 1] + - type: rect + bounds: [60, 10, 50, 50] + color: [255, 0, 0, 1] + - type: rect + bounds: [60, 60, 50, 50] + color: [128, 128, 128, 1] diff --git a/wrench/reftests/filters/filter-color-matrix.yaml b/wrench/reftests/filters/filter-color-matrix.yaml new file mode 100644 index 0000000000..ac0e25598d --- /dev/null +++ b/wrench/reftests/filters/filter-color-matrix.yaml @@ -0,0 +1,49 @@ +--- +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] + filters: color-matrix( 0.393, 0.189, 0.349, 0, 0, + 0.686, 0.168, 0.272, 0, 0, + 0.534, 0.131, 0, 0, 0, + 0, 0, 0, 1, 0 ) + items: + - type: rect + bounds: [0, 0, 50, 50] + color: [255, 0, 0, 1] + - type: stacking-context + bounds: [10, 60, 50, 50] + filters: color-matrix( -1, 0, 0, 0, 1, + 0, -1, 0, 0, 1, + 0, 0, -1, 0, 1, + 0, 0, 0, 1, 0 ) + items: + - type: rect + bounds: [0, 0, 50, 50] + color: [0, 255, 0, 1] + - type: stacking-context + bounds: [60, 10, 50, 50] + filters: color-matrix( 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 1, 0 ) + items: + - type: rect + bounds: [0, 0, 50, 50] + color: [0, 0, 255, 1] + - type: stacking-context + bounds: [60, 60, 50, 50] + filters: color-matrix( 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0.5, 0 ) + items: + - type: rect + bounds: [0, 0, 50, 50] + color: [255, 255, 255, 1] diff --git a/wrench/reftests/filters/reftest.list b/wrench/reftests/filters/reftest.list index da32d675a5..803f7eabc8 100644 --- a/wrench/reftests/filters/reftest.list +++ b/wrench/reftests/filters/reftest.list @@ -9,6 +9,7 @@ == filter-brightness-2.yaml filter-brightness-2-ref.yaml == filter-brightness-3.yaml filter-brightness-3-ref.yaml == filter-brightness-4.yaml filter-brightness-4-ref.yaml +== filter-color-matrix.yaml filter-color-matrix-ref.yaml == filter-contrast-gray-alpha-1.yaml filter-contrast-gray-alpha-1-ref.yaml == filter-invert.yaml filter-invert-ref.yaml == filter-invert-2.yaml filter-invert-2-ref.yaml diff --git a/wrench/src/yaml_frame_writer.rs b/wrench/src/yaml_frame_writer.rs index bbb0470569..a6f8e04eaf 100644 --- a/wrench/src/yaml_frame_writer.rs +++ b/wrench/src/yaml_frame_writer.rs @@ -215,6 +215,9 @@ fn write_sc(parent: &mut Table, sc: &StackingContext, properties: &SceneProperti blur, color_to_string(color)))) } + FilterOp::ColorMatrix(matrix) => { + filters.push(Yaml::String(format!("color-matrix({:?})", matrix))) + } } } diff --git a/wrench/src/yaml_helper.rs b/wrench/src/yaml_helper.rs index 60ce06d099..c578fcb6ab 100644 --- a/wrench/src/yaml_helper.rs +++ b/wrench/src/yaml_helper.rs @@ -560,6 +560,12 @@ impl YamlHelper for Yaml { yaml["blur-radius"].as_f32().unwrap(), yaml["color"].as_colorf().unwrap())) } + ("color-matrix", ref args, _) if args.len() == 20 => { + let m: Vec = args.iter().map(|f| f.parse().unwrap()).collect(); + let mut matrix: [f32; 20] = [0.0; 20]; + matrix.clone_from_slice(&m); + Some(FilterOp::ColorMatrix(matrix)) + } (_, _, _) => None, } } else {