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