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"
17 #include "imgui.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
static sk_sp< DlRuntimeEffect > Make(std::shared_ptr< impeller::RuntimeStage > runtime_stage)
static bool ImGuiBegin(const char *name, bool *p_open, ImGuiWindowFlags flags)
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
int32_t x
AiksPlayground AiksTest
TEST_P(AiksTest, DrawAtlasNoColor)
Point Vector2
Definition: point.h:429
float Scalar
Definition: scalar.h:19
constexpr RuntimeStageBackend PlaygroundBackendToRuntimeStageBackend(PlaygroundBackend backend)
Definition: playground.h:33
flutter::DlPoint DlPoint
Definition: dl_dispatcher.h:24
TSize< Scalar > Size
Definition: size.h:159
static constexpr TSize MakeWH(Type width, Type height)
Definition: size.h:43