| Flutter Impeller |

aiks_dl_runtime_effect_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 <memory>
6
7 #include "absl/status/statusor.h"
8
9 #include "flutter/display_list/dl_builder.h"
10 #include "flutter/display_list/dl_paint.h"
11 #include "flutter/display_list/effects/dl_color_source.h"
12 #include "flutter/display_list/effects/dl_image_filter.h"
13 #include "flutter/display_list/effects/dl_runtime_effect.h"
14 #include "flutter/impeller/display_list/aiks_unittests.h"
15 #include "flutter/impeller/display_list/dl_image_impeller.h"
16 #include "flutter/impeller/display_list/dl_runtime_effect_impeller.h"
17 #include "imgui.h"
18 #include "impeller/geometry/point.h"
19 #include "impeller/geometry/vector.h"
20 #include "third_party/abseil-cpp/absl/status/status_matchers.h"
21
22 namespace impeller {
23 namespace testing {
24
25 using namespace flutter;
26
27 namespace {
28 absl::StatusOr<std::shared_ptr<DlColorSource>> MakeRuntimeEffect(
29 AiksTest* test,
30 std::string_view name,
31 const std::shared_ptr<std::vector<uint8_t>>& uniform_data = {},
32 const std::vector<std::shared_ptr<DlColorSource>>& samplers = {}) {
33 auto runtime_stages_result = test->OpenAssetAsRuntimeStage(name.data());
34 if (!runtime_stages_result.ok()) {
35 return runtime_stages_result.status();
36 }
37 std::shared_ptr<RuntimeStage> runtime_stage =
38 runtime_stages_result
39 .value()[PlaygroundBackendToRuntimeStageBackend(test->GetBackend())];
40 if (!runtime_stage) {
41 return absl::InternalError("Runtime stage not found for backend.");
42 }
43 if (!runtime_stage->IsDirty()) {
44 return absl::InternalError("Runtime stage is not dirty.");
45 }
46
47 auto dl_runtime_effect = DlRuntimeEffectImpeller::Make(runtime_stage);
48
49 return DlColorSource::MakeRuntimeEffect(dl_runtime_effect, samplers,
50 uniform_data);
51 }
52 } // namespace
53
54 // Regression test for https://github.com/flutter/flutter/issues/126701 .
55 TEST_P(AiksTest, CanRenderClippedRuntimeEffects) {
56 struct FragUniforms {
57 Vector2 iResolution;
58 Scalar iTime;
59 } frag_uniforms = {.iResolution = Vector2(400, 400), .iTime = 100.0};
60 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
61 uniform_data->resize(sizeof(FragUniforms));
62 memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms));
63
64 DlPaint paint;
65 auto effect =
66 MakeRuntimeEffect(this, "runtime_stage_example.frag.iplr", uniform_data);
67 ABSL_ASSERT_OK(effect);
68 paint.setColorSource(effect.value());
69
70 DisplayListBuilder builder;
71 builder.Save();
72 builder.ClipRoundRect(
73 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(0, 0, 400, 400), 10.0, 10.0),
74 DlClipOp::kIntersect);
75 builder.DrawRect(DlRect::MakeXYWH(0, 0, 400, 400), paint);
76 builder.Restore();
77
78 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
79 }
80
81 TEST_P(AiksTest, DrawPaintTransformsBounds) {
82 struct FragUniforms {
83 Size size;
84 } frag_uniforms = {.size = Size::MakeWH(400, 400)};
85 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
86 uniform_data->resize(sizeof(FragUniforms));
87 memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms));
88
89 DlPaint paint;
90 auto effect = MakeRuntimeEffect(this, "gradient.frag.iplr", uniform_data);
91 ABSL_ASSERT_OK(effect);
92 paint.setColorSource(effect.value());
93
94 DisplayListBuilder builder;
95 builder.Save();
96 builder.Scale(GetContentScale().x, GetContentScale().y);
97 builder.DrawPaint(paint);
98 builder.Restore();
99
100 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
101 }
102
103 TEST_P(AiksTest, CanRenderRuntimeEffectFilter) {
104 auto runtime_stages_result =
105 OpenAssetAsRuntimeStage("runtime_stage_filter_example.frag.iplr");
106 ABSL_ASSERT_OK(runtime_stages_result);
107 std::shared_ptr<RuntimeStage> runtime_stage =
108 runtime_stages_result
109 .value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
110 ASSERT_TRUE(runtime_stage);
111 ASSERT_TRUE(runtime_stage->IsDirty());
112
113 std::vector<std::shared_ptr<DlColorSource>> sampler_inputs = {
114 nullptr,
115 };
116 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
117 uniform_data->resize(sizeof(Vector2));
118
119 DlPaint paint;
120 paint.setColor(DlColor::kAqua());
121 paint.setImageFilter(DlImageFilter::MakeRuntimeEffect(
122 DlRuntimeEffectImpeller::Make(runtime_stage), sampler_inputs,
123 uniform_data));
124
125 DisplayListBuilder builder;
126 builder.DrawRect(DlRect::MakeXYWH(0, 0, 400, 400), paint);
127
128 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
129 }
130
131 TEST_P(AiksTest, RuntimeEffectWithInvalidSamplerDoesNotCrash) {
132 ScopedValidationDisable disable_validation;
133
134 // Create a sampler that is not usable as an input to the runtime effect.
135 std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
136 flutter::DlColor::kRed()};
137 const float stops[2] = {0.0, 1.0};
138 auto linear = flutter::DlColorSource::MakeLinear({0.0, 0.0}, {300.0, 300.0},
139 2, colors.data(), stops,
140 flutter::DlTileMode::kClamp);
141 std::vector<std::shared_ptr<DlColorSource>> sampler_inputs = {
142 linear,
143 };
144
145 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
146 uniform_data->resize(sizeof(Vector2));
147
148 DlPaint paint;
149 auto effect =
150 MakeRuntimeEffect(this, "runtime_stage_filter_example.frag.iplr",
151 uniform_data, sampler_inputs);
152 ABSL_ASSERT_OK(effect);
153 paint.setColorSource(effect.value());
154
155 DisplayListBuilder builder;
156 builder.DrawPaint(paint);
157
158 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
159 }
160
161 TEST_P(AiksTest, ComposePaintRuntimeOuter) {
162 DisplayListBuilder builder;
163 DlPaint background;
164 background.setColor(DlColor(1.0, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
165 builder.DrawPaint(background);
166
167 DlPaint paint;
168 paint.setColor(DlColor::kGreen());
169 float matrix[] = {
170 0, 1, 0, 0, 0, //
171 1, 0, 0, 0, 0, //
172 0, 0, 1, 0, 0, //
173 0, 0, 0, 1, 0 //
174 };
175 std::shared_ptr<DlImageFilter> color_filter =
176 DlImageFilter::MakeColorFilter(DlColorFilter::MakeMatrix(matrix));
177
178 auto runtime_stages_result =
179 OpenAssetAsRuntimeStage("runtime_stage_filter_warp.frag.iplr");
180 ABSL_ASSERT_OK(runtime_stages_result);
181 std::shared_ptr<RuntimeStage> runtime_stage =
182 runtime_stages_result
183 .value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
184 ASSERT_TRUE(runtime_stage);
185 ASSERT_TRUE(runtime_stage->IsDirty());
186
187 std::vector<std::shared_ptr<DlColorSource>> sampler_inputs = {
188 nullptr,
189 };
190 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
191 uniform_data->resize(sizeof(Vector2));
192
193 auto runtime_filter = DlImageFilter::MakeRuntimeEffect(
194 DlRuntimeEffectImpeller::Make(runtime_stage), sampler_inputs,
195 uniform_data);
196
197 builder.Translate(50, 50);
198 builder.Scale(0.7, 0.7);
199
200 paint.setImageFilter(
201 DlImageFilter::MakeCompose(runtime_filter, color_filter));
202 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
203 builder.DrawImage(image, DlPoint(100.0, 100.0),
204 DlImageSampling::kNearestNeighbor, &paint);
205
206 DlPaint green;
207 green.setColor(DlColor::kGreen());
208 builder.DrawLine({100, 100}, {200, 100}, green);
209 builder.DrawLine({100, 100}, {100, 200}, green);
210
211 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
212 }
213
214 TEST_P(AiksTest, ComposePaintRuntimeInner) {
215 auto runtime_stages_result =
216 OpenAssetAsRuntimeStage("runtime_stage_filter_warp.frag.iplr");
217 ABSL_ASSERT_OK(runtime_stages_result);
218 std::shared_ptr<RuntimeStage> runtime_stage =
219 runtime_stages_result
220 .value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
221 ASSERT_TRUE(runtime_stage);
222 ASSERT_TRUE(runtime_stage->IsDirty());
223 Scalar xoffset = 50;
224 Scalar yoffset = 50;
225 Scalar xscale = 0.7;
226 Scalar yscale = 0.7;
227 bool compare = false;
228
229 auto callback = [&]() -> sk_sp<DisplayList> {
230 if (AiksTest::ImGuiBegin("Controls", nullptr,
231 ImGuiWindowFlags_AlwaysAutoResize)) {
232 ImGui::SliderFloat("xoffset", &xoffset, -50, 50);
233 ImGui::SliderFloat("yoffset", &yoffset, -50, 50);
234 ImGui::SliderFloat("xscale", &xscale, 0, 1);
235 ImGui::SliderFloat("yscale", &yscale, 0, 1);
236 ImGui::Checkbox("compare", &compare);
237 ImGui::End();
238 }
239 DisplayListBuilder builder;
240 DlPaint background;
241 background.setColor(DlColor(1.0, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
242 builder.DrawPaint(background);
243
244 DlPaint paint;
245 paint.setColor(DlColor::kGreen());
246 float matrix[] = {
247 0, 1, 0, 0, 0, //
248 1, 0, 0, 0, 0, //
249 0, 0, 1, 0, 0, //
250 0, 0, 0, 1, 0 //
251 };
252 std::shared_ptr<DlImageFilter> color_filter =
253 DlImageFilter::MakeColorFilter(DlColorFilter::MakeMatrix(matrix));
254
255 std::vector<std::shared_ptr<DlColorSource>> sampler_inputs = {
256 nullptr,
257 };
258 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
259 uniform_data->resize(sizeof(Vector2));
260
261 auto runtime_filter = DlImageFilter::MakeRuntimeEffect(
262 DlRuntimeEffectImpeller::Make(runtime_stage), sampler_inputs,
263 uniform_data);
264
265 builder.Translate(xoffset, yoffset);
266 builder.Scale(xscale, yscale);
267
268 paint.setImageFilter(
269 DlImageFilter::MakeCompose(color_filter, runtime_filter));
270 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
271 builder.DrawImage(image, DlPoint(100.0, 100.0),
272 DlImageSampling::kNearestNeighbor, &paint);
273
274 if (compare) {
275 paint.setImageFilter(
276 DlImageFilter::MakeCompose(runtime_filter, color_filter));
277 builder.DrawImage(image, DlPoint(800.0, 100.0),
278 DlImageSampling::kNearestNeighbor, &paint);
279
280 paint.setImageFilter(runtime_filter);
281 builder.DrawImage(image, DlPoint(100.0, 800.0),
282 DlImageSampling::kNearestNeighbor, &paint);
283 }
284
285 DlPaint green;
286 green.setColor(DlColor::kGreen());
287 builder.DrawLine({100, 100}, {200, 100}, green);
288 builder.DrawLine({100, 100}, {100, 200}, green);
289 if (compare) {
290 builder.DrawLine({800, 100}, {900, 100}, green);
291 builder.DrawLine({800, 100}, {800, 200}, green);
292 builder.DrawLine({100, 800}, {200, 800}, green);
293 builder.DrawLine({100, 800}, {100, 900}, green);
294 }
295
296 return builder.Build();
297 };
298
299 ASSERT_TRUE(OpenPlaygroundHere(callback));
300 }
301
302 TEST_P(AiksTest, ComposeBackdropRuntimeOuterBlurInner) {
303 auto runtime_stages_result =
304 OpenAssetAsRuntimeStage("runtime_stage_filter_circle.frag.iplr");
305 ABSL_ASSERT_OK(runtime_stages_result);
306 std::shared_ptr<RuntimeStage> runtime_stage =
307 runtime_stages_result
308 .value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
309 ASSERT_TRUE(runtime_stage);
310 ASSERT_TRUE(runtime_stage->IsDirty());
311 Scalar sigma = 20.0;
312
313 auto callback = [&]() -> sk_sp<DisplayList> {
314 if (AiksTest::ImGuiBegin("Controls", nullptr,
315 ImGuiWindowFlags_AlwaysAutoResize)) {
316 ImGui::SliderFloat("sigma", &sigma, 0, 20);
317 ImGui::End();
318 }
319 DisplayListBuilder builder;
320 DlPaint background;
321 background.setColor(DlColor(1.0, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
322 builder.DrawPaint(background);
323
324 auto blur_filter =
325 DlImageFilter::MakeBlur(sigma, sigma, DlTileMode::kClamp);
326
327 std::vector<std::shared_ptr<DlColorSource>> sampler_inputs = {
328 nullptr,
329 };
330
331 struct FragUniforms {
332 Vector2 size;
333 Vector2 origin;
334 } frag_uniforms = {.size = Vector2(1, 1), .origin = Vector2(30.f, 30.f)};
335 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
336 uniform_data->resize(sizeof(FragUniforms));
337 memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms));
338
339 auto runtime_filter = DlImageFilter::MakeRuntimeEffect(
340 DlRuntimeEffectImpeller::Make(runtime_stage), sampler_inputs,
341 uniform_data);
342
343 auto backdrop_filter = DlImageFilter::MakeCompose(/*outer=*/runtime_filter,
344 /*inner=*/blur_filter);
345
346 DlPaint paint;
347 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
348 builder.DrawImage(image, DlPoint(100.0, 100.0),
349 DlImageSampling::kNearestNeighbor, &paint);
350
351 DlPaint save_paint;
352 save_paint.setBlendMode(DlBlendMode::kSrc);
353 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get());
354 builder.Restore();
355
356 DlPaint green;
357 green.setColor(DlColor::kGreen());
358 builder.DrawLine({100, 100}, {200, 100}, green);
359 builder.DrawLine({100, 100}, {100, 200}, green);
360
361 return builder.Build();
362 };
363
364 ASSERT_TRUE(OpenPlaygroundHere(callback));
365 }
366
367 TEST_P(AiksTest, ComposeBackdropRuntimeOuterBlurInnerSmallSigma) {
368 auto runtime_stages_result =
369 OpenAssetAsRuntimeStage("runtime_stage_filter_circle.frag.iplr");
370 ABSL_ASSERT_OK(runtime_stages_result);
371 std::shared_ptr<RuntimeStage> runtime_stage =
372 runtime_stages_result
373 .value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
374 ASSERT_TRUE(runtime_stage);
375 ASSERT_TRUE(runtime_stage->IsDirty());
376 Scalar sigma = 5.0;
377
378 auto callback = [&]() -> sk_sp<DisplayList> {
379 if (AiksTest::ImGuiBegin("Controls", nullptr,
380 ImGuiWindowFlags_AlwaysAutoResize)) {
381 ImGui::SliderFloat("sigma", &sigma, 0, 20);
382 ImGui::End();
383 }
384 DisplayListBuilder builder;
385 DlPaint background;
386 background.setColor(DlColor(1.0, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
387 builder.DrawPaint(background);
388
389 auto blur_filter =
390 DlImageFilter::MakeBlur(sigma, sigma, DlTileMode::kClamp);
391
392 std::vector<std::shared_ptr<DlColorSource>> sampler_inputs = {
393 nullptr,
394 };
395 struct FragUniforms {
396 Vector2 size;
397 Vector2 origin;
398 } frag_uniforms = {.size = Vector2(1, 1), .origin = Vector2(30.f, 30.f)};
399 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
400 uniform_data->resize(sizeof(FragUniforms));
401 memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms));
402
403 auto runtime_filter = DlImageFilter::MakeRuntimeEffect(
404 DlRuntimeEffectImpeller::Make(runtime_stage), sampler_inputs,
405 uniform_data);
406
407 auto backdrop_filter = DlImageFilter::MakeCompose(/*outer=*/runtime_filter,
408 /*inner=*/blur_filter);
409
410 DlPaint paint;
411 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
412 builder.DrawImage(image, DlPoint(100.0, 100.0),
413 DlImageSampling::kNearestNeighbor, &paint);
414
415 DlPaint save_paint;
416 save_paint.setBlendMode(DlBlendMode::kSrc);
417 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get());
418 builder.Restore();
419
420 DlPaint green;
421 green.setColor(DlColor::kGreen());
422 builder.DrawLine({100, 100}, {200, 100}, green);
423 builder.DrawLine({100, 100}, {100, 200}, green);
424
425 return builder.Build();
426 };
427
428 ASSERT_TRUE(OpenPlaygroundHere(callback));
429 }
430
431 TEST_P(AiksTest, ClippedComposeBackdropRuntimeOuterBlurInnerSmallSigma) {
432 auto runtime_stages_result =
433 OpenAssetAsRuntimeStage("runtime_stage_filter_circle.frag.iplr");
434 ABSL_ASSERT_OK(runtime_stages_result);
435 std::shared_ptr<RuntimeStage> runtime_stage =
436 runtime_stages_result
437 .value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
438 ASSERT_TRUE(runtime_stage);
439 ASSERT_TRUE(runtime_stage->IsDirty());
440 Scalar sigma = 5.0;
441 Vector2 clip_origin = Vector2(20.f, 20.f);
442 Vector2 clip_size = Vector2(300, 300);
443 Vector2 circle_origin = Vector2(30.f, 30.f);
444
445 auto callback = [&]() -> sk_sp<DisplayList> {
446 if (AiksTest::ImGuiBegin("Controls", nullptr,
447 ImGuiWindowFlags_AlwaysAutoResize)) {
448 ImGui::SliderFloat("sigma", &sigma, 0, 20);
449 ImGui::SliderFloat("clip_x", &clip_origin.x, 0, 2048.f);
450 ImGui::SliderFloat("clip_y", &clip_origin.y, 0, 1536.f);
451 ImGui::SliderFloat("clip_width", &clip_size.x, 0, 2048.f);
452 ImGui::SliderFloat("clip_height", &clip_size.y, 0, 1536.f);
453 ImGui::SliderFloat("circle_x", &circle_origin.x, 0.f, 2048.f);
454 ImGui::SliderFloat("circle_y", &circle_origin.y, 0.f, 1536.f);
455 ImGui::End();
456 }
457 DisplayListBuilder builder;
458 DlPaint background;
459 background.setColor(DlColor(1.0, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
460 builder.DrawPaint(background);
461
462 auto blur_filter =
463 DlImageFilter::MakeBlur(sigma, sigma, DlTileMode::kClamp);
464
465 std::vector<std::shared_ptr<DlColorSource>> sampler_inputs = {
466 nullptr,
467 };
468 struct FragUniforms {
469 Vector2 size;
470 Vector2 origin;
471 } frag_uniforms = {.size = Vector2(1, 1), .origin = circle_origin};
472 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
473 uniform_data->resize(sizeof(FragUniforms));
474 memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms));
475
476 auto runtime_filter = DlImageFilter::MakeRuntimeEffect(
477 DlRuntimeEffectImpeller::Make(runtime_stage), sampler_inputs,
478 uniform_data);
479
480 auto backdrop_filter = DlImageFilter::MakeCompose(/*outer=*/runtime_filter,
481 /*inner=*/blur_filter);
482
483 builder.ClipRect(DlRect::MakeXYWH(clip_origin.x, clip_origin.y, clip_size.x,
484 clip_size.y));
485
486 DlPaint paint;
487 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
488 builder.DrawImage(image, DlPoint(100.0, 100.0),
489 DlImageSampling::kNearestNeighbor, &paint);
490
491 DlPaint save_paint;
492 save_paint.setBlendMode(DlBlendMode::kSrc);
493 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get());
494 builder.Restore();
495
496 DlPaint green;
497 green.setColor(DlColor::kGreen());
498 builder.DrawLine({100, 100}, {200, 100}, green);
499 builder.DrawLine({100, 100}, {100, 200}, green);
500
501 return builder.Build();
502 };
503
504 ASSERT_TRUE(OpenPlaygroundHere(callback));
505 }
506
507 TEST_P(AiksTest, ClippedBackdropFilterWithShader) {
508 struct FragUniforms {
509 Vector2 uSize;
510 } frag_uniforms = {.uSize = Vector2(400, 400)};
511 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
512 uniform_data->resize(sizeof(FragUniforms));
513 memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms));
514
515 auto runtime_stages_result =
516 OpenAssetAsRuntimeStage("runtime_stage_border.frag.iplr");
517 ABSL_ASSERT_OK(runtime_stages_result);
518 std::shared_ptr<RuntimeStage> runtime_stage =
519 runtime_stages_result
520 .value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
521 ASSERT_TRUE(runtime_stage);
522 ASSERT_TRUE(runtime_stage->IsDirty());
523
524 std::vector<std::shared_ptr<DlColorSource>> sampler_inputs = {
525 nullptr,
526 };
527
528 auto runtime_filter = DlImageFilter::MakeRuntimeEffect(
529 DlRuntimeEffectImpeller::Make(runtime_stage), sampler_inputs,
530 uniform_data);
531
532 DisplayListBuilder builder;
533
534 // Draw a background so the backdrop filter has something to affect
535 DlPaint background_paint;
536 background_paint.setColor(DlColor::kWhite());
537 builder.DrawPaint(background_paint);
538
539 // Draw some pattern to verify the filter effect
540 DlPaint pattern_paint;
541 pattern_paint.setColor(DlColor::kRed());
542 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), pattern_paint);
543 pattern_paint.setColor(DlColor::kBlue());
544 builder.DrawRect(DlRect::MakeXYWH(200, 200, 200, 200), pattern_paint);
545
546 builder.Save();
547
548 // Replicate the clip rect (inset by 66)
549 // Assuming a 400x400 screen, inset 66 gives roughly 66, 66, 268, 268
550 builder.ClipRect(DlRect::MakeXYWH(66, 66, 268, 268));
551
552 DlPaint save_paint;
553 // The Flutter code uses a backdrop filter layer.
554 // In DisplayList, this corresponds to SaveLayer with a backdrop filter.
555 builder.SaveLayer(std::nullopt, &save_paint, runtime_filter.get());
556
557 // The child was empty in the Flutter example, so we don't draw anything
558 // inside the SaveLayer
559
560 builder.Restore(); // Restore SaveLayer
561 builder.Restore(); // Restore Save (Clip)
562
563 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
564 }
565
566 TEST_P(AiksTest, RuntimeEffectImageFilterRotated) {
567 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
568 auto size = image->GetBounds().GetSize();
569
570 struct FragUniforms {
571 Size size;
572 } frag_uniforms = {.size = Size(size.width, size.height)};
573 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
574 uniform_data->resize(sizeof(FragUniforms));
575 memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms));
576
577 auto runtime_stages_result = OpenAssetAsRuntimeStage("gradient.frag.iplr");
578 ABSL_ASSERT_OK(runtime_stages_result);
579 std::shared_ptr<RuntimeStage> runtime_stage =
580 runtime_stages_result
581 .value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
582 ASSERT_TRUE(runtime_stage);
583 ASSERT_TRUE(runtime_stage->IsDirty());
584
585 std::vector<std::shared_ptr<DlColorSource>> sampler_inputs = {
586 nullptr,
587 };
588
589 auto runtime_filter = DlImageFilter::MakeRuntimeEffect(
590 DlRuntimeEffectImpeller::Make(runtime_stage), sampler_inputs,
591 uniform_data);
592
593 Scalar rotation = 45;
594
595 auto callback = [&]() -> sk_sp<DisplayList> {
596 if (AiksTest::ImGuiBegin("Controls", nullptr,
597 ImGuiWindowFlags_AlwaysAutoResize)) {
598 ImGui::SliderFloat("rotation", &rotation, 0, 360);
599 ImGui::End();
600 }
601 DisplayListBuilder builder;
602 builder.Translate(size.width * 0.5, size.height * 0.5);
603 builder.Rotate(rotation);
604 builder.Translate(-size.width * 0.5, -size.height * 0.5);
605
606 DlPaint paint;
607 paint.setImageFilter(runtime_filter);
608 builder.DrawImage(image, DlPoint(0.0, 0.0),
609 DlImageSampling::kNearestNeighbor, &paint);
610
611 return builder.Build();
612 };
613
614 ASSERT_TRUE(OpenPlaygroundHere(callback));
615 }
616
617 } // namespace testing
618 } // namespace impeller
aiks_unittests.h
flutter::DlRuntimeEffectImpeller::Make
static sk_sp< DlRuntimeEffect > Make(std::shared_ptr< impeller::RuntimeStage > runtime_stage)
Definition: dl_runtime_effect_impeller.cc:14
impeller::AiksPlayground
Definition: aiks_playground.h:16
impeller::AiksPlayground::ImGuiBegin
static bool ImGuiBegin(const char *name, bool *p_open, ImGuiWindowFlags flags)
Definition: aiks_playground.cc:30
impeller::DlImageImpeller::Make
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
Definition: dl_image_impeller.cc:23
x
int32_t x
Definition: dl_golden_unittests.cc:458
dl_image_impeller.h
dl_runtime_effect_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::Vector2
Point Vector2
Definition: point.h:429
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::PlaygroundBackendToRuntimeStageBackend
constexpr RuntimeStageBackend PlaygroundBackendToRuntimeStageBackend(PlaygroundBackend backend)
Definition: playground.h:33
impeller::DlPoint
flutter::DlPoint DlPoint
Definition: dl_dispatcher.h:24
impeller::Size
TSize< Scalar > Size
Definition: size.h:159
point.h
impeller::ScopedValidationDisable
Definition: validation.h:56
impeller::TPoint< Scalar >
impeller::TPoint::y
Type y
Definition: point.h:32
impeller::TPoint::x
Type x
Definition: point.h:31
impeller::TSize< Scalar >
impeller::TSize< Scalar >::MakeWH
static constexpr TSize MakeWH(Type width, Type height)
Definition: size.h:43
vector.h