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