| 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>>
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(),
169 PixelFormat::kB10G10R10A10XR);
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 =
195 geom.CreateSimpleVertexBuffer(context.GetTransientsBuffer());
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 =
218 geom.CreateBlendVertexBuffer(context.GetTransientsBuffer());
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
aiks_unittests.h
impeller::AiksPlayground
Definition: aiks_playground.h:16
impeller::ContentContext
Definition: content_context.h:138
impeller::ContentContext::GetTransientsBuffer
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Definition: content_context.h:297
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:60
impeller
Definition: allocation.cc:12
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::Scalar
float Scalar
Definition: scalar.h:19
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