| Flutter Impeller |

directional_gaussian_blur_filter_contents_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/testing/testing.h"
6 #include "gmock/gmock.h"
7 #include "impeller/entity/contents/content_context.h"
8 #include "impeller/entity/contents/filters/directional_gaussian_blur_filter_contents.h"
9 #include "impeller/entity/contents/texture_contents.h"
10 #include "impeller/entity/entity_playground.h"
11 #include "impeller/geometry/geometry_asserts.h"
12 #include "impeller/renderer/testing/mocks.h"
13
14 namespace impeller {
15 namespace testing {
16
17 using ::testing::Return;
18
19 namespace {
20
21 Scalar CalculateSigmaForBlurRadius(Scalar blur_radius) {
22 // See Sigma.h
23 return (blur_radius / kKernelRadiusPerSigma) + 0.5;
24 }
25 } // namespace
26
27 class DirectionalGaussianBlurFilterContentsTest : public EntityPlayground {
28 public:
29 // Stubs in the minimal support to make rendering pass.
30 void SetupMinimalMockContext() {
31 // This mocking code was removed since it wasn't strictly needed yet. If it
32 // is needed you can find it here:
33 // https://gist.github.com/gaaclarke/c2f6bf5fc6ecb10678da03789abc5843.
34 }
35 };
36
37 INSTANTIATE_PLAYGROUND_SUITE(DirectionalGaussianBlurFilterContentsTest);
38
39 TEST_P(DirectionalGaussianBlurFilterContentsTest, CoverageWithEffectTransform) {
40 TextureDescriptor desc = {
41 .format = PixelFormat::kB8G8R8A8UNormInt,
42 .size = ISize(100, 100),
43 };
44 Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
45 auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
46 contents->SetSigma(Sigma{sigma_radius_1});
47 contents->SetDirection({1.0, 0.0});
48 std::shared_ptr<Texture> texture =
49 GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
50 desc);
51 FilterInput::Vector inputs = {FilterInput::Make(texture)};
52 Entity entity;
53 entity.SetTransform(Matrix::MakeTranslation({100, 100, 0}));
54 std::optional<Rect> coverage = contents->GetFilterCoverage(
55 inputs, entity, /*effect_transform=*/Matrix::MakeScale({2.0, 2.0, 1.0}));
56 EXPECT_TRUE(coverage.has_value());
57 if (coverage.has_value()) {
58 EXPECT_NEAR(coverage->GetLeft(), 100 - 2,
59 0.5); // Higher tolerance for sigma scaling.
60 EXPECT_NEAR(coverage->GetTop(), 100, 0.01);
61 EXPECT_NEAR(coverage->GetRight(), 200 + 2,
62 0.5); // Higher tolerance for sigma scaling.
63 EXPECT_NEAR(coverage->GetBottom(), 200, 0.01);
64 }
65 }
66
67 TEST(DirectionalGaussianBlurFilterContentsTest, FilterSourceCoverage) {
68 Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
69 auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
70 contents->SetSigma(Sigma{sigma_radius_1});
71 contents->SetDirection({1.0, 0.0});
72 std::optional<Rect> coverage = contents->GetFilterSourceCoverage(
73 /*effect_transform=*/Matrix::MakeScale({2.0, 2.0, 1.0}),
74 /*output_limit=*/Rect::MakeLTRB(100, 100, 200, 200));
75 ASSERT_EQ(coverage, Rect::MakeLTRB(100 - 2, 100, 200 + 2, 200));
76 }
77
78 TEST_P(DirectionalGaussianBlurFilterContentsTest, RenderNoCoverage) {
79 Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
80 auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
81 contents->SetSigma(Sigma{sigma_radius_1});
82 contents->SetDirection({1.0, 0.0});
83 std::shared_ptr<ContentContext> renderer = GetContentContext();
84 Entity entity;
85 Rect coverage_hint = Rect::MakeLTRB(0, 0, 0, 0);
86 std::optional<Entity> result =
87 contents->GetEntity(*renderer, entity, coverage_hint);
88 ASSERT_FALSE(result.has_value());
89 }
90
91 TEST_P(DirectionalGaussianBlurFilterContentsTest,
92 RenderCoverageMatchesGetCoverage) {
93 TextureDescriptor desc = {
94 .storage_mode = StorageMode::kDevicePrivate,
95 .format = PixelFormat::kB8G8R8A8UNormInt,
96 .size = ISize(100, 100),
97 };
98 std::shared_ptr<Texture> texture =
99 GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
100 desc);
101 Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
102 auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
103 contents->SetSigma(Sigma{sigma_radius_1});
104 contents->SetDirection({1.0, 0.0});
105 contents->SetInputs({FilterInput::Make(texture)});
106 std::shared_ptr<ContentContext> renderer = GetContentContext();
107
108 Entity entity;
109 std::optional<Entity> result =
110 contents->GetEntity(*renderer, entity, /*coverage_hint=*/{});
111 EXPECT_TRUE(result.has_value());
112 if (result.has_value()) {
113 EXPECT_EQ(result.value().GetBlendMode(), BlendMode::kSourceOver);
114 std::optional<Rect> result_coverage = result.value().GetCoverage();
115 std::optional<Rect> contents_coverage = contents->GetCoverage(entity);
116 EXPECT_TRUE(result_coverage.has_value());
117 EXPECT_TRUE(contents_coverage.has_value());
118 if (result_coverage.has_value() && contents_coverage.has_value()) {
119 EXPECT_TRUE(RectNear(result_coverage.value(), contents_coverage.value()));
120 // The precision on this blur is kind of off, thus the tolerance.
121 EXPECT_NEAR(result_coverage.value().GetLeft(), -1.f, 0.1f);
122 EXPECT_NEAR(result_coverage.value().GetTop(), 0.f, 0.001f);
123 EXPECT_NEAR(result_coverage.value().GetRight(), 101.f, 0.1f);
124 EXPECT_NEAR(result_coverage.value().GetBottom(), 100.f, 0.001f);
125 }
126 }
127 }
128
129 TEST_P(DirectionalGaussianBlurFilterContentsTest,
130 TextureContentsWithDestinationRect) {
131 TextureDescriptor desc = {
132 .storage_mode = StorageMode::kDevicePrivate,
133 .format = PixelFormat::kB8G8R8A8UNormInt,
134 .size = ISize(100, 100),
135 };
136
137 std::shared_ptr<Texture> texture =
138 GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
139 desc);
140 auto texture_contents = std::make_shared<TextureContents>();
141 texture_contents->SetSourceRect(Rect::MakeSize(texture->GetSize()));
142 texture_contents->SetTexture(texture);
143 texture_contents->SetDestinationRect(Rect::MakeXYWH(
144 50, 40, texture->GetSize().width, texture->GetSize().height));
145
146 Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
147 auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
148 contents->SetSigma(Sigma{sigma_radius_1});
149 contents->SetDirection({1.0, 0.0});
150 contents->SetInputs({FilterInput::Make(texture_contents)});
151 std::shared_ptr<ContentContext> renderer = GetContentContext();
152
153 Entity entity;
154 std::optional<Entity> result =
155 contents->GetEntity(*renderer, entity, /*coverage_hint=*/{});
156 EXPECT_TRUE(result.has_value());
157 if (result.has_value()) {
158 EXPECT_EQ(result.value().GetBlendMode(), BlendMode::kSourceOver);
159 std::optional<Rect> result_coverage = result.value().GetCoverage();
160 std::optional<Rect> contents_coverage = contents->GetCoverage(entity);
161 EXPECT_TRUE(result_coverage.has_value());
162 EXPECT_TRUE(contents_coverage.has_value());
163 if (result_coverage.has_value() && contents_coverage.has_value()) {
164 EXPECT_TRUE(RectNear(result_coverage.value(), contents_coverage.value()));
165 // The precision on this blur is kind of off, thus the tolerance.
166 EXPECT_NEAR(result_coverage.value().GetLeft(), 49.f, 0.1f);
167 EXPECT_NEAR(result_coverage.value().GetTop(), 40.f, 0.001f);
168 EXPECT_NEAR(result_coverage.value().GetRight(), 151.f, 0.1f);
169 EXPECT_NEAR(result_coverage.value().GetBottom(), 140.f, 0.001f);
170 }
171 }
172 }
173
174 TEST_P(DirectionalGaussianBlurFilterContentsTest,
175 TextureContentsWithDestinationRectScaled) {
176 TextureDescriptor desc = {
177 .storage_mode = StorageMode::kDevicePrivate,
178 .format = PixelFormat::kB8G8R8A8UNormInt,
179 .size = ISize(100, 100),
180 };
181
182 std::shared_ptr<Texture> texture =
183 GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
184 desc);
185 auto texture_contents = std::make_shared<TextureContents>();
186 texture_contents->SetSourceRect(Rect::MakeSize(texture->GetSize()));
187 texture_contents->SetTexture(texture);
188 texture_contents->SetDestinationRect(Rect::MakeXYWH(
189 50, 40, texture->GetSize().width, texture->GetSize().height));
190
191 Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
192 auto contents = std::make_unique<DirectionalGaussianBlurFilterContents>();
193 contents->SetSigma(Sigma{sigma_radius_1});
194 contents->SetDirection({1.0, 0.0});
195 contents->SetInputs({FilterInput::Make(texture_contents)});
196 std::shared_ptr<ContentContext> renderer = GetContentContext();
197
198 Entity entity;
199 entity.SetTransform(Matrix::MakeScale({2.0, 2.0, 1.0}));
200 std::optional<Entity> result =
201 contents->GetEntity(*renderer, entity, /*coverage_hint=*/{});
202 EXPECT_TRUE(result.has_value());
203 if (result.has_value()) {
204 EXPECT_EQ(result.value().GetBlendMode(), BlendMode::kSourceOver);
205 std::optional<Rect> result_coverage = result.value().GetCoverage();
206 std::optional<Rect> contents_coverage = contents->GetCoverage(entity);
207 EXPECT_TRUE(result_coverage.has_value());
208 EXPECT_TRUE(contents_coverage.has_value());
209 if (result_coverage.has_value() && contents_coverage.has_value()) {
210 // The precision on this blur is kind of off, thus the tolerance.
211
212 EXPECT_NEAR(result_coverage.value().GetLeft(), 98.f, 0.1f);
213 EXPECT_NEAR(result_coverage.value().GetTop(), 80.f, 0.001f);
214 EXPECT_NEAR(result_coverage.value().GetRight(), 302.f, 0.1f);
215 EXPECT_NEAR(result_coverage.value().GetBottom(), 280.f, 0.001f);
216
217 EXPECT_NEAR(contents_coverage.value().GetLeft(), 98.f, 0.1f);
218 EXPECT_NEAR(contents_coverage.value().GetTop(), 80.f, 0.001f);
219 EXPECT_NEAR(contents_coverage.value().GetRight(), 302.f, 0.1f);
220 EXPECT_NEAR(contents_coverage.value().GetBottom(), 280.f, 0.001f);
221 }
222 }
223 }
224
225 } // namespace testing
226 } // namespace impeller
impeller::Scalar
float Scalar
Definition: scalar.h:18
texture_contents.h
geometry_asserts.h
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:34
impeller::FilterInput::Make
static FilterInput::Ref Make(Variant input, bool msaa_enabled=true)
Definition: filter_input.cc:19
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:40
impeller::testing::DirectionalGaussianBlurFilterContentsTest::SetupMinimalMockContext
void SetupMinimalMockContext()
Definition: directional_gaussian_blur_filter_contents_unittests.cc:30
impeller::testing::DirectionalGaussianBlurFilterContentsTest
Definition: directional_gaussian_blur_filter_contents_unittests.cc:27
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::testing::INSTANTIATE_PLAYGROUND_SUITE
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
impeller::Entity
Definition: entity.h:21
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
impeller::testing::TEST
TEST(CanvasRecorder, Save)
Definition: canvas_recorder_unittests.cc:61
impeller::Sigma
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
Definition: sigma.h:32
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:138
content_context.h
impeller::EntityPlayground
Definition: entity_playground.h:18
impeller::Entity::SetTransform
void SetTransform(const Matrix &transform)
Set the global transform matrix for this Entity.
Definition: entity.cc:53
RectNear
inline ::testing::AssertionResult RectNear(impeller::Rect a, impeller::Rect b)
Definition: geometry_asserts.h:56
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:44
directional_gaussian_blur_filter_contents.h
impeller::kKernelRadiusPerSigma
constexpr static float kKernelRadiusPerSigma
Definition: sigma.h:24
impeller::TextureDescriptor::storage_mode
StorageMode storage_mode
Definition: texture_descriptor.h:38
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:27
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:37
impeller::FilterInput::Vector
std::vector< FilterInput::Ref > Vector
Definition: filter_input.h:33
impeller::testing::TEST_P
TEST_P(AiksTest, CanRenderLinearGradientClamp)
Definition: aiks_gradient_unittests.cc:48
impeller::PixelFormat::kB8G8R8A8UNormInt
@ kB8G8R8A8UNormInt
impeller
Definition: aiks_context.cc:10
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::TRect< Scalar >
impeller::BlendMode::kSourceOver
@ kSourceOver
entity_playground.h