Skip to content

Commit 78eb5d6

Browse files
bderodnfield
authored andcommitted
Add blur styles to gaussian blur (flutter#107)
1 parent 31812de commit 78eb5d6

File tree

7 files changed

+168
-48
lines changed

7 files changed

+168
-48
lines changed

impeller/entity/contents/filters/filter_contents.cc

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,26 @@ std::shared_ptr<FilterContents> FilterContents::MakeBlend(
6161

6262
std::shared_ptr<FilterContents> FilterContents::MakeDirectionalGaussianBlur(
6363
FilterInput::Ref input,
64-
Vector2 blur_vector) {
64+
Vector2 blur_vector,
65+
BlurStyle blur_style,
66+
FilterInput::Ref source_override) {
6567
auto blur = std::make_shared<DirectionalGaussianBlurFilterContents>();
6668
blur->SetInputs({input});
6769
blur->SetBlurVector(blur_vector);
70+
blur->SetBlurStyle(blur_style);
71+
blur->SetSourceOverride(source_override);
6872
return blur;
6973
}
7074

7175
std::shared_ptr<FilterContents> FilterContents::MakeGaussianBlur(
7276
FilterInput::Ref input,
7377
Scalar sigma_x,
74-
Scalar sigma_y) {
75-
auto x_blur = MakeDirectionalGaussianBlur(input, Point(sigma_x, 0));
76-
auto y_blur =
77-
MakeDirectionalGaussianBlur(FilterInput::Make(x_blur), Point(0, sigma_y));
78+
Scalar sigma_y,
79+
BlurStyle blur_style) {
80+
auto x_blur =
81+
MakeDirectionalGaussianBlur(input, Point(sigma_x, 0), BlurStyle::kNormal);
82+
auto y_blur = MakeDirectionalGaussianBlur(
83+
FilterInput::Make(x_blur), Point(0, sigma_y), blur_style, input);
7884
return y_blur;
7985
}
8086

impeller/entity/contents/filters/filter_contents.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,31 @@ class Pipeline;
1818

1919
class FilterContents : public Contents {
2020
public:
21+
enum class BlurStyle {
22+
/// Blurred inside and outside.
23+
kNormal,
24+
/// Solid inside, blurred outside.
25+
kSolid,
26+
/// Nothing inside, blurred outside.
27+
kOuter,
28+
/// Blurred inside, nothing outside.
29+
kInner,
30+
};
31+
2132
static std::shared_ptr<FilterContents> MakeBlend(Entity::BlendMode blend_mode,
2233
FilterInput::Vector inputs);
2334

2435
static std::shared_ptr<FilterContents> MakeDirectionalGaussianBlur(
2536
FilterInput::Ref input,
26-
Vector2 blur_vector);
37+
Vector2 blur_vector,
38+
BlurStyle blur_style = BlurStyle::kNormal,
39+
FilterInput::Ref alpha_mask = nullptr);
2740

28-
static std::shared_ptr<FilterContents>
29-
MakeGaussianBlur(FilterInput::Ref input, Scalar sigma_x, Scalar sigma_y);
41+
static std::shared_ptr<FilterContents> MakeGaussianBlur(
42+
FilterInput::Ref input,
43+
Scalar sigma_x,
44+
Scalar sigma_y,
45+
BlurStyle blur_style = BlurStyle::kNormal);
3046

3147
FilterContents();
3248

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,38 @@ void DirectionalGaussianBlurFilterContents::SetBlurVector(Vector2 blur_vector) {
3030
blur_vector_ = blur_vector;
3131
}
3232

33+
void DirectionalGaussianBlurFilterContents::SetBlurStyle(BlurStyle blur_style) {
34+
blur_style_ = blur_style;
35+
36+
switch (blur_style) {
37+
case FilterContents::BlurStyle::kNormal:
38+
src_color_factor_ = false;
39+
inner_blur_factor_ = true;
40+
outer_blur_factor_ = true;
41+
break;
42+
case FilterContents::BlurStyle::kSolid:
43+
src_color_factor_ = true;
44+
inner_blur_factor_ = false;
45+
outer_blur_factor_ = true;
46+
break;
47+
case FilterContents::BlurStyle::kOuter:
48+
src_color_factor_ = false;
49+
inner_blur_factor_ = false;
50+
outer_blur_factor_ = true;
51+
break;
52+
case FilterContents::BlurStyle::kInner:
53+
src_color_factor_ = false;
54+
inner_blur_factor_ = true;
55+
outer_blur_factor_ = false;
56+
break;
57+
}
58+
}
59+
60+
void DirectionalGaussianBlurFilterContents::SetSourceOverride(
61+
FilterInput::Ref alpha_mask) {
62+
source_override_ = alpha_mask;
63+
}
64+
3365
bool DirectionalGaussianBlurFilterContents::RenderFilter(
3466
const FilterInput::Vector& inputs,
3567
const ContentContext& renderer,
@@ -45,43 +77,59 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter(
4577

4678
auto& host_buffer = pass.GetTransientsBuffer();
4779

48-
// Because this filter is intended to be used with only one input parameter,
49-
// and GetBounds just increases the input size by a factor of the direction,
50-
// we we can just scale up the UVs by the same amount and don't need to worry
51-
// about mapping the UVs to the destination rect (like we do in
52-
// BlendFilterContents).
53-
5480
auto input = inputs[0]->GetSnapshot(renderer, entity);
55-
auto input_size = input->texture->GetSize();
81+
auto input_bounds = inputs[0]->GetBounds(entity);
82+
auto filter_bounds = GetBounds(entity);
5683

5784
auto transformed_blur =
5885
entity.GetTransformation().TransformDirection(blur_vector_);
5986

60-
auto uv_offset = transformed_blur.Abs() / input_size;
6187
// LTRB
6288
Scalar uv[4] = {
63-
-uv_offset.x,
64-
-uv_offset.y,
65-
1 + uv_offset.x,
66-
1 + uv_offset.y,
89+
(filter_bounds.GetLeft() - input_bounds.GetLeft()) /
90+
input_bounds.size.width,
91+
(filter_bounds.GetTop() - input_bounds.GetTop()) /
92+
input_bounds.size.height,
93+
1 + (filter_bounds.GetRight() - input_bounds.GetRight()) /
94+
input_bounds.size.width,
95+
1 + (filter_bounds.GetBottom() - input_bounds.GetBottom()) /
96+
input_bounds.size.height,
97+
};
98+
99+
auto source = source_override_ ? source_override_ : inputs[0];
100+
auto source_texture = source->GetSnapshot(renderer, entity);
101+
auto source_bounds = source->GetBounds(entity);
102+
103+
// LTRB
104+
Scalar uv_src[4] = {
105+
(filter_bounds.GetLeft() - source_bounds.GetLeft()) /
106+
source_bounds.size.width,
107+
(filter_bounds.GetTop() - source_bounds.GetTop()) /
108+
source_bounds.size.height,
109+
1 + (filter_bounds.GetRight() - source_bounds.GetRight()) /
110+
source_bounds.size.width,
111+
1 + (filter_bounds.GetBottom() - source_bounds.GetBottom()) /
112+
source_bounds.size.height,
67113
};
68114

69115
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
70-
auto size = pass.GetRenderTargetSize();
71116
vtx_builder.AddVertices({
72-
{Point(0, 0), Point(uv[0], uv[1])},
73-
{Point(size.width, 0), Point(uv[2], uv[1])},
74-
{Point(size.width, size.height), Point(uv[2], uv[3])},
75-
{Point(0, 0), Point(uv[0], uv[1])},
76-
{Point(size.width, size.height), Point(uv[2], uv[3])},
77-
{Point(0, size.height), Point(uv[0], uv[3])},
117+
{Point(0, 0), Point(uv[0], uv[1]), Point(uv_src[0], uv_src[1])},
118+
{Point(1, 0), Point(uv[2], uv[1]), Point(uv_src[2], uv_src[1])},
119+
{Point(1, 1), Point(uv[2], uv[3]), Point(uv_src[2], uv_src[3])},
120+
{Point(0, 0), Point(uv[0], uv[1]), Point(uv_src[0], uv_src[1])},
121+
{Point(1, 1), Point(uv[2], uv[3]), Point(uv_src[2], uv_src[3])},
122+
{Point(0, 1), Point(uv[0], uv[3]), Point(uv_src[0], uv_src[3])},
78123
});
79124
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
80125

81126
VS::FrameInfo frame_info;
82-
frame_info.texture_size = Point(input_size);
127+
frame_info.texture_size = Point(input_bounds.size);
83128
frame_info.blur_radius = transformed_blur.GetLength();
84129
frame_info.blur_direction = transformed_blur.Normalize();
130+
frame_info.src_factor = src_color_factor_;
131+
frame_info.inner_blur_factor = inner_blur_factor_;
132+
frame_info.outer_blur_factor = outer_blur_factor_;
85133

86134
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
87135

@@ -93,8 +141,9 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter(
93141
cmd.BindVertices(vtx_buffer);
94142

95143
FS::BindTextureSampler(cmd, input->texture, sampler);
144+
FS::BindAlphaMaskSampler(cmd, source_texture->texture, sampler);
96145

97-
frame_info.mvp = Matrix::MakeOrthographic(size);
146+
frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));
98147
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
99148
VS::BindFrameInfo(cmd, uniform_view);
100149

impeller/entity/contents/filters/gaussian_blur_filter_contents.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#pragma once
66

7+
#include <memory>
8+
#include <optional>
79
#include "impeller/entity/contents/filters/filter_contents.h"
810
#include "impeller/entity/contents/filters/filter_input.h"
911
#include "impeller/geometry/matrix.h"
@@ -18,6 +20,10 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents {
1820

1921
void SetBlurVector(Vector2 blur_vector);
2022

23+
void SetBlurStyle(BlurStyle blur_style);
24+
25+
void SetSourceOverride(FilterInput::Ref alpha_mask);
26+
2127
// |Contents|
2228
Rect GetBounds(const Entity& entity) const override;
2329

@@ -30,6 +36,11 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents {
3036
const Rect& bounds) const override;
3137

3238
Vector2 blur_vector_;
39+
BlurStyle blur_style_ = BlurStyle::kNormal;
40+
bool src_color_factor_ = false;
41+
bool inner_blur_factor_ = true;
42+
bool outer_blur_factor_ = true;
43+
FilterInput::Ref source_override_;
3344

3445
FML_DISALLOW_COPY_AND_ASSIGN(DirectionalGaussianBlurFilterContents);
3546
};

impeller/entity/entity_unittests.cc

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -689,11 +689,18 @@ TEST_F(EntityTest, GaussianBlurFilter) {
689689
auto callback = [&](ContentContext& context, RenderPass& pass) -> bool {
690690
if (first_frame) {
691691
first_frame = false;
692-
ImGui::SetNextWindowSize({500, 190});
692+
ImGui::SetNextWindowSize({500, 220});
693693
ImGui::SetNextWindowPos({300, 550});
694694
}
695695

696+
const char* blur_style_names[] = {"Normal", "Solid", "Outer", "Inner"};
697+
const FilterContents::BlurStyle blur_styles[] = {
698+
FilterContents::BlurStyle::kNormal, FilterContents::BlurStyle::kSolid,
699+
FilterContents::BlurStyle::kOuter, FilterContents::BlurStyle::kInner};
700+
701+
// UI state.
696702
static float blur_amount[2] = {20, 20};
703+
static int selected_blur_style = 0;
697704
static Color cover_color(1, 0, 0, 0.2);
698705
static Color bounds_color(0, 1, 0, 0.1);
699706
static float offset[2] = {500, 400};
@@ -702,21 +709,27 @@ TEST_F(EntityTest, GaussianBlurFilter) {
702709
static float skew[2] = {0, 0};
703710

704711
ImGui::Begin("Controls");
705-
ImGui::SliderFloat2("Blur", &blur_amount[0], 0, 200);
706-
ImGui::ColorEdit4("Cover color", reinterpret_cast<float*>(&cover_color));
707-
ImGui::ColorEdit4("Bounds color", reinterpret_cast<float*>(&bounds_color));
708-
ImGui::SliderFloat2("Translation", &offset[0], 0,
709-
pass.GetRenderTargetSize().width);
710-
ImGui::SliderFloat("Rotation", &rotation, 0, kPi * 2);
711-
ImGui::SliderFloat2("Scale", &scale[0], 0, 3);
712-
ImGui::SliderFloat2("Skew", &skew[0], -3, 3);
712+
{
713+
ImGui::SliderFloat2("Blur", &blur_amount[0], 0, 200);
714+
ImGui::Combo("Blur style", &selected_blur_style, blur_style_names,
715+
sizeof(blur_style_names) / sizeof(char*));
716+
ImGui::ColorEdit4("Cover color", reinterpret_cast<float*>(&cover_color));
717+
ImGui::ColorEdit4("Bounds color",
718+
reinterpret_cast<float*>(&bounds_color));
719+
ImGui::SliderFloat2("Translation", &offset[0], 0,
720+
pass.GetRenderTargetSize().width);
721+
ImGui::SliderFloat("Rotation", &rotation, 0, kPi * 2);
722+
ImGui::SliderFloat2("Scale", &scale[0], 0, 3);
723+
ImGui::SliderFloat2("Skew", &skew[0], -3, 3);
724+
}
713725
ImGui::End();
714726

715727
auto blend = FilterContents::MakeBlend(
716728
Entity::BlendMode::kPlus, FilterInput::Make({boston, bridge, bridge}));
717729

718730
auto blur = FilterContents::MakeGaussianBlur(
719-
FilterInput::Make(blend), blur_amount[0], blur_amount[1]);
731+
FilterInput::Make(blend), blur_amount[0], blur_amount[1],
732+
blur_styles[selected_blur_style]);
720733

721734
ISize input_size = boston->GetSize();
722735
auto rect = Rect(-Point(input_size) / 2, Size(input_size));

impeller/entity/shaders/gaussian_blur.frag

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,21 @@
55
// 1D (directional) gaussian blur.
66
//
77
// Paths for future optimization:
8-
// * Remove the uv bounds check branch in SampleColor by adding optional
8+
// * Remove the uv bounds multiplier in SampleColor by adding optional
99
// support for SamplerAddressMode::ClampToBorder in the texture sampler.
1010
// * Sample from higher mipmap levels when the blur radius is high enough.
1111

1212
uniform sampler2D texture_sampler;
13+
uniform sampler2D alpha_mask_sampler;
1314

1415
in vec2 v_texture_coords;
16+
in vec2 v_src_texture_coords;
1517
in vec2 v_texture_size;
1618
in vec2 v_blur_direction;
1719
in float v_blur_radius;
20+
in float v_src_factor;
21+
in float v_inner_blur_factor;
22+
in float v_outer_blur_factor;
1823

1924
out vec4 frag_color;
2025

@@ -27,21 +32,27 @@ float Gaussian(float x) {
2732
}
2833

2934
// Emulate SamplerAddressMode::ClampToBorder.
30-
vec4 SampleWithBorder(vec2 uv) {
31-
if (uv.x > 0 && uv.y > 0 && uv.x < 1 && uv.y < 1) {
32-
return texture(texture_sampler, uv);
33-
}
34-
return vec4(0);
35+
vec4 SampleWithBorder(sampler2D tex, vec2 uv) {
36+
float within_bounds = float(uv.x >= 0 && uv.y >= 0 && uv.x < 1 && uv.y < 1);
37+
return texture(tex, uv) * within_bounds;
3538
}
3639

3740
void main() {
3841
vec4 total = vec4(0);
3942
float total_gaussian = 0;
43+
vec2 blur_uv_offset = v_blur_direction / v_texture_size;
4044
for (float i = -v_blur_radius; i <= v_blur_radius; i++) {
4145
float gaussian = Gaussian(i);
4246
total_gaussian += gaussian;
43-
total += gaussian * SampleWithBorder(v_texture_coords +
44-
v_blur_direction * i / v_texture_size);
47+
total += gaussian * SampleWithBorder(texture_sampler,
48+
v_texture_coords + blur_uv_offset * i);
4549
}
46-
frag_color = total / total_gaussian;
50+
51+
vec4 blur_color = total / total_gaussian;
52+
53+
vec4 src_color = SampleWithBorder(alpha_mask_sampler, v_src_texture_coords);
54+
float blur_factor = v_inner_blur_factor * float(src_color.a > 0) +
55+
v_outer_blur_factor * float(src_color.a == 0);
56+
57+
frag_color = blur_color * blur_factor + src_color * v_src_factor;
4758
}

impeller/entity/shaders/gaussian_blur.vert

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,37 @@
55
uniform FrameInfo {
66
mat4 mvp;
77
vec2 texture_size;
8+
89
vec2 blur_direction;
910
float blur_radius;
11+
12+
float src_factor;
13+
float inner_blur_factor;
14+
float outer_blur_factor;
1015
}
1116
frame_info;
1217

1318
in vec2 vertices;
1419
in vec2 texture_coords;
20+
in vec2 src_texture_coords;
1521

1622
out vec2 v_texture_coords;
23+
out vec2 v_src_texture_coords;
1724
out vec2 v_texture_size;
1825
out vec2 v_blur_direction;
1926
out float v_blur_radius;
27+
out float v_src_factor;
28+
out float v_inner_blur_factor;
29+
out float v_outer_blur_factor;
2030

2131
void main() {
2232
gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0);
2333
v_texture_coords = texture_coords;
34+
v_src_texture_coords = src_texture_coords;
2435
v_texture_size = frame_info.texture_size;
2536
v_blur_direction = frame_info.blur_direction;
2637
v_blur_radius = frame_info.blur_radius;
38+
v_src_factor = frame_info.src_factor;
39+
v_inner_blur_factor = frame_info.inner_blur_factor;
40+
v_outer_blur_factor = frame_info.outer_blur_factor;
2741
}

0 commit comments

Comments
 (0)