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"
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 
28  public:
29  // Stubs in the minimal support to make rendering pass.
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 = {
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 
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 
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 
92  RenderCoverageMatchesGetCoverage) {
93  TextureDescriptor desc = {
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 
130  TextureContentsWithDestinationRect) {
131  TextureDescriptor desc = {
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 
175  TextureContentsWithDestinationRectScaled) {
176  TextureDescriptor desc = {
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