[Impeller] deleted the old blur (flutter/engine#50470)

fixes https://github.com/flutter/flutter/issues/131579


## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I added new tests to check the change I am making or feature I am
adding, or the PR is [test-exempt]. See [testing the engine] for
instructions on writing and running engine tests.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I signed the [CLA].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[C++, Objective-C, Java style guides]:
https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
[testing the engine]:
https://github.com/flutter/flutter/wiki/Testing-the-engine
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat
This commit is contained in:
gaaclarke
2024-02-12 09:00:06 -08:00
committed by GitHub
parent bb9eaca791
commit daaedbbe2b
9 changed files with 1 additions and 701 deletions

View File

@@ -144,7 +144,6 @@
../../../flutter/impeller/docs
../../../flutter/impeller/entity/contents/checkerboard_contents_unittests.cc
../../../flutter/impeller/entity/contents/content_context_unittests.cc
../../../flutter/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents_unittests.cc
../../../flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc
../../../flutter/impeller/entity/contents/filters/inputs/filter_input_unittests.cc
../../../flutter/impeller/entity/contents/host_buffer_unittests.cc

View File

@@ -5102,8 +5102,6 @@ ORIGIN: ../../../flutter/impeller/entity/contents/filters/color_filter_contents.
ORIGIN: ../../../flutter/impeller/entity/contents/filters/color_filter_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/filters/color_matrix_filter_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/filters/color_matrix_filter_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/filters/filter_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/filters/filter_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc + ../../../flutter/LICENSE
@@ -7935,8 +7933,6 @@ FILE: ../../../flutter/impeller/entity/contents/filters/color_filter_contents.cc
FILE: ../../../flutter/impeller/entity/contents/filters/color_filter_contents.h
FILE: ../../../flutter/impeller/entity/contents/filters/color_matrix_filter_contents.cc
FILE: ../../../flutter/impeller/entity/contents/filters/color_matrix_filter_contents.h
FILE: ../../../flutter/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.cc
FILE: ../../../flutter/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.h
FILE: ../../../flutter/impeller/entity/contents/filters/filter_contents.cc
FILE: ../../../flutter/impeller/entity/contents/filters/filter_contents.h
FILE: ../../../flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

View File

@@ -134,8 +134,6 @@ impeller_component("entity") {
"contents/filters/color_filter_contents.h",
"contents/filters/color_matrix_filter_contents.cc",
"contents/filters/color_matrix_filter_contents.h",
"contents/filters/directional_gaussian_blur_filter_contents.cc",
"contents/filters/directional_gaussian_blur_filter_contents.h",
"contents/filters/filter_contents.cc",
"contents/filters/filter_contents.h",
"contents/filters/gaussian_blur_filter_contents.cc",
@@ -268,7 +266,6 @@ impeller_component("entity_unittests") {
sources = [
"contents/checkerboard_contents_unittests.cc",
"contents/content_context_unittests.cc",
"contents/filters/directional_gaussian_blur_filter_contents_unittests.cc",
"contents/filters/gaussian_blur_filter_contents_unittests.cc",
"contents/filters/inputs/filter_input_unittests.cc",
"contents/host_buffer_unittests.cc",

View File

@@ -1,315 +0,0 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.h"
#include <cmath>
#include <utility>
#include "impeller/base/strings.h"
#include "impeller/core/formats.h"
#include "impeller/core/sampler_descriptor.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/contents/filters/filter_contents.h"
#include "impeller/geometry/rect.h"
#include "impeller/geometry/scalar.h"
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/render_target.h"
#include "impeller/renderer/vertex_buffer_builder.h"
namespace impeller {
// This function was calculated by observing Skia's behavior. Its blur at 500
// seemed to be 0.15. Since we clamp at 500 I solved the quadratic equation
// that puts the minima there and a f(0)=1.
Sigma ScaleSigma(Sigma sigma) {
// Limit the kernel size to 1000x1000 pixels, like Skia does.
Scalar clamped = std::min(sigma.sigma, 500.0f);
Scalar scalar = 1.0 - 3.4e-3 * clamped + 3.4e-06 * clamped * clamped;
return Sigma(clamped * scalar);
}
DirectionalGaussianBlurFilterContents::DirectionalGaussianBlurFilterContents() =
default;
DirectionalGaussianBlurFilterContents::
~DirectionalGaussianBlurFilterContents() = default;
void DirectionalGaussianBlurFilterContents::SetSigma(Sigma sigma) {
blur_sigma_ = sigma;
}
void DirectionalGaussianBlurFilterContents::SetSecondarySigma(Sigma sigma) {
secondary_blur_sigma_ = sigma;
}
void DirectionalGaussianBlurFilterContents::SetDirection(Vector2 direction) {
blur_direction_ = direction.Normalize();
if (blur_direction_.IsZero()) {
blur_direction_ = Vector2(0, 1);
}
}
void DirectionalGaussianBlurFilterContents::SetBlurStyle(BlurStyle blur_style) {
blur_style_ = blur_style;
}
void DirectionalGaussianBlurFilterContents::SetTileMode(
Entity::TileMode tile_mode) {
tile_mode_ = tile_mode;
}
void DirectionalGaussianBlurFilterContents::SetIsSecondPass(
bool is_second_pass) {
is_second_pass_ = is_second_pass;
}
std::optional<Entity> DirectionalGaussianBlurFilterContents::RenderFilter(
const FilterInput::Vector& inputs,
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage,
const std::optional<Rect>& coverage_hint) const {
using VS = GaussianBlurPipeline::VertexShader;
using FS = GaussianBlurPipeline::FragmentShader;
//----------------------------------------------------------------------------
/// Handle inputs.
///
if (inputs.empty()) {
return std::nullopt;
}
auto radius = Radius{ScaleSigma(blur_sigma_)}.radius;
auto transform = entity.GetTransform() * effect_transform.Basis();
auto transformed_blur_radius =
transform.TransformDirection(blur_direction_ * radius);
auto transformed_blur_radius_length = transformed_blur_radius.GetLength();
// Input 0 snapshot.
std::optional<Rect> expanded_coverage_hint;
if (coverage_hint.has_value()) {
auto r =
Point(transformed_blur_radius_length, transformed_blur_radius_length)
.Abs();
expanded_coverage_hint =
is_second_pass_ ? coverage_hint : coverage_hint->Expand(r);
}
auto input_snapshot = inputs[0]->GetSnapshot("GaussianBlur", renderer, entity,
expanded_coverage_hint);
if (!input_snapshot.has_value()) {
return std::nullopt;
}
if (blur_sigma_.sigma < kEhCloseEnough) {
return Entity::FromSnapshot(input_snapshot.value(), entity.GetBlendMode(),
entity.GetClipDepth()); // No blur to render.
}
// If the radius length is < .5, the shader will take at most 1 sample,
// resulting in no blur.
if (transformed_blur_radius_length < .5) {
return Entity::FromSnapshot(input_snapshot.value(), entity.GetBlendMode(),
entity.GetClipDepth()); // No blur to render.
}
// A matrix that rotates the snapshot space such that the blur direction is
// +X.
auto texture_rotate = Matrix::MakeRotationZ(
transformed_blur_radius.Normalize().AngleTo({1, 0}));
// Converts local pass space to screen space. This is just the snapshot space
// rotated such that the blur direction is +X.
auto pass_transform = texture_rotate * input_snapshot->transform;
// The pass texture coverage, but rotated such that the blur is in the +X
// direction, and expanded to include the blur radius. This is used for UV
// projection and as a source for the pass size. Note that it doesn't matter
// which direction the space is rotated in when grabbing the pass size.
auto pass_texture_rect = Rect::MakeSize(input_snapshot->texture->GetSize())
.TransformBounds(pass_transform)
.Expand(transformed_blur_radius_length, 0);
// UV mapping.
auto pass_uv_project = [&texture_rotate,
&pass_texture_rect](Snapshot& input) {
auto uv_matrix = Matrix::MakeScale(1 / Vector2(input.texture->GetSize())) *
(texture_rotate * input.transform).Invert();
return pass_texture_rect.GetTransformedPoints(uv_matrix);
};
auto input_uvs = pass_uv_project(input_snapshot.value());
//----------------------------------------------------------------------------
/// Render to texture.
///
ContentContext::SubpassCallback subpass_callback = [&](const ContentContext&
renderer,
RenderPass& pass) {
auto& host_buffer = renderer.GetTransientsBuffer();
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
vtx_builder.AddVertices({
{Point(0, 0), input_uvs[0]},
{Point(1, 0), input_uvs[1]},
{Point(0, 1), input_uvs[2]},
{Point(1, 1), input_uvs[3]},
});
VS::FrameInfo frame_info;
frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));
frame_info.texture_sampler_y_coord_scale =
input_snapshot->texture->GetYCoordScale();
FS::BlurInfo frag_info;
auto r = Radius{transformed_blur_radius_length};
frag_info.blur_sigma = Sigma{r}.sigma;
frag_info.blur_radius = std::round(r.radius);
frag_info.step_size = 2.0;
// The blur direction is in input UV space.
frag_info.blur_uv_offset =
pass_transform.Invert().TransformDirection(Vector2(1, 0)).Normalize() /
Point(input_snapshot->GetCoverage().value().GetSize());
#ifdef IMPELLER_DEBUG
pass.SetCommandLabel(SPrintF("Gaussian Blur Filter (Radius=%.2f)",
transformed_blur_radius_length));
#endif // IMPELLER_DEBUG
pass.SetVertexBuffer(vtx_builder.CreateVertexBuffer(host_buffer));
auto options = OptionsFromPass(pass);
options.primitive_type = PrimitiveType::kTriangleStrip;
options.blend_mode = BlendMode::kSource;
auto input_descriptor = input_snapshot->sampler_descriptor;
switch (tile_mode_) {
case Entity::TileMode::kDecal:
if (renderer.GetDeviceCapabilities()
.SupportsDecalSamplerAddressMode()) {
input_descriptor.width_address_mode = SamplerAddressMode::kDecal;
input_descriptor.height_address_mode = SamplerAddressMode::kDecal;
}
break;
case Entity::TileMode::kClamp:
input_descriptor.width_address_mode = SamplerAddressMode::kClampToEdge;
input_descriptor.height_address_mode = SamplerAddressMode::kClampToEdge;
break;
case Entity::TileMode::kMirror:
input_descriptor.width_address_mode = SamplerAddressMode::kMirror;
input_descriptor.height_address_mode = SamplerAddressMode::kMirror;
break;
case Entity::TileMode::kRepeat:
input_descriptor.width_address_mode = SamplerAddressMode::kRepeat;
input_descriptor.height_address_mode = SamplerAddressMode::kRepeat;
break;
}
input_descriptor.mag_filter = MinMagFilter::kLinear;
input_descriptor.min_filter = MinMagFilter::kLinear;
bool has_decal_specialization =
tile_mode_ == Entity::TileMode::kDecal &&
!renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode();
if (has_decal_specialization) {
pass.SetPipeline(renderer.GetGaussianBlurDecalPipeline(options));
} else {
pass.SetPipeline(renderer.GetGaussianBlurPipeline(options));
}
FS::BindTextureSampler(
pass, input_snapshot->texture,
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
input_descriptor));
VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info));
FS::BindBlurInfo(pass, host_buffer.EmplaceUniform(frag_info));
return pass.Draw().ok();
};
Vector2 scale;
auto scale_curve = [](Scalar radius) {
constexpr Scalar decay = 4.0; // Larger is more gradual.
constexpr Scalar limit = 0.95; // The maximum percentage of the scaledown.
const Scalar curve =
std::min(1.0, decay / (std::max(1.0f, radius) + decay - 1.0));
return (curve - 1) * limit + 1;
};
{
scale.x = scale_curve(transformed_blur_radius_length);
Scalar y_radius = std::abs(pass_transform.GetDirectionScale(Vector2(
0, !is_second_pass_ ? 1 : Radius{secondary_blur_sigma_}.radius)));
scale.y = scale_curve(y_radius);
}
Vector2 scaled_size = pass_texture_rect.GetSize() * scale;
ISize floored_size = ISize(scaled_size.x, scaled_size.y);
fml::StatusOr<RenderTarget> render_target = renderer.MakeSubpass(
"Directional Gaussian Blur Filter", floored_size, subpass_callback);
if (!render_target.ok()) {
return std::nullopt;
}
SamplerDescriptor sampler_desc;
sampler_desc.min_filter = MinMagFilter::kLinear;
sampler_desc.mag_filter = MinMagFilter::kLinear;
sampler_desc.width_address_mode = SamplerAddressMode::kClampToEdge;
sampler_desc.width_address_mode = SamplerAddressMode::kClampToEdge;
return Entity::FromSnapshot(
Snapshot{
.texture = render_target.value().GetRenderTargetTexture(),
.transform =
texture_rotate.Invert() *
Matrix::MakeTranslation(pass_texture_rect.GetOrigin()) *
Matrix::MakeScale((1 / scale) * (scaled_size / floored_size)),
.sampler_descriptor = sampler_desc,
.opacity = input_snapshot->opacity},
entity.GetBlendMode(), entity.GetClipDepth());
}
std::optional<Rect>
DirectionalGaussianBlurFilterContents::GetFilterSourceCoverage(
const Matrix& effect_transform,
const Rect& output_limit) const {
auto transform = effect_transform.Basis();
auto transformed_blur_vector =
transform.TransformDirection(blur_direction_ * Radius{blur_sigma_}.radius)
.Abs();
return output_limit.Expand(transformed_blur_vector);
}
std::optional<Rect> DirectionalGaussianBlurFilterContents::GetFilterCoverage(
const FilterInput::Vector& inputs,
const Entity& entity,
const Matrix& effect_transform) const {
if (inputs.empty()) {
return std::nullopt;
}
auto coverage = inputs[0]->GetCoverage(entity);
if (!coverage.has_value()) {
return std::nullopt;
}
auto transform = inputs[0]->GetTransform(entity) * effect_transform.Basis();
auto transformed_blur_vector =
transform
.TransformDirection(blur_direction_ *
Radius{ScaleSigma(blur_sigma_)}.radius)
.Abs();
return coverage->Expand(transformed_blur_vector);
}
} // namespace impeller

View File

@@ -1,112 +0,0 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_FILTERS_DIRECTIONAL_GAUSSIAN_BLUR_FILTER_CONTENTS_H_
#define FLUTTER_IMPELLER_ENTITY_CONTENTS_FILTERS_DIRECTIONAL_GAUSSIAN_BLUR_FILTER_CONTENTS_H_
#include <memory>
#include <optional>
#include "impeller/entity/contents/filters/filter_contents.h"
#include "impeller/entity/contents/filters/inputs/filter_input.h"
namespace impeller {
/// A gaussian blur filter that performs the work for one dimension of a
/// multi-dimensional Gaussian blur.
///
/// This filter takes a snapshot of its provided FilterInput, creates a new
/// render pass and blurs the contents. Two of these are chained together to
/// perform a full 2D blur effect.
///
/// Example:
///
/// Input Pass 1
/// +-------------+ +-----+
/// | | | |
/// | | | | Pass 2
/// | | | | +----+
/// | | | | | |
/// | | -> | | -> | |
/// | | | | | |
/// | | | | +----+
/// | | | | 87x102
/// +-------------+ +-----+
/// 586x678 97x678
///
/// The math for determining how much of the input should be processed for a
/// given sigma (aka radius) is found in `Sigma::operator Radius`. The math for
/// determining how much to scale down the input based on the radius is inside
/// the curve function in this implementation.
///
/// See also:
/// - `FilterContents::MakeGaussianBlur`
/// - //flutter/impeller/entity/shaders/gaussian_blur/gaussian_blur.glsl
///
///\deprecated Previously 2 of these were chained to do 2D blurs, use
/// \ref GaussianBlurFilterContents instead since it has better
/// performance.
class DirectionalGaussianBlurFilterContents final : public FilterContents {
public:
DirectionalGaussianBlurFilterContents();
~DirectionalGaussianBlurFilterContents() override;
/// Set sigma (stddev) used for 'direction_'.
void SetSigma(Sigma sigma);
/// Set sigma (stddev) used for direction 90 degrees from 'direction_'.
/// Not used if `!is_second_pass_`.
void SetSecondarySigma(Sigma sigma);
void SetDirection(Vector2 direction);
void SetBlurStyle(BlurStyle blur_style);
void SetTileMode(Entity::TileMode tile_mode);
/// Determines if this filter represents the second pass in a chained
/// 2D gaussian blur.
/// If `is_second_pass_ == true` then the `secondary_sigma_` is used to
/// determine the blur radius in the 90 degree rotation of direction_. Its
/// output aspect-ratio will closely match the FilterInput snapshot at the
/// beginning of the chain.
void SetIsSecondPass(bool is_second_pass);
// |FilterContents|
std::optional<Rect> GetFilterSourceCoverage(
const Matrix& effect_transform,
const Rect& output_limit) const override;
// |FilterContents|
std::optional<Rect> GetFilterCoverage(
const FilterInput::Vector& inputs,
const Entity& entity,
const Matrix& effect_transform) const override;
private:
// |FilterContents|
std::optional<Entity> RenderFilter(
const FilterInput::Vector& input_textures,
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage,
const std::optional<Rect>& coverage_hint) const override;
Sigma blur_sigma_;
Sigma secondary_blur_sigma_;
Vector2 blur_direction_;
BlurStyle blur_style_ = BlurStyle::kNormal;
Entity::TileMode tile_mode_ = Entity::TileMode::kDecal;
bool is_second_pass_ = false;
DirectionalGaussianBlurFilterContents(
const DirectionalGaussianBlurFilterContents&) = delete;
DirectionalGaussianBlurFilterContents& operator=(
const DirectionalGaussianBlurFilterContents&) = delete;
};
} // namespace impeller
#endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_FILTERS_DIRECTIONAL_GAUSSIAN_BLUR_FILTER_CONTENTS_H_

View File

@@ -1,226 +0,0 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/testing/testing.h"
#include "gmock/gmock.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.h"
#include "impeller/entity/contents/texture_contents.h"
#include "impeller/entity/entity_playground.h"
#include "impeller/geometry/geometry_asserts.h"
#include "impeller/renderer/testing/mocks.h"
namespace impeller {
namespace testing {
using ::testing::Return;
namespace {
Scalar CalculateSigmaForBlurRadius(Scalar blur_radius) {
// See Sigma.h
return (blur_radius / kKernelRadiusPerSigma) + 0.5;
}
} // namespace
class DirectionalGaussianBlurFilterContentsTest : public EntityPlayground {
public:
// Stubs in the minimal support to make rendering pass.
void SetupMinimalMockContext() {
// This mocking code was removed since it wasn't strictly needed yet. If it
// is needed you can find it here:
// https://gist.github.com/gaaclarke/c2f6bf5fc6ecb10678da03789abc5843.
}
};
INSTANTIATE_PLAYGROUND_SUITE(DirectionalGaussianBlurFilterContentsTest);
TEST_P(DirectionalGaussianBlurFilterContentsTest, CoverageWithEffectTransform) {
TextureDescriptor desc = {
.format = PixelFormat::kB8G8R8A8UNormInt,
.size = ISize(100, 100),
};
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
contents->SetSigma(Sigma{sigma_radius_1});
contents->SetDirection({1.0, 0.0});
std::shared_ptr<Texture> texture =
GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
desc);
FilterInput::Vector inputs = {FilterInput::Make(texture)};
Entity entity;
entity.SetTransform(Matrix::MakeTranslation({100, 100, 0}));
std::optional<Rect> coverage = contents->GetFilterCoverage(
inputs, entity, /*effect_transform=*/Matrix::MakeScale({2.0, 2.0, 1.0}));
EXPECT_TRUE(coverage.has_value());
if (coverage.has_value()) {
EXPECT_NEAR(coverage->GetLeft(), 100 - 2,
0.5); // Higher tolerance for sigma scaling.
EXPECT_NEAR(coverage->GetTop(), 100, 0.01);
EXPECT_NEAR(coverage->GetRight(), 200 + 2,
0.5); // Higher tolerance for sigma scaling.
EXPECT_NEAR(coverage->GetBottom(), 200, 0.01);
}
}
TEST(DirectionalGaussianBlurFilterContentsTest, FilterSourceCoverage) {
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
contents->SetSigma(Sigma{sigma_radius_1});
contents->SetDirection({1.0, 0.0});
std::optional<Rect> coverage = contents->GetFilterSourceCoverage(
/*effect_transform=*/Matrix::MakeScale({2.0, 2.0, 1.0}),
/*output_limit=*/Rect::MakeLTRB(100, 100, 200, 200));
ASSERT_EQ(coverage, Rect::MakeLTRB(100 - 2, 100, 200 + 2, 200));
}
TEST_P(DirectionalGaussianBlurFilterContentsTest, RenderNoCoverage) {
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
contents->SetSigma(Sigma{sigma_radius_1});
contents->SetDirection({1.0, 0.0});
std::shared_ptr<ContentContext> renderer = GetContentContext();
Entity entity;
Rect coverage_hint = Rect::MakeLTRB(0, 0, 0, 0);
std::optional<Entity> result =
contents->GetEntity(*renderer, entity, coverage_hint);
ASSERT_FALSE(result.has_value());
}
TEST_P(DirectionalGaussianBlurFilterContentsTest,
RenderCoverageMatchesGetCoverage) {
TextureDescriptor desc = {
.storage_mode = StorageMode::kDevicePrivate,
.format = PixelFormat::kB8G8R8A8UNormInt,
.size = ISize(100, 100),
};
std::shared_ptr<Texture> texture =
GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
desc);
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
contents->SetSigma(Sigma{sigma_radius_1});
contents->SetDirection({1.0, 0.0});
contents->SetInputs({FilterInput::Make(texture)});
std::shared_ptr<ContentContext> renderer = GetContentContext();
Entity entity;
std::optional<Entity> result =
contents->GetEntity(*renderer, entity, /*coverage_hint=*/{});
EXPECT_TRUE(result.has_value());
if (result.has_value()) {
EXPECT_EQ(result.value().GetBlendMode(), BlendMode::kSourceOver);
std::optional<Rect> result_coverage = result.value().GetCoverage();
std::optional<Rect> contents_coverage = contents->GetCoverage(entity);
EXPECT_TRUE(result_coverage.has_value());
EXPECT_TRUE(contents_coverage.has_value());
if (result_coverage.has_value() && contents_coverage.has_value()) {
EXPECT_TRUE(RectNear(result_coverage.value(), contents_coverage.value()));
// The precision on this blur is kind of off, thus the tolerance.
EXPECT_NEAR(result_coverage.value().GetLeft(), -1.f, 0.1f);
EXPECT_NEAR(result_coverage.value().GetTop(), 0.f, 0.001f);
EXPECT_NEAR(result_coverage.value().GetRight(), 101.f, 0.1f);
EXPECT_NEAR(result_coverage.value().GetBottom(), 100.f, 0.001f);
}
}
}
TEST_P(DirectionalGaussianBlurFilterContentsTest,
TextureContentsWithDestinationRect) {
TextureDescriptor desc = {
.storage_mode = StorageMode::kDevicePrivate,
.format = PixelFormat::kB8G8R8A8UNormInt,
.size = ISize(100, 100),
};
std::shared_ptr<Texture> texture =
GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
desc);
auto texture_contents = std::make_shared<TextureContents>();
texture_contents->SetSourceRect(Rect::MakeSize(texture->GetSize()));
texture_contents->SetTexture(texture);
texture_contents->SetDestinationRect(Rect::MakeXYWH(
50, 40, texture->GetSize().width, texture->GetSize().height));
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
contents->SetSigma(Sigma{sigma_radius_1});
contents->SetDirection({1.0, 0.0});
contents->SetInputs({FilterInput::Make(texture_contents)});
std::shared_ptr<ContentContext> renderer = GetContentContext();
Entity entity;
std::optional<Entity> result =
contents->GetEntity(*renderer, entity, /*coverage_hint=*/{});
EXPECT_TRUE(result.has_value());
if (result.has_value()) {
EXPECT_EQ(result.value().GetBlendMode(), BlendMode::kSourceOver);
std::optional<Rect> result_coverage = result.value().GetCoverage();
std::optional<Rect> contents_coverage = contents->GetCoverage(entity);
EXPECT_TRUE(result_coverage.has_value());
EXPECT_TRUE(contents_coverage.has_value());
if (result_coverage.has_value() && contents_coverage.has_value()) {
EXPECT_TRUE(RectNear(result_coverage.value(), contents_coverage.value()));
// The precision on this blur is kind of off, thus the tolerance.
EXPECT_NEAR(result_coverage.value().GetLeft(), 49.f, 0.1f);
EXPECT_NEAR(result_coverage.value().GetTop(), 40.f, 0.001f);
EXPECT_NEAR(result_coverage.value().GetRight(), 151.f, 0.1f);
EXPECT_NEAR(result_coverage.value().GetBottom(), 140.f, 0.001f);
}
}
}
TEST_P(DirectionalGaussianBlurFilterContentsTest,
TextureContentsWithDestinationRectScaled) {
TextureDescriptor desc = {
.storage_mode = StorageMode::kDevicePrivate,
.format = PixelFormat::kB8G8R8A8UNormInt,
.size = ISize(100, 100),
};
std::shared_ptr<Texture> texture =
GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
desc);
auto texture_contents = std::make_shared<TextureContents>();
texture_contents->SetSourceRect(Rect::MakeSize(texture->GetSize()));
texture_contents->SetTexture(texture);
texture_contents->SetDestinationRect(Rect::MakeXYWH(
50, 40, texture->GetSize().width, texture->GetSize().height));
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
contents->SetSigma(Sigma{sigma_radius_1});
contents->SetDirection({1.0, 0.0});
contents->SetInputs({FilterInput::Make(texture_contents)});
std::shared_ptr<ContentContext> renderer = GetContentContext();
Entity entity;
entity.SetTransform(Matrix::MakeScale({2.0, 2.0, 1.0}));
std::optional<Entity> result =
contents->GetEntity(*renderer, entity, /*coverage_hint=*/{});
EXPECT_TRUE(result.has_value());
if (result.has_value()) {
EXPECT_EQ(result.value().GetBlendMode(), BlendMode::kSourceOver);
std::optional<Rect> result_coverage = result.value().GetCoverage();
std::optional<Rect> contents_coverage = contents->GetCoverage(entity);
EXPECT_TRUE(result_coverage.has_value());
EXPECT_TRUE(contents_coverage.has_value());
if (result_coverage.has_value() && contents_coverage.has_value()) {
// The precision on this blur is kind of off, thus the tolerance.
EXPECT_NEAR(result_coverage.value().GetLeft(), 98.f, 0.1f);
EXPECT_NEAR(result_coverage.value().GetTop(), 80.f, 0.001f);
EXPECT_NEAR(result_coverage.value().GetRight(), 302.f, 0.1f);
EXPECT_NEAR(result_coverage.value().GetBottom(), 280.f, 0.001f);
EXPECT_NEAR(contents_coverage.value().GetLeft(), 98.f, 0.1f);
EXPECT_NEAR(contents_coverage.value().GetTop(), 80.f, 0.001f);
EXPECT_NEAR(contents_coverage.value().GetRight(), 302.f, 0.1f);
EXPECT_NEAR(contents_coverage.value().GetBottom(), 280.f, 0.001f);
}
}
}
} // namespace testing
} // namespace impeller

View File

@@ -16,7 +16,6 @@
#include "impeller/core/formats.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/contents/filters/border_mask_blur_filter_contents.h"
#include "impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.h"
#include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h"
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/contents/filters/local_matrix_filter_contents.h"
@@ -31,25 +30,6 @@
namespace impeller {
std::shared_ptr<FilterContents> FilterContents::MakeDirectionalGaussianBlur(
FilterInput::Ref input,
Sigma sigma,
Vector2 direction,
BlurStyle blur_style,
Entity::TileMode tile_mode,
bool is_second_pass,
Sigma secondary_sigma) {
auto blur = std::make_shared<DirectionalGaussianBlurFilterContents>();
blur->SetInputs({std::move(input)});
blur->SetSigma(sigma);
blur->SetDirection(direction);
blur->SetBlurStyle(blur_style);
blur->SetTileMode(tile_mode);
blur->SetIsSecondPass(is_second_pass);
blur->SetSecondarySigma(secondary_sigma);
return blur;
}
const int32_t FilterContents::kBlurFilterRequiredMipCount =
GaussianBlurFilterContents::kBlurFilterRequiredMipCount;

View File

@@ -35,17 +35,6 @@ class FilterContents : public Contents {
enum class MorphType { kDilate, kErode };
/// Creates a gaussian blur that operates in one direction.
/// See also: `MakeGaussianBlur`
static std::shared_ptr<FilterContents> MakeDirectionalGaussianBlur(
FilterInput::Ref input,
Sigma sigma,
Vector2 direction,
BlurStyle blur_style = BlurStyle::kNormal,
Entity::TileMode tile_mode = Entity::TileMode::kDecal,
bool is_second_pass = false,
Sigma secondary_sigma = {});
/// Creates a gaussian blur that operates in 2 dimensions.
/// See also: `MakeDirectionalGaussianBlur`
static std::shared_ptr<FilterContents> MakeGaussianBlur(

View File

@@ -994,8 +994,7 @@ TEST_P(EntityTest, GaussianBlurFilter) {
auto callback = [&](ContentContext& context, RenderPass& pass) -> bool {
const char* input_type_names[] = {"Texture", "Solid Color"};
const char* blur_type_names[] = {"Image blur", "Mask blur"};
const char* pass_variation_names[] = {"New", "2D Directional",
"Directional"};
const char* pass_variation_names[] = {"New"};
const char* blur_style_names[] = {"Normal", "Solid", "Outer", "Inner"};
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
const FilterContents::BlurStyle blur_styles[] = {
@@ -1108,13 +1107,6 @@ TEST_P(EntityTest, GaussianBlurFilter) {
FilterInput::Make(input), blur_sigma_x, blur_sigma_y,
blur_styles[selected_blur_style], tile_modes[selected_tile_mode]);
break;
case 2: {
Vector2 blur_vector(blur_sigma_x.sigma, blur_sigma_y.sigma);
blur = FilterContents::MakeDirectionalGaussianBlur(
FilterInput::Make(input), Sigma{blur_vector.GetLength()},
blur_vector.Normalize());
break;
}
};
FML_CHECK(blur);