Flutter Impeller
aiks_dl_atlas_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 "display_list/dl_sampling_options.h"
6 #include "display_list/dl_types.h"
7 #include "display_list/effects/dl_color_filter.h"
8 #include "display_list/effects/image_filters/dl_matrix_image_filter.h"
9 #include "display_list/geometry/dl_geometry_types.h"
11 
12 #include "flutter/display_list/dl_blend_mode.h"
13 #include "flutter/display_list/dl_builder.h"
14 #include "flutter/display_list/dl_color.h"
15 #include "flutter/display_list/dl_paint.h"
16 #include "flutter/testing/testing.h"
17 #include "impeller/core/formats.h"
23 
24 namespace impeller {
25 namespace testing {
26 
27 using namespace flutter;
28 
29 namespace {
30 RSTransform MakeTranslation(Scalar tx, Scalar ty) {
31  return RSTransform::Make({tx, ty}, 1, DlDegrees(0));
32 }
33 
34 std::tuple<std::vector<DlRect>, //
35  std::vector<RSTransform>, //
36  sk_sp<DlImageImpeller>>
37 CreateTestData(const AiksTest* test) {
38  // Draws the image as four squares stiched together.
39  auto atlas =
40  DlImageImpeller::Make(test->CreateTextureForFixture("bay_bridge.jpg"));
41  auto size = atlas->impeller_texture()->GetSize();
42  // Divide image into four quadrants.
43  Scalar half_width = size.width / 2;
44  Scalar half_height = size.height / 2;
45  std::vector<DlRect> texture_coordinates = {
46  DlRect::MakeLTRB(0, 0, half_width, half_height),
47  DlRect::MakeLTRB(half_width, 0, size.width, half_height),
48  DlRect::MakeLTRB(0, half_height, half_width, size.height),
49  DlRect::MakeLTRB(half_width, half_height, size.width, size.height)};
50  // Position quadrants adjacent to eachother.
51  std::vector<RSTransform> transforms = {
52  MakeTranslation(0, 0), MakeTranslation(half_width, 0),
53  MakeTranslation(0, half_height),
54  MakeTranslation(half_width, half_height)};
55  return std::make_tuple(texture_coordinates, transforms, atlas);
56 }
57 
58 } // namespace
59 
60 TEST_P(AiksTest, DrawAtlasNoColor) {
61  DisplayListBuilder builder;
62  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
63 
64  builder.Scale(GetContentScale().x, GetContentScale().y);
65  builder.DrawAtlas(atlas, transforms.data(), texture_coordinates.data(),
66  /*colors=*/nullptr, /*count=*/4, DlBlendMode::kSrcOver,
67  DlImageSampling::kNearestNeighbor, nullptr);
68 
69  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
70 }
71 
72 TEST_P(AiksTest, DrawAtlasWithColorAdvanced) {
73  DisplayListBuilder builder;
74  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
75 
76  std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kGreen(),
77  DlColor::kBlue(), DlColor::kYellow()};
78 
79  builder.Scale(GetContentScale().x, GetContentScale().y);
80  builder.DrawAtlas(atlas, transforms.data(), texture_coordinates.data(),
81  colors.data(), /*count=*/4, DlBlendMode::kModulate,
82  DlImageSampling::kNearestNeighbor, /*cullRect=*/nullptr);
83 
84  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
85 }
86 
87 TEST_P(AiksTest, DrawAtlasWithColorSimple) {
88  DisplayListBuilder builder;
89  // Draws the image as four squares stiched together.
90  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
91 
92  std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kGreen(),
93  DlColor::kBlue(), DlColor::kYellow()};
94 
95  builder.Scale(GetContentScale().x, GetContentScale().y);
96  builder.DrawAtlas(atlas, transforms.data(), texture_coordinates.data(),
97  colors.data(), /*count=*/4, DlBlendMode::kSrcATop,
98  DlImageSampling::kNearestNeighbor, /*cullRect=*/nullptr);
99 
100  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
101 }
102 
103 TEST_P(AiksTest, DrawAtlasWithOpacity) {
104  DisplayListBuilder builder;
105  // Draws the image as four squares stiched together slightly
106  // opaque
107  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
108 
109  DlPaint paint;
110  paint.setAlpha(128);
111  builder.Scale(GetContentScale().x, GetContentScale().y);
112  builder.DrawAtlas(atlas, transforms.data(), texture_coordinates.data(),
113  /*colors=*/nullptr, 4, DlBlendMode::kSrcOver,
114  DlImageSampling::kNearestNeighbor, /*cullRect=*/nullptr,
115  &paint);
116 
117  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
118 }
119 
120 TEST_P(AiksTest, DrawAtlasNoColorFullSize) {
121  auto atlas = DlImageImpeller::Make(CreateTextureForFixture("bay_bridge.jpg"));
122  auto size = atlas->impeller_texture()->GetSize();
123  std::vector<DlRect> texture_coordinates = {
124  DlRect::MakeLTRB(0, 0, size.width, size.height)};
125  std::vector<RSTransform> transforms = {MakeTranslation(0, 0)};
126 
127  DisplayListBuilder builder;
128  builder.Scale(GetContentScale().x, GetContentScale().y);
129  builder.DrawAtlas(atlas, transforms.data(), texture_coordinates.data(),
130  /*colors=*/nullptr, /*count=*/1, DlBlendMode::kSrcOver,
131  DlImageSampling::kNearestNeighbor, /*cullRect=*/nullptr);
132 
133  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
134 }
135 
136 // Regression test for https://github.com/flutter/flutter/issues/127374.
137 TEST_P(AiksTest, DrawAtlasAdvancedAndTransform) {
138  DisplayListBuilder builder;
139  // Draws the image as four squares stiched together.
140  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
141 
142  builder.Scale(0.25, 0.25);
143  builder.DrawAtlas(atlas, transforms.data(), texture_coordinates.data(),
144  /*colors=*/nullptr, /*count=*/4, DlBlendMode::kModulate,
145  DlImageSampling::kNearestNeighbor, /*cullRect=*/nullptr);
146 
147  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
148 }
149 
150 // Regression test for https://github.com/flutter/flutter/issues/127374.
151 TEST_P(AiksTest, DrawAtlasWithColorAdvancedAndTransform) {
152  DisplayListBuilder builder;
153  // Draws the image as four squares stiched together.
154  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
155  std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kGreen(),
156  DlColor::kBlue(), DlColor::kYellow()};
157 
158  builder.Scale(0.25, 0.25);
159  builder.DrawAtlas(atlas, transforms.data(), texture_coordinates.data(),
160  colors.data(), /*count=*/4, DlBlendMode::kModulate,
161  DlImageSampling::kNearestNeighbor, /*cullRect=*/nullptr);
162 
163  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
164 }
165 
166 TEST_P(AiksTest, DrawAtlasPlusWideGamut) {
167  DisplayListBuilder builder;
168  EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
170 
171  // Draws the image as four squares stiched together.
172  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
173  std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kGreen(),
174  DlColor::kBlue(), DlColor::kYellow()};
175 
176  builder.DrawAtlas(atlas, transforms.data(), texture_coordinates.data(),
177  colors.data(), /*count=*/4, DlBlendMode::kPlus,
178  DlImageSampling::kNearestNeighbor, /*cullRect=*/nullptr);
179 
180  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
181 }
182 
183 TEST_P(AiksTest, DlAtlasGeometryNoBlendRenamed) {
184  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
185 
186  DlAtlasGeometry geom(atlas->impeller_texture(), transforms.data(),
187  texture_coordinates.data(), nullptr, transforms.size(),
188  BlendMode::kSrcOver, {}, std::nullopt);
189 
190  EXPECT_FALSE(geom.ShouldUseBlend());
191  EXPECT_FALSE(geom.ShouldSkip());
192 
193  ContentContext context(GetContext(), nullptr);
194  auto vertex_buffer =
196 
197  EXPECT_EQ(vertex_buffer.index_type, IndexType::kNone);
198  EXPECT_EQ(vertex_buffer.vertex_count, texture_coordinates.size() * 6);
199 }
200 
201 TEST_P(AiksTest, DlAtlasGeometryBlend) {
202  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
203 
204  std::vector<DlColor> colors;
205  colors.reserve(texture_coordinates.size());
206  for (auto i = 0u; i < texture_coordinates.size(); i++) {
207  colors.push_back(DlColor::ARGB(0.5, 1, 1, 1));
208  }
209  DlAtlasGeometry geom(
210  atlas->impeller_texture(), transforms.data(), texture_coordinates.data(),
211  colors.data(), transforms.size(), BlendMode::kSrcOver, {}, std::nullopt);
212 
213  EXPECT_TRUE(geom.ShouldUseBlend());
214  EXPECT_FALSE(geom.ShouldSkip());
215 
216  ContentContext context(GetContext(), nullptr);
217  auto vertex_buffer =
219 
220  EXPECT_EQ(vertex_buffer.index_type, IndexType::kNone);
221  EXPECT_EQ(vertex_buffer.vertex_count, texture_coordinates.size() * 6);
222 }
223 
224 TEST_P(AiksTest, DlAtlasGeometryColorButNoBlend) {
225  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
226 
227  std::vector<DlColor> colors;
228  colors.reserve(texture_coordinates.size());
229  for (auto i = 0u; i < texture_coordinates.size(); i++) {
230  colors.push_back(DlColor::ARGB(0.5, 1, 1, 1));
231  }
232  DlAtlasGeometry geom(atlas->impeller_texture(), transforms.data(),
233  texture_coordinates.data(), colors.data(),
234  transforms.size(), BlendMode::kSrc, {}, std::nullopt);
235 
236  // Src blend mode means that colors would be ignored, even if provided.
237  EXPECT_FALSE(geom.ShouldUseBlend());
238  EXPECT_FALSE(geom.ShouldSkip());
239 }
240 
241 TEST_P(AiksTest, DlAtlasGeometrySkip) {
242  auto [texture_coordinates, transforms, atlas] = CreateTestData(this);
243 
244  std::vector<DlColor> colors;
245  colors.reserve(texture_coordinates.size());
246  for (auto i = 0u; i < texture_coordinates.size(); i++) {
247  colors.push_back(DlColor::ARGB(0.5, 1, 1, 1));
248  }
249  DlAtlasGeometry geom(atlas->impeller_texture(), transforms.data(),
250  texture_coordinates.data(), colors.data(),
251  transforms.size(), BlendMode::kClear, {}, std::nullopt);
252  EXPECT_TRUE(geom.ShouldSkip());
253 }
254 
255 TEST_P(AiksTest, DrawImageRectWithBlendColorFilter) {
256  sk_sp<DlImageImpeller> texture =
257  DlImageImpeller::Make(CreateTextureForFixture("bay_bridge.jpg"));
258 
259  DisplayListBuilder builder;
260  DlPaint paint = DlPaint().setColorFilter(DlColorFilter::MakeBlend(
261  DlColor::kRed().withAlphaF(0.4), DlBlendMode::kSrcOver));
262 
263  DlMatrix filter_matrix = DlMatrix();
264  auto filter = flutter::DlMatrixImageFilter(filter_matrix,
265  flutter::DlImageSampling::kLinear);
266  DlPaint paint_with_filter = paint;
267  paint_with_filter.setImageFilter(&filter);
268 
269  // Compare porter-duff blend modes.
270  builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
271  // Uses image filter to disable atlas conversion.
272  builder.DrawImageRect(texture, DlRect::MakeSize(texture->GetSize()),
273  DlRect::MakeLTRB(0, 0, 500, 500), {},
274  &paint_with_filter);
275 
276  // Uses atlas conversion.
277  builder.Translate(600, 0);
278  builder.DrawImageRect(texture, DlRect::MakeSize(texture->GetSize()),
279  DlRect::MakeLTRB(0, 0, 500, 500), {}, &paint);
280 
281  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
282 }
283 
284 TEST_P(AiksTest, DrawImageRectWithMatrixColorFilter) {
285  sk_sp<DlImageImpeller> texture =
286  DlImageImpeller::Make(CreateTextureForFixture("bay_bridge.jpg"));
287 
288  DisplayListBuilder builder;
289  static const constexpr ColorMatrix kColorInversion = {
290  .array = {
291  -1.0, 0, 0, 1.0, 0, //
292  0, -1.0, 0, 1.0, 0, //
293  0, 0, -1.0, 1.0, 0, //
294  1.0, 1.0, 1.0, 1.0, 0 //
295  }};
296  DlPaint paint = DlPaint().setColorFilter(
297  DlColorFilter::MakeMatrix(kColorInversion.array));
298 
299  DlMatrix filter_matrix = DlMatrix();
300  auto filter = flutter::DlMatrixImageFilter(filter_matrix,
301  flutter::DlImageSampling::kLinear);
302  DlPaint paint_with_filter = paint;
303  paint_with_filter.setImageFilter(&filter);
304 
305  // Compare inverting color matrix filter.
306  builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
307  // Uses image filter to disable atlas conversion.
308  builder.DrawImageRect(texture, DlRect::MakeSize(texture->GetSize()),
309  DlRect::MakeLTRB(0, 0, 500, 500), {},
310  &paint_with_filter);
311 
312  // Uses atlas conversion.
313  builder.Translate(600, 0);
314  builder.DrawImageRect(texture, DlRect::MakeSize(texture->GetSize()),
315  DlRect::MakeLTRB(0, 0, 500, 500), {}, &paint);
316 
317  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
318 }
319 
320 } // namespace testing
321 } // namespace impeller
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
A wrapper around data provided by a drawAtlas call.
VertexBuffer CreateBlendVertexBuffer(HostBuffer &host_buffer) const override
bool ShouldUseBlend() const override
Whether the blend shader should be used.
bool ShouldSkip() const override
VertexBuffer CreateSimpleVertexBuffer(HostBuffer &host_buffer) const override
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
int32_t x
AiksPlayground AiksTest
TEST_P(AiksTest, DrawAtlasNoColor)
@ kNone
Does not use the index buffer.
float Scalar
Definition: scalar.h:19
static constexpr const ColorMatrix kColorInversion
A color matrix which inverts colors.
Definition: color_filter.h:16
Scalar array[20]
Definition: color.h:118
static RSTransform Make(Point origin, Scalar scale, Radians radians)
Definition: rstransform.h:38