Skip to content

Commit

Permalink
[Impeller] Add tile modes to gaussian blur (flutter#35249)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdero authored Aug 9, 2022
1 parent 9bfbc54 commit 6c14fb3
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 27 deletions.
3 changes: 2 additions & 1 deletion impeller/aiks/paint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
FilterInput::Ref input,
bool is_solid_color) const {
if (is_solid_color) {
return FilterContents::MakeGaussianBlur(input, sigma, sigma, style);
return FilterContents::MakeGaussianBlur(input, sigma, sigma, style,
Entity::TileMode::kDecal);
}
return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style);
}
Expand Down
33 changes: 21 additions & 12 deletions impeller/display_list/display_list_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ static Entity::BlendMode ToBlendMode(flutter::DlBlendMode mode) {
FML_UNREACHABLE();
}

static Entity::TileMode ToTileMode(flutter::DlTileMode tile_mode) {
switch (tile_mode) {
case flutter::DlTileMode::kClamp:
return Entity::TileMode::kClamp;
case flutter::DlTileMode::kRepeat:
return Entity::TileMode::kRepeat;
case flutter::DlTileMode::kMirror:
return Entity::TileMode::kMirror;
case flutter::DlTileMode::kDecal:
return Entity::TileMode::kDecal;
}
}

// |flutter::Dispatcher|
void DisplayListDispatcher::setAntiAlias(bool aa) {
// Nothing to do because AA is implicit.
Expand Down Expand Up @@ -248,7 +261,7 @@ void DisplayListDispatcher::setColorSource(
colors.emplace_back(ToColor(linear->colors()[i]));
}
contents->SetColors(std::move(colors));
contents->SetTileMode(static_cast<Entity::TileMode>(linear->tile_mode()));
contents->SetTileMode(ToTileMode(linear->tile_mode()));
paint_.contents = std::move(contents);
return;
}
Expand All @@ -264,8 +277,7 @@ void DisplayListDispatcher::setColorSource(
colors.emplace_back(ToColor(radialGradient->colors()[i]));
}
contents->SetColors(std::move(colors));
contents->SetTileMode(
static_cast<Entity::TileMode>(radialGradient->tile_mode()));
contents->SetTileMode(ToTileMode(radialGradient->tile_mode()));
paint_.contents = std::move(contents);
return;
}
Expand All @@ -282,8 +294,7 @@ void DisplayListDispatcher::setColorSource(
colors.emplace_back(ToColor(sweepGradient->colors()[i]));
}
contents->SetColors(std::move(colors));
contents->SetTileMode(
static_cast<Entity::TileMode>(sweepGradient->tile_mode()));
contents->SetTileMode(ToTileMode(sweepGradient->tile_mode()));
paint_.contents = std::move(contents);
return;
}
Expand Down Expand Up @@ -400,14 +411,12 @@ static std::optional<Paint::ImageFilterProc> ToImageFilterProc(
Vector2(blur->sigma_x(), blur->sigma_y()) * effect_scale;
auto sigma_x = Sigma(scaled_blur.x);
auto sigma_y = Sigma(scaled_blur.y);
auto tile_mode = ToTileMode(blur->tile_mode());

if (blur->tile_mode() != flutter::DlTileMode::kClamp) {
// TODO(105072): Implement tile mode for blur filter.
UNIMPLEMENTED;
}

return [sigma_x, sigma_y](FilterInput::Ref input) {
return FilterContents::MakeGaussianBlur(input, sigma_x, sigma_y);
return [sigma_x, sigma_y, tile_mode](FilterInput::Ref input) {
return FilterContents::MakeGaussianBlur(
input, sigma_x, sigma_y, FilterContents::BlurStyle::kNormal,
tile_mode);
};

break;
Expand Down
12 changes: 8 additions & 4 deletions impeller/entity/contents/filters/filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,14 @@ std::shared_ptr<FilterContents> FilterContents::MakeDirectionalGaussianBlur(
Sigma sigma,
Vector2 direction,
BlurStyle blur_style,
Entity::TileMode tile_mode,
FilterInput::Ref source_override) {
auto blur = std::make_shared<DirectionalGaussianBlurFilterContents>();
blur->SetInputs({input});
blur->SetSigma(sigma);
blur->SetDirection(direction);
blur->SetBlurStyle(blur_style);
blur->SetTileMode(tile_mode);
blur->SetSourceOverride(source_override);
return blur;
}
Expand All @@ -88,11 +90,13 @@ std::shared_ptr<FilterContents> FilterContents::MakeGaussianBlur(
FilterInput::Ref input,
Sigma sigma_x,
Sigma sigma_y,
BlurStyle blur_style) {
BlurStyle blur_style,
Entity::TileMode tile_mode) {
auto x_blur = MakeDirectionalGaussianBlur(input, sigma_x, Point(1, 0),
BlurStyle::kNormal);
auto y_blur = MakeDirectionalGaussianBlur(FilterInput::Make(x_blur), sigma_y,
Point(0, 1), blur_style, input);
BlurStyle::kNormal, tile_mode);
auto y_blur =
MakeDirectionalGaussianBlur(FilterInput::Make(x_blur), sigma_y,
Point(0, 1), blur_style, tile_mode, input);
return y_blur;
}

Expand Down
4 changes: 3 additions & 1 deletion impeller/entity/contents/filters/filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ class FilterContents : public Contents {
Sigma sigma,
Vector2 direction,
BlurStyle blur_style = BlurStyle::kNormal,
Entity::TileMode tile_mode = Entity::TileMode::kDecal,
FilterInput::Ref alpha_mask = nullptr);

static std::shared_ptr<FilterContents> MakeGaussianBlur(
FilterInput::Ref input,
Sigma sigma_x,
Sigma sigma_y,
BlurStyle blur_style = BlurStyle::kNormal);
BlurStyle blur_style = BlurStyle::kNormal,
Entity::TileMode tile_mode = Entity::TileMode::kDecal);

static std::shared_ptr<FilterContents> MakeBorderMaskBlur(
FilterInput::Ref input,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ void DirectionalGaussianBlurFilterContents::SetBlurStyle(BlurStyle blur_style) {
}
}

void DirectionalGaussianBlurFilterContents::SetTileMode(
Entity::TileMode tile_mode) {
tile_mode_ = tile_mode;
}

void DirectionalGaussianBlurFilterContents::SetSourceOverride(
FilterInput::Ref source_override) {
source_override_ = source_override;
Expand Down Expand Up @@ -138,6 +143,7 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter(
frag_info.blur_direction = input_snapshot->transform.Invert()
.TransformDirection(transformed_blur)
.Normalize();
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
frag_info.src_factor = src_color_factor_;
frag_info.inner_blur_factor = inner_blur_factor_;
frag_info.outer_blur_factor = outer_blur_factor_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents {

void SetBlurStyle(BlurStyle blur_style);

void SetTileMode(Entity::TileMode tile_mode);

void SetSourceOverride(FilterInput::Ref alpha_mask);

// |FilterContents|
Expand All @@ -39,6 +41,7 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents {
Sigma blur_sigma_;
Vector2 blur_direction_;
BlurStyle blur_style_ = BlurStyle::kNormal;
Entity::TileMode tile_mode_ = Entity::TileMode::kDecal;
bool src_color_factor_ = false;
bool inner_blur_factor_ = true;
bool outer_blur_factor_ = true;
Expand Down
18 changes: 12 additions & 6 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -842,31 +842,35 @@ TEST_P(EntityTest, GaussianBlurFilter) {
auto callback = [&](ContentContext& context, RenderPass& pass) -> bool {
if (first_frame) {
first_frame = false;
ImGui::SetNextWindowSize({500, 290});
ImGui::SetNextWindowPos({300, 480});
ImGui::SetNextWindowPos({10, 10});
}

const char* input_type_names[] = {"Texture", "Solid Color"};
const char* blur_type_names[] = {"Image blur", "Mask blur"};
const char* blur_style_names[] = {"Normal", "Solid", "Outer", "Inner"};
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
const FilterContents::BlurStyle blur_styles[] = {
FilterContents::BlurStyle::kNormal, FilterContents::BlurStyle::kSolid,
FilterContents::BlurStyle::kOuter, FilterContents::BlurStyle::kInner};
const Entity::TileMode tile_modes[] = {
Entity::TileMode::kClamp, Entity::TileMode::kRepeat,
Entity::TileMode::kMirror, Entity::TileMode::kDecal};

// UI state.
static int selected_input_type = 0;
static Color input_color = Color::Black();
static int selected_blur_type = 0;
static float blur_amount[2] = {20, 20};
static int selected_blur_style = 0;
static int selected_tile_mode = 3;
static Color cover_color(1, 0, 0, 0.2);
static Color bounds_color(0, 1, 0, 0.1);
static float offset[2] = {500, 400};
static float rotation = 0;
static float scale[2] = {0.75, 0.75};
static float scale[2] = {0.65, 0.65};
static float skew[2] = {0, 0};

ImGui::Begin("Controls");
ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
{
ImGui::Combo("Input type", &selected_input_type, input_type_names,
sizeof(input_type_names) / sizeof(char*));
Expand All @@ -878,9 +882,11 @@ TEST_P(EntityTest, GaussianBlurFilter) {
}
ImGui::Combo("Blur type", &selected_blur_type, blur_type_names,
sizeof(blur_type_names) / sizeof(char*));
ImGui::SliderFloat2("Blur", &blur_amount[0], 0, 200);
ImGui::SliderFloat2("Sigma", &blur_amount[0], 0, 200);
ImGui::Combo("Blur style", &selected_blur_style, blur_style_names,
sizeof(blur_style_names) / sizeof(char*));
ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
sizeof(tile_mode_names) / sizeof(char*));
ImGui::ColorEdit4("Cover color", reinterpret_cast<float*>(&cover_color));
ImGui::ColorEdit4("Bounds color",
reinterpret_cast<float*>(&bounds_color));
Expand Down Expand Up @@ -917,7 +923,7 @@ TEST_P(EntityTest, GaussianBlurFilter) {

auto blur = FilterContents::MakeGaussianBlur(
FilterInput::Make(input), Sigma{blur_amount[0]}, Sigma{blur_amount[1]},
blur_styles[selected_blur_style]);
blur_styles[selected_blur_style], tile_modes[selected_tile_mode]);

auto mask_blur = FilterContents::MakeBorderMaskBlur(
FilterInput::Make(input), Sigma{blur_amount[0]}, Sigma{blur_amount[1]},
Expand Down
13 changes: 10 additions & 3 deletions impeller/entity/shaders/gaussian_blur.frag
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@ uniform FragInfo {
vec2 texture_size;
vec2 blur_direction;

float tile_mode;

// The blur sigma and radius have a linear relationship which is defined
// host-side, but both are useful controls here. Sigma (pixels per standard
// deviation) is used to define the gaussian function itself, whereas the
// radius is used to limit how much of the function is integrated.
float blur_sigma;
float blur_radius;

float src_factor;
float inner_blur_factor;
float outer_blur_factor;
Expand Down Expand Up @@ -52,13 +59,13 @@ void main() {
total_color +=
gaussian * IPSampleWithTileMode(texture_sampler,
v_texture_coords + blur_uv_offset * i,
kTileModeDecal);
frag_info.tile_mode);
}

vec4 blur_color = total_color / gaussian_integral;

vec4 src_color = IPSampleWithTileMode(alpha_mask_sampler,
v_src_texture_coords, kTileModeDecal);
vec4 src_color = IPSampleWithTileMode(
alpha_mask_sampler, v_src_texture_coords, frag_info.tile_mode);
float blur_factor = frag_info.inner_blur_factor * float(src_color.a > 0) +
frag_info.outer_blur_factor * float(src_color.a == 0);

Expand Down

0 comments on commit 6c14fb3

Please sign in to comment.