Skip to content

Commit dd0ac12

Browse files
s3bkpcwalton
authored andcommitted
Add ColorMatrix filter
1 parent 448ede2 commit dd0ac12

File tree

17 files changed

+596
-194
lines changed

17 files changed

+596
-194
lines changed

color/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use std::f32::consts::PI;
1313
use std::fmt::{self, Debug, Formatter};
1414
use std::slice;
1515

16+
pub mod matrix;
17+
1618
// TODO(pcwalton): Maybe this should be a u32? Need to be aware of endianness issues if we do that.
1719
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1820
#[repr(C)]

color/src/matrix.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// pathfinder/color/src/lib.rs
2+
//
3+
// Copyright © 2020 The Pathfinder Project Developers.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use pathfinder_simd::default::F32x4;
12+
use std::ops::{Add, Mul, Deref};
13+
14+
/// ColorMatrix filter/transformation
15+
///
16+
/// The entries are stored in 5 columns of F32x4, each containing a row.
17+
#[derive(Copy, Clone, Debug, PartialEq)]
18+
pub struct ColorMatrix(pub [F32x4; 5]);
19+
20+
impl ColorMatrix {
21+
#[inline]
22+
pub fn from_rows(rows: [[f32; 5]; 4]) -> ColorMatrix {
23+
ColorMatrix([
24+
F32x4::new(rows[0][0], rows[1][0], rows[2][0], rows[3][0]),
25+
F32x4::new(rows[0][1], rows[1][1], rows[2][1], rows[3][1]),
26+
F32x4::new(rows[0][2], rows[1][2], rows[2][2], rows[3][2]),
27+
F32x4::new(rows[0][3], rows[1][3], rows[2][3], rows[3][3]),
28+
F32x4::new(rows[0][4], rows[1][4], rows[2][4], rows[3][4]),
29+
])
30+
}
31+
32+
/// Creates a hue-rotate color matrix filter from the given angle in radians.
33+
///
34+
/// See the `hueRotate` attribute of the `feColorMatrix` element in the SVG specification.
35+
pub fn hue_rotate(angle: f32) -> ColorMatrix {
36+
let a = ColorMatrix::from_rows([
37+
[ 0.213, 0.715, 0.072, 0.0, 0.0],
38+
[ 0.213, 0.715, 0.072, 0.0, 0.0],
39+
[ 0.213, 0.715, 0.072, 0.0, 0.0],
40+
[ 0.0, 0.0, 0.0, 1.0, 0.0],
41+
]);
42+
let b = ColorMatrix::from_rows([
43+
[ 0.787, -0.715, -0.072, 0.0, 0.0],
44+
[-0.213, 0.285, -0.072, 0.0, 0.0],
45+
[-0.213, -0.715, 0.928, 0.0, 0.0],
46+
[ 0.0, 0.0, 0.0, 0.0, 0.0],
47+
]);
48+
let c = ColorMatrix::from_rows([
49+
[-0.213, -0.715, 0.928, 0.0, 0.0],
50+
[ 0.143, 0.140, -0.283, 0.0, 0.0],
51+
[-0.787, 0.715, 0.072, 0.0, 0.0],
52+
[ 0.0, 0.0, 0.0, 0.0, 0.0],
53+
]);
54+
a + b * angle.cos() + c * angle.sin()
55+
}
56+
57+
/// Creates a saturate color matrix filter with the given factor between 0 and 1.
58+
///
59+
/// See the `saturate` attribute of the `feColorMatrix` element in the SVG specification.
60+
pub fn saturate(saturation: f32) -> ColorMatrix {
61+
let a = ColorMatrix::from_rows([
62+
[ 0.213, 0.715, 0.072, 0.0, 0.0],
63+
[ 0.213, 0.715, 0.072, 0.0, 0.0],
64+
[ 0.213, 0.715, 0.072, 0.0, 0.0],
65+
[ 0.0, 0.0, 0.0, 1.0, 0.0],
66+
]);
67+
let b = ColorMatrix::from_rows([
68+
[ 0.787, -0.715, -0.072, 0.0, 0.0],
69+
[-0.213, 0.285, -0.072, 0.0, 0.0],
70+
[-0.213, -0.715, 0.928, 0.0, 0.0],
71+
[ 0.0, 0.0, 0.0, 0.0, 0.0],
72+
]);
73+
a + b * saturation
74+
}
75+
76+
/// Creates a luminance-to-alpha color matrix filter.
77+
///
78+
/// See the `luminanceToAlpha` attribute of the `feColorMatrix` element in the SVG
79+
/// specification.
80+
pub fn luminance_to_alpha() -> ColorMatrix {
81+
ColorMatrix::from_rows([
82+
[ 0.0, 0.0, 0.0, 0.0, 0.0],
83+
[ 0.0, 0.0, 0.0, 0.0, 0.0],
84+
[ 0.0, 0.0, 0.0, 0.0, 0.0],
85+
[ 0.2125, 0.7154, 0.0721, 0.0, 0.0],
86+
])
87+
}
88+
}
89+
impl Deref for ColorMatrix {
90+
type Target = [F32x4; 5];
91+
92+
#[inline]
93+
fn deref(&self) -> &[F32x4; 5] {
94+
&self.0
95+
}
96+
}
97+
impl Add for ColorMatrix {
98+
type Output = ColorMatrix;
99+
100+
#[inline]
101+
fn add(self, rhs: ColorMatrix) -> ColorMatrix {
102+
ColorMatrix([
103+
self[0] + rhs[0],
104+
self[1] + rhs[1],
105+
self[2] + rhs[2],
106+
self[3] + rhs[3],
107+
self[4] + rhs[4],
108+
])
109+
}
110+
}
111+
112+
impl Mul<f32> for ColorMatrix {
113+
type Output = ColorMatrix;
114+
115+
#[inline]
116+
fn mul(self, rhs: f32) -> ColorMatrix {
117+
let rhs = F32x4::splat(rhs);
118+
ColorMatrix([
119+
self[0] * rhs,
120+
self[1] * rhs,
121+
self[2] * rhs,
122+
self[3] * rhs,
123+
self[4] * rhs,
124+
])
125+
}
126+
}

content/src/effects.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
//! Special effects that can be applied to layers.
1212
13-
use pathfinder_color::ColorF;
13+
use pathfinder_color::{ColorF, matrix::ColorMatrix};
1414
use pathfinder_geometry::line_segment::LineSegment2F;
1515
use pathfinder_geometry::vector::Vector2F;
1616
use pathfinder_simd::default::F32x2;
@@ -83,6 +83,12 @@ pub enum PatternFilter {
8383
direction: BlurDirection,
8484
sigma: f32,
8585
},
86+
87+
/// A color matrix multiplication.
88+
///
89+
/// The matrix is stored in 5 columns of `F32x4`. See the `feColorMatrix` element in the SVG
90+
/// specification.
91+
ColorMatrix(ColorMatrix),
8692
}
8793

8894
/// Blend modes that can be applied to individual paths.

renderer/src/gpu/renderer.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub(crate) const MASK_TILES_DOWN: u32 = 256;
5353
const SQRT_2_PI_INV: f32 = 0.3989422804014327;
5454

5555
const TEXTURE_METADATA_ENTRIES_PER_ROW: i32 = 128;
56-
const TEXTURE_METADATA_TEXTURE_WIDTH: i32 = TEXTURE_METADATA_ENTRIES_PER_ROW * 8;
56+
const TEXTURE_METADATA_TEXTURE_WIDTH: i32 = TEXTURE_METADATA_ENTRIES_PER_ROW * 10;
5757
const TEXTURE_METADATA_TEXTURE_HEIGHT: i32 = 65536 / TEXTURE_METADATA_ENTRIES_PER_ROW;
5858

5959
// FIXME(pcwalton): Shrink this again!
@@ -63,10 +63,11 @@ pub(crate) const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 / 4 * MASK_TI
6363
const COMBINER_CTRL_FILTER_RADIAL_GRADIENT: i32 = 0x1;
6464
const COMBINER_CTRL_FILTER_TEXT: i32 = 0x2;
6565
const COMBINER_CTRL_FILTER_BLUR: i32 = 0x3;
66+
const COMBINER_CTRL_FILTER_COLOR_MATRIX: i32 = 0x4;
6667

6768
const COMBINER_CTRL_COLOR_FILTER_SHIFT: i32 = 4;
68-
const COMBINER_CTRL_COLOR_COMBINE_SHIFT: i32 = 6;
69-
const COMBINER_CTRL_COMPOSITE_SHIFT: i32 = 8;
69+
const COMBINER_CTRL_COLOR_COMBINE_SHIFT: i32 = 8;
70+
const COMBINER_CTRL_COMPOSITE_SHIFT: i32 = 10;
7071

7172
/// The GPU renderer that processes commands necessary to render a scene.
7273
pub struct Renderer<D> where D: Device {
@@ -693,11 +694,21 @@ impl<D> Renderer<D> where D: Device {
693694
f16::from_f32(filter_params.p2.z()),
694695
f16::from_f32(filter_params.p2.w()),
695696
// 6
697+
f16::from_f32(filter_params.p3.x()),
698+
f16::from_f32(filter_params.p3.y()),
699+
f16::from_f32(filter_params.p3.z()),
700+
f16::from_f32(filter_params.p3.w()),
701+
// 7
702+
f16::from_f32(filter_params.p4.x()),
703+
f16::from_f32(filter_params.p4.y()),
704+
f16::from_f32(filter_params.p4.z()),
705+
f16::from_f32(filter_params.p4.w()),
706+
// 8
696707
f16::from_f32(filter_params.ctrl as f32),
697708
f16::default(),
698709
f16::default(),
699710
f16::default(),
700-
// 7
711+
// 9
701712
f16::default(),
702713
f16::default(),
703714
f16::default(),
@@ -921,6 +932,8 @@ impl<D> Renderer<D> where D: Device {
921932
p0: line.from().0.concat_xy_xy(line.vector().0),
922933
p1: radii.concat_xy_xy(uv_origin.0),
923934
p2: F32x4::default(),
935+
p3: F32x4::default(),
936+
p4: F32x4::default(),
924937
ctrl: ctrl | (COMBINER_CTRL_FILTER_RADIAL_GRADIENT <<
925938
COMBINER_CTRL_COLOR_FILTER_SHIFT)
926939
}
@@ -942,6 +955,8 @@ impl<D> Renderer<D> where D: Device {
942955
p0: src_offset.0.concat_xy_xy(F32x2::new(support, 0.0)),
943956
p1: F32x4::new(gauss_coeff_x, gauss_coeff_y, gauss_coeff_z, 0.0),
944957
p2: F32x4::default(),
958+
p3: F32x4::default(),
959+
p4: F32x4::default(),
945960
ctrl: ctrl | (COMBINER_CTRL_FILTER_BLUR << COMBINER_CTRL_COLOR_FILTER_SHIFT),
946961
}
947962
}
@@ -961,14 +976,25 @@ impl<D> Renderer<D> where D: Device {
961976
},
962977
p1: bg_color.0,
963978
p2,
979+
p3: F32x4::default(),
980+
p4: F32x4::default(),
964981
ctrl: ctrl | (COMBINER_CTRL_FILTER_TEXT << COMBINER_CTRL_COLOR_FILTER_SHIFT),
965982
}
966983
}
984+
Filter::PatternFilter(PatternFilter::ColorMatrix(matrix)) => {
985+
let [p0, p1, p2, p3, p4] = matrix.0;
986+
FilterParams {
987+
p0, p1, p2, p3, p4,
988+
ctrl: ctrl | (COMBINER_CTRL_FILTER_COLOR_MATRIX << COMBINER_CTRL_COLOR_FILTER_SHIFT),
989+
}
990+
}
967991
Filter::None => {
968992
FilterParams {
969993
p0: F32x4::default(),
970994
p1: F32x4::default(),
971995
p2: F32x4::default(),
996+
p3: F32x4::default(),
997+
p4: F32x4::default(),
972998
ctrl,
973999
}
9741000
}
@@ -1317,6 +1343,8 @@ struct FilterParams {
13171343
p0: F32x4,
13181344
p1: F32x4,
13191345
p2: F32x4,
1346+
p3: F32x4,
1347+
p4: F32x4,
13201348
ctrl: i32,
13211349
}
13221350

resources/shaders/gl3/d3d9/tile.fs.glsl

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ precision highp float;
9494

9595

9696

97+
9798

9899

99100
vec4 sampleColor(sampler2D colorTexture, vec2 colorTexCoord){
@@ -370,6 +371,18 @@ vec4 filterBlur(vec2 colorTexCoord,
370371
return color / gaussSum;
371372
}
372373

374+
vec4 filterColorMatrix(vec2 colorTexCoord,
375+
sampler2D colorTexture,
376+
vec4 filterParams0,
377+
vec4 filterParams1,
378+
vec4 filterParams2,
379+
vec4 filterParams3,
380+
vec4 filterParams4){
381+
vec4 srcColor = texture(colorTexture, colorTexCoord);
382+
mat4 colorMatrix = mat4(filterParams0, filterParams1, filterParams2, filterParams3);
383+
return colorMatrix * srcColor + filterParams4;
384+
}
385+
373386
vec4 filterNone(vec2 colorTexCoord, sampler2D colorTexture){
374387
return sampleColor(colorTexture, colorTexCoord);
375388
}
@@ -383,6 +396,8 @@ vec4 filterColor(vec2 colorTexCoord,
383396
vec4 filterParams0,
384397
vec4 filterParams1,
385398
vec4 filterParams2,
399+
vec4 filterParams3,
400+
vec4 filterParams4,
386401
int colorFilter){
387402
switch(colorFilter){
388403
case 0x1 :
@@ -407,6 +422,14 @@ vec4 filterColor(vec2 colorTexCoord,
407422
filterParams0,
408423
filterParams1,
409424
filterParams2);
425+
case 0x4 :
426+
return filterColorMatrix(colorTexCoord,
427+
colorTexture,
428+
filterParams0,
429+
filterParams1,
430+
filterParams2,
431+
filterParams3,
432+
filterParams4);
410433
}
411434
return filterNone(colorTexCoord, colorTexture);
412435
}
@@ -569,6 +592,8 @@ vec4 calculateColor(vec2 fragCoord,
569592
vec4 filterParams0,
570593
vec4 filterParams1,
571594
vec4 filterParams2,
595+
vec4 filterParams3,
596+
vec4 filterParams4,
572597
vec2 framebufferSize,
573598
int ctrl,
574599
vec3 maskTexCoord0,
@@ -582,10 +607,10 @@ vec4 calculateColor(vec2 fragCoord,
582607

583608

584609
vec4 color = baseColor;
585-
int color0Combine =(ctrl >> 6)&
610+
int color0Combine =(ctrl >> 8)&
586611
0x3;
587612
if(color0Combine != 0){
588-
int color0Filter =(ctrl >> 4)& 0x3;
613+
int color0Filter =(ctrl >> 4)& 0xf;
589614
vec4 color0 = filterColor(colorTexCoord0,
590615
colorTexture0,
591616
gammaLUT,
@@ -595,6 +620,8 @@ vec4 calculateColor(vec2 fragCoord,
595620
filterParams0,
596621
filterParams1,
597622
filterParams2,
623+
filterParams3,
624+
filterParams4,
598625
color0Filter);
599626
color = combineColor0(color, color0, color0Combine);
600627
}
@@ -603,7 +630,7 @@ vec4 calculateColor(vec2 fragCoord,
603630
color . a *= maskAlpha;
604631

605632

606-
int compositeOp =(ctrl >> 8)& 0xf;
633+
int compositeOp =(ctrl >> 10)& 0xf;
607634
color = composite(color, destTexture, framebufferSize, fragCoord, compositeOp);
608635

609636

@@ -627,6 +654,8 @@ in float vTileCtrl;
627654
in vec4 vFilterParams0;
628655
in vec4 vFilterParams1;
629656
in vec4 vFilterParams2;
657+
in vec4 vFilterParams3;
658+
in vec4 vFilterParams4;
630659
in float vCtrl;
631660

632661
out vec4 oFragColor;
@@ -646,6 +675,8 @@ void main(){
646675
vFilterParams0,
647676
vFilterParams1,
648677
vFilterParams2,
678+
vFilterParams3,
679+
vFilterParams4,
649680
uFramebufferSize,
650681
int(vCtrl),
651682
vMaskTexCoord0,

0 commit comments

Comments
 (0)