Flutter Impeller
aiks_dl_unittests.cc
Go to the documentation of this file.
1 
2 // Copyright 2013 The Flutter Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 
6 #include "display_list/dl_sampling_options.h"
7 #include "display_list/dl_tile_mode.h"
8 #include "display_list/effects/dl_color_filter.h"
9 #include "display_list/effects/dl_color_source.h"
10 #include "display_list/effects/dl_image_filter.h"
11 #include "display_list/geometry/dl_geometry_types.h"
12 #include "display_list/image/dl_image.h"
14 
15 #include "flutter/display_list/dl_blend_mode.h"
16 #include "flutter/display_list/dl_builder.h"
17 #include "flutter/display_list/dl_color.h"
18 #include "flutter/display_list/dl_paint.h"
19 #include "flutter/testing/testing.h"
20 #include "imgui.h"
24 #include "include/core/SkMatrix.h"
25 #include "include/core/SkRSXform.h"
26 #include "include/core/SkRefCnt.h"
27 
28 namespace impeller {
29 namespace testing {
30 
31 using namespace flutter;
32 
33 namespace {
34 SkRect GetCullRect(ISize window_size) {
35  return SkRect::MakeSize(SkSize::Make(window_size.width, window_size.height));
36 }
37 } // namespace
38 
39 TEST_P(AiksTest, CollapsedDrawPaintInSubpass) {
40  DisplayListBuilder builder;
41 
42  DlPaint paint;
43  paint.setColor(DlColor::kYellow());
44  paint.setBlendMode(DlBlendMode::kSrc);
45  builder.DrawPaint(paint);
46 
47  DlPaint save_paint;
48  save_paint.setBlendMode(DlBlendMode::kMultiply);
49  builder.SaveLayer(nullptr, &save_paint);
50 
51  DlPaint draw_paint;
52  draw_paint.setColor(DlColor::kCornflowerBlue().modulateOpacity(0.75f));
53  builder.DrawPaint(draw_paint);
54 
55  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
56 }
57 
58 TEST_P(AiksTest, CollapsedDrawPaintInSubpassBackdropFilter) {
59  // Bug: https://github.com/flutter/flutter/issues/131576
60  DisplayListBuilder builder;
61 
62  DlPaint paint;
63  paint.setColor(DlColor::kYellow());
64  paint.setBlendMode(DlBlendMode::kSrc);
65  builder.DrawPaint(paint);
66 
67  auto filter = DlBlurImageFilter::Make(20.0, 20.0, DlTileMode::kDecal);
68  builder.SaveLayer(nullptr, nullptr, filter.get());
69 
70  DlPaint draw_paint;
71  draw_paint.setColor(DlColor::kCornflowerBlue());
72  builder.DrawPaint(draw_paint);
73 
74  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
75 }
76 
77 TEST_P(AiksTest, ColorMatrixFilterSubpassCollapseOptimization) {
78  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
79 
80  const float matrix[20] = {
81  -1.0, 0, 0, 1.0, 0, //
82  0, -1.0, 0, 1.0, 0, //
83  0, 0, -1.0, 1.0, 0, //
84  1.0, 1.0, 1.0, 1.0, 0 //
85  };
86  auto filter = DlMatrixColorFilter::Make(matrix);
87 
88  DlPaint paint;
89  paint.setColorFilter(filter);
90  builder.SaveLayer(nullptr, &paint);
91 
92  builder.Translate(500, 300);
93  builder.Rotate(120); // 120 deg
94 
95  DlPaint draw_paint;
96  draw_paint.setColor(DlColor::kBlue());
97  builder.DrawRect(SkRect::MakeXYWH(100, 100, 200, 200), draw_paint);
98 
99  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
100 }
101 
102 TEST_P(AiksTest, LinearToSrgbFilterSubpassCollapseOptimization) {
103  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
104 
105  DlPaint paint;
106  paint.setColorFilter(DlLinearToSrgbGammaColorFilter::kInstance);
107  builder.SaveLayer(nullptr, &paint);
108 
109  builder.Translate(500, 300);
110  builder.Rotate(120); // 120 deg.
111 
112  DlPaint draw_paint;
113  draw_paint.setColor(DlColor::kBlue());
114  builder.DrawRect(SkRect::MakeXYWH(100, 100, 200, 200), draw_paint);
115 
116  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
117 }
118 
119 TEST_P(AiksTest, SrgbToLinearFilterSubpassCollapseOptimization) {
120  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
121 
122  DlPaint paint;
123  paint.setColorFilter(DlLinearToSrgbGammaColorFilter::kInstance);
124  builder.SaveLayer(nullptr, &paint);
125 
126  builder.Translate(500, 300);
127  builder.Rotate(120); // 120 deg
128 
129  DlPaint draw_paint;
130  draw_paint.setColor(DlColor::kBlue());
131  builder.DrawRect(SkRect::MakeXYWH(100, 100, 200, 200), draw_paint);
132 
133  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
134 }
135 
136 TEST_P(AiksTest, TranslucentSaveLayerDrawsCorrectly) {
137  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
138 
139  DlPaint paint;
140  paint.setColor(DlColor::kBlue());
141  builder.DrawRect(SkRect::MakeXYWH(100, 100, 300, 300), paint);
142 
143  DlPaint save_paint;
144  save_paint.setColor(DlColor::kBlack().withAlpha(128));
145  builder.SaveLayer(nullptr, &save_paint);
146  builder.DrawRect(SkRect::MakeXYWH(100, 500, 300, 300), paint);
147  builder.Restore();
148 
149  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
150 }
151 
152 TEST_P(AiksTest, TranslucentSaveLayerWithBlendColorFilterDrawsCorrectly) {
153  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
154 
155  DlPaint paint;
156  paint.setColor(DlColor::kBlue());
157  builder.DrawRect(SkRect::MakeXYWH(100, 100, 300, 300), paint);
158 
159  DlPaint save_paint;
160  paint.setColor(DlColor::kBlack().withAlpha(128));
161  paint.setColorFilter(
162  DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kDstOver));
163  builder.SaveLayer(nullptr, &paint);
164 
165  DlPaint draw_paint;
166  draw_paint.setColor(DlColor::kBlue());
167  builder.DrawRect(SkRect::MakeXYWH(100, 500, 300, 300), draw_paint);
168  builder.Restore();
169 
170  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
171 }
172 
173 TEST_P(AiksTest, TranslucentSaveLayerWithBlendImageFilterDrawsCorrectly) {
174  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
175 
176  DlPaint paint;
177  paint.setColor(DlColor::kBlue());
178  builder.DrawRect(SkRect::MakeXYWH(100, 100, 300, 300), paint);
179 
180  DlPaint save_paint;
181  save_paint.setColor(DlColor::kBlack().withAlpha(128));
182  save_paint.setImageFilter(DlColorFilterImageFilter::Make(
183  DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kDstOver)));
184 
185  builder.SaveLayer(nullptr, &save_paint);
186 
187  DlPaint draw_paint;
188  draw_paint.setColor(DlColor::kBlue());
189  builder.DrawRect(SkRect::MakeXYWH(100, 500, 300, 300), draw_paint);
190  builder.Restore();
191 
192  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
193 }
194 
195 TEST_P(AiksTest, TranslucentSaveLayerWithColorAndImageFilterDrawsCorrectly) {
196  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
197 
198  DlPaint paint;
199  paint.setColor(DlColor::kBlue());
200  builder.DrawRect(SkRect::MakeXYWH(100, 100, 300, 300), paint);
201 
202  DlPaint save_paint;
203  save_paint.setColor(DlColor::kBlack().withAlpha(128));
204  save_paint.setColorFilter(
205  DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kDstOver));
206  builder.SaveLayer(nullptr, &save_paint);
207 
208  DlPaint draw_paint;
209  draw_paint.setColor(DlColor::kBlue());
210  builder.DrawRect(SkRect::MakeXYWH(100, 500, 300, 300), draw_paint);
211  builder.Restore();
212 
213  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
214 }
215 
216 TEST_P(AiksTest, ImageFilteredUnboundedSaveLayerWithUnboundedContents) {
217  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
218  builder.Scale(GetContentScale().x, GetContentScale().y);
219 
220  DlPaint save_paint;
221  save_paint.setImageFilter(
222  DlBlurImageFilter::Make(10.0, 10.0, DlTileMode::kDecal));
223  builder.SaveLayer(nullptr, &save_paint);
224 
225  {
226  // DrawPaint to verify correct behavior when the contents are unbounded.
227  DlPaint draw_paint;
228  draw_paint.setColor(DlColor::kYellow());
229  builder.DrawPaint(draw_paint);
230 
231  // Contrasting rectangle to see interior blurring
232  DlPaint draw_rect;
233  draw_rect.setColor(DlColor::kBlue());
234  builder.DrawRect(SkRect::MakeLTRB(125, 125, 175, 175), draw_rect);
235  }
236  builder.Restore();
237 
238  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
239 }
240 
241 TEST_P(AiksTest, TranslucentSaveLayerImageDrawsCorrectly) {
242  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
243 
244  auto image = DlImageImpeller::Make(CreateTextureForFixture("airplane.jpg"));
245  builder.DrawImage(image, {100, 100}, DlImageSampling::kMipmapLinear);
246 
247  DlPaint paint;
248  paint.setColor(DlColor::kBlack().withAlpha(128));
249  builder.SaveLayer(nullptr, &paint);
250  builder.DrawImage(image, {100, 500}, DlImageSampling::kMipmapLinear);
251  builder.Restore();
252 
253  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
254 }
255 
256 TEST_P(AiksTest, TranslucentSaveLayerWithColorMatrixColorFilterDrawsCorrectly) {
257  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
258 
259  auto image = DlImageImpeller::Make(CreateTextureForFixture("airplane.jpg"));
260  builder.DrawImage(image, {100, 100}, {});
261 
262  const float matrix[20] = {
263  1, 0, 0, 0, 0, //
264  0, 1, 0, 0, 0, //
265  0, 0, 1, 0, 0, //
266  0, 0, 0, 2, 0 //
267  };
268  DlPaint paint;
269  paint.setColor(DlColor::kBlack().withAlpha(128));
270  paint.setColorFilter(DlMatrixColorFilter::Make(matrix));
271  builder.SaveLayer(nullptr, &paint);
272  builder.DrawImage(image, {100, 500}, {});
273  builder.Restore();
274 
275  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
276 }
277 
278 TEST_P(AiksTest, TranslucentSaveLayerWithColorMatrixImageFilterDrawsCorrectly) {
279  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
280 
281  auto image = DlImageImpeller::Make(CreateTextureForFixture("airplane.jpg"));
282  builder.DrawImage(image, {100, 100}, {});
283 
284  const float matrix[20] = {
285  1, 0, 0, 0, 0, //
286  0, 1, 0, 0, 0, //
287  0, 0, 1, 0, 0, //
288  0, 0, 0, 2, 0 //
289  };
290  DlPaint paint;
291  paint.setColor(DlColor::kBlack().withAlpha(128));
292  paint.setColorFilter(DlMatrixColorFilter::Make(matrix));
293  builder.SaveLayer(nullptr, &paint);
294  builder.DrawImage(image, {100, 500}, {});
295  builder.Restore();
296 
297  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
298 }
299 
301  TranslucentSaveLayerWithColorFilterAndImageFilterDrawsCorrectly) {
302  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
303 
304  auto image = DlImageImpeller::Make(CreateTextureForFixture("airplane.jpg"));
305  builder.DrawImage(image, {100, 100}, {});
306 
307  const float matrix[20] = {
308  1, 0, 0, 0, 0, //
309  0, 1, 0, 0, 0, //
310  0, 0.2, 1, 0, 0, //
311  0, 0, 0, 0.5, 0 //
312  };
313  DlPaint paint;
314  paint.setColor(DlColor::kBlack().withAlpha(128));
315  paint.setImageFilter(
316  DlColorFilterImageFilter::Make(DlMatrixColorFilter::Make(matrix)));
317  paint.setColorFilter(
318  DlBlendColorFilter::Make(DlColor::kGreen(), DlBlendMode::kModulate));
319  builder.SaveLayer(nullptr, &paint);
320  builder.DrawImage(image, {100, 500}, {});
321  builder.Restore();
322 
323  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
324 }
325 
326 TEST_P(AiksTest, TranslucentSaveLayerWithAdvancedBlendModeDrawsCorrectly) {
327  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
328 
329  DlPaint paint;
330  paint.setColor(DlColor::kRed());
331  builder.DrawRect(SkRect::MakeXYWH(0, 0, 400, 400), paint);
332 
333  DlPaint save_paint;
334  save_paint.setAlpha(128);
335  save_paint.setBlendMode(DlBlendMode::kLighten);
336  builder.SaveLayer(nullptr, &save_paint);
337 
338  DlPaint draw_paint;
339  draw_paint.setColor(DlColor::kGreen());
340  builder.DrawCircle({200, 200}, 100, draw_paint);
341  builder.Restore();
342 
343  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
344 }
345 
346 /// This is a regression check for https://github.com/flutter/engine/pull/41129
347 /// The entire screen is green if successful. If failing, no frames will render,
348 /// or the entire screen will be transparent black.
349 TEST_P(AiksTest, CanRenderTinyOverlappingSubpasses) {
350  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
351 
352  DlPaint paint;
353  paint.setColor(DlColor::kRed());
354  builder.DrawPaint(paint);
355 
356  // Draw two overlapping subpixel circles.
357  builder.SaveLayer({});
358 
359  DlPaint yellow_paint;
360  yellow_paint.setColor(DlColor::kYellow());
361  builder.DrawCircle({100, 100}, 0.1, yellow_paint);
362  builder.Restore();
363  builder.SaveLayer({});
364  builder.DrawCircle({100, 100}, 0.1, yellow_paint);
365  builder.Restore();
366 
367  DlPaint draw_paint;
368  draw_paint.setColor(DlColor::kGreen());
369  builder.DrawPaint(draw_paint);
370 
371  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
372 }
373 
374 TEST_P(AiksTest, CanRenderDestructiveSaveLayer) {
375  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
376 
377  DlPaint paint;
378  paint.setColor(DlColor::kRed());
379  builder.DrawPaint(paint);
380  // Draw an empty savelayer with a destructive blend mode, which will replace
381  // the entire red screen with fully transparent black, except for the green
382  // circle drawn within the layer.
383 
384  DlPaint save_paint;
385  save_paint.setBlendMode(DlBlendMode::kSrc);
386  builder.SaveLayer(nullptr, &save_paint);
387 
388  DlPaint draw_paint;
389  draw_paint.setColor(DlColor::kGreen());
390  builder.DrawCircle({300, 300}, 100, draw_paint);
391  builder.Restore();
392 
393  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
394 }
395 
396 TEST_P(AiksTest, CanDrawPoints) {
397  std::vector<SkPoint> points = {
398  {0, 0}, //
399  {100, 100}, //
400  {100, 0}, //
401  {0, 100}, //
402  {0, 0}, //
403  {48, 48}, //
404  {52, 52}, //
405  };
406  DlPaint paint_round;
407  paint_round.setColor(DlColor::kYellow().withAlpha(128));
408  paint_round.setStrokeCap(DlStrokeCap::kRound);
409  paint_round.setStrokeWidth(20);
410 
411  DlPaint paint_square;
412  paint_square.setColor(DlColor::kYellow().withAlpha(128));
413  paint_square.setStrokeCap(DlStrokeCap::kSquare);
414  paint_square.setStrokeWidth(20);
415 
416  DlPaint background;
417  background.setColor(DlColor::kBlack());
418 
419  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
420  builder.DrawPaint(background);
421  builder.Translate(200, 200);
422 
423  builder.DrawPoints(DlCanvas::PointMode::kPoints, points.size(), points.data(),
424  paint_round);
425  builder.Translate(150, 0);
426  builder.DrawPoints(DlCanvas::PointMode::kPoints, points.size(), points.data(),
427  paint_square);
428 
429  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
430 }
431 
432 TEST_P(AiksTest, CanDrawPointsWithTextureMap) {
433  auto texture = DlImageImpeller::Make(
434  CreateTextureForFixture("table_mountain_nx.png",
435  /*enable_mipmapping=*/true));
436 
437  std::vector<SkPoint> points = {
438  {0, 0}, //
439  {100, 100}, //
440  {100, 0}, //
441  {0, 100}, //
442  {0, 0}, //
443  {48, 48}, //
444  {52, 52}, //
445  };
446 
447  auto image_src = std::make_shared<DlImageColorSource>(
448  texture, DlTileMode::kClamp, DlTileMode::kClamp);
449 
450  DlPaint paint_round;
451  paint_round.setStrokeCap(DlStrokeCap::kRound);
452  paint_round.setColorSource(image_src);
453  paint_round.setStrokeWidth(200);
454 
455  DlPaint paint_square;
456  paint_square.setStrokeCap(DlStrokeCap::kSquare);
457  paint_square.setColorSource(image_src);
458  paint_square.setStrokeWidth(200);
459 
460  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
461  builder.Translate(200, 200);
462 
463  builder.DrawPoints(DlCanvas::PointMode::kPoints, points.size(), points.data(),
464  paint_round);
465  builder.Translate(150, 0);
466  builder.DrawPoints(DlCanvas::PointMode::kPoints, points.size(), points.data(),
467  paint_square);
468 
469  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
470 }
471 
472 TEST_P(AiksTest, MipmapGenerationWorksCorrectly) {
473  TextureDescriptor texture_descriptor;
474  texture_descriptor.size = ISize{1024, 1024};
475  texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
476  texture_descriptor.storage_mode = StorageMode::kHostVisible;
477  texture_descriptor.mip_count = texture_descriptor.size.MipCount();
478 
479  std::vector<uint8_t> bytes(4194304);
480  bool alternate = false;
481  for (auto i = 0u; i < 4194304; i += 4) {
482  if (alternate) {
483  bytes[i] = 255;
484  bytes[i + 1] = 0;
485  bytes[i + 2] = 0;
486  bytes[i + 3] = 255;
487  } else {
488  bytes[i] = 0;
489  bytes[i + 1] = 255;
490  bytes[i + 2] = 0;
491  bytes[i + 3] = 255;
492  }
493  alternate = !alternate;
494  }
495 
496  ASSERT_EQ(texture_descriptor.GetByteSizeOfBaseMipLevel(), bytes.size());
497  auto mapping = std::make_shared<fml::NonOwnedMapping>(
498  bytes.data(), // data
499  texture_descriptor.GetByteSizeOfBaseMipLevel() // size
500  );
501  auto texture =
502  GetContext()->GetResourceAllocator()->CreateTexture(texture_descriptor);
503 
504  auto device_buffer =
505  GetContext()->GetResourceAllocator()->CreateBufferWithCopy(*mapping);
506  auto command_buffer = GetContext()->CreateCommandBuffer();
507  auto blit_pass = command_buffer->CreateBlitPass();
508 
509  blit_pass->AddCopy(DeviceBuffer::AsBufferView(std::move(device_buffer)),
510  texture);
511  blit_pass->GenerateMipmap(texture);
512  EXPECT_TRUE(blit_pass->EncodeCommands(GetContext()->GetResourceAllocator()));
513  EXPECT_TRUE(GetContext()->GetCommandQueue()->Submit({command_buffer}).ok());
514 
515  auto image = DlImageImpeller::Make(texture);
516 
517  DisplayListBuilder builder;
518  builder.DrawImageRect(
519  image,
520  SkRect::MakeSize(
521  SkSize::Make(texture->GetSize().width, texture->GetSize().height)),
522  SkRect::MakeLTRB(0, 0, 100, 100), DlImageSampling::kMipmapLinear);
523 
524  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
525 }
526 
527 // https://github.com/flutter/flutter/issues/146648
528 TEST_P(AiksTest, StrokedPathWithMoveToThenCloseDrawnCorrectly) {
529  SkPath path;
530  path.moveTo(0, 400)
531  .lineTo(0, 0)
532  .lineTo(400, 0)
533  // MoveTo implicitly adds a contour, ensure that close doesn't
534  // add another nearly-empty contour.
535  .moveTo(0, 400)
536  .close();
537 
538  DisplayListBuilder builder;
539  builder.Translate(50, 50);
540 
541  DlPaint paint;
542  paint.setColor(DlColor::kBlue());
543  paint.setStrokeCap(DlStrokeCap::kRound);
544  paint.setStrokeWidth(10);
545  paint.setDrawStyle(DlDrawStyle::kStroke);
546  builder.DrawPath(path, paint);
547 
548  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
549 }
550 
551 TEST_P(AiksTest, SetContentsWithRegion) {
552  auto bridge = CreateTextureForFixture("bay_bridge.jpg");
553 
554  // Replace part of the texture with a red rectangle.
555  std::vector<uint8_t> bytes(100 * 100 * 4);
556  for (auto i = 0u; i < bytes.size(); i += 4) {
557  bytes[i] = 255;
558  bytes[i + 1] = 0;
559  bytes[i + 2] = 0;
560  bytes[i + 3] = 255;
561  }
562  auto mapping =
563  std::make_shared<fml::NonOwnedMapping>(bytes.data(), bytes.size());
564  auto device_buffer =
565  GetContext()->GetResourceAllocator()->CreateBufferWithCopy(*mapping);
566  auto cmd_buffer = GetContext()->CreateCommandBuffer();
567  auto blit_pass = cmd_buffer->CreateBlitPass();
568  blit_pass->AddCopy(DeviceBuffer::AsBufferView(device_buffer), bridge,
569  IRect::MakeLTRB(50, 50, 150, 150));
570 
571  auto did_submit =
572  blit_pass->EncodeCommands(GetContext()->GetResourceAllocator()) &&
573  GetContext()->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok();
574  ASSERT_TRUE(did_submit);
575 
576  auto image = DlImageImpeller::Make(bridge);
577 
578  DisplayListBuilder builder;
579  builder.DrawImage(image, {0, 0}, {});
580 
581  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
582 }
583 
584 // Regression test for https://github.com/flutter/flutter/issues/134678.
585 TEST_P(AiksTest, ReleasesTextureOnTeardown) {
586  auto context = MakeContext();
587  std::weak_ptr<Texture> weak_texture;
588 
589  {
590  auto texture = CreateTextureForFixture("table_mountain_nx.png");
591  weak_texture = texture;
592 
593  DisplayListBuilder builder;
594  builder.Scale(GetContentScale().x, GetContentScale().y);
595  builder.Translate(100.0f, 100.0f);
596 
597  DlPaint paint;
598  paint.setColorSource(std::make_shared<DlImageColorSource>(
599  DlImageImpeller::Make(texture), DlTileMode::kClamp, DlTileMode::kClamp,
600  DlImageSampling::kLinear, nullptr));
601 
602  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
603 
604  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
605  }
606 
607  // See https://github.com/flutter/flutter/issues/134751.
608  //
609  // If the fence waiter was working this may not be released by the end of the
610  // scope above. Adding a manual shutdown so that future changes to the fence
611  // waiter will not flake this test.
612  context->Shutdown();
613 
614  // The texture should be released by now.
615  ASSERT_TRUE(weak_texture.expired()) << "When the texture is no longer in use "
616  "by the backend, it should be "
617  "released.";
618 }
619 
620 TEST_P(AiksTest, MatrixImageFilterMagnify) {
621  Scalar scale = 2.0;
622  auto callback = [&]() -> sk_sp<DisplayList> {
623  if (AiksTest::ImGuiBegin("Controls", nullptr,
624  ImGuiWindowFlags_AlwaysAutoResize)) {
625  ImGui::SliderFloat("Scale", &scale, 1, 2);
626  ImGui::End();
627  }
628  DisplayListBuilder builder;
629  builder.Scale(GetContentScale().x, GetContentScale().y);
630  auto image = DlImageImpeller::Make(CreateTextureForFixture("airplane.jpg"));
631 
632  builder.Translate(600, -200);
633 
634  SkMatrix matrix = SkMatrix::Scale(scale, scale);
635  DlPaint paint;
636  paint.setImageFilter(
637  DlMatrixImageFilter::Make(matrix, DlImageSampling::kLinear));
638  builder.SaveLayer(nullptr, &paint);
639 
640  DlPaint rect_paint;
641  rect_paint.setAlpha(0.5 * 255);
642  builder.DrawImage(image, {0, 0}, DlImageSampling::kLinear, &rect_paint);
643  builder.Restore();
644 
645  return builder.Build();
646  };
647 
648  ASSERT_TRUE(OpenPlaygroundHere(callback));
649 }
650 
651 TEST_P(AiksTest, ImageFilteredSaveLayerWithUnboundedContents) {
652  DisplayListBuilder builder;
653  builder.Scale(GetContentScale().x, GetContentScale().y);
654 
655  auto test = [&builder](const std::shared_ptr<const DlImageFilter>& filter) {
656  auto DrawLine = [&builder](const SkPoint& p0, const SkPoint& p1,
657  const DlPaint& p) {
658  DlPaint paint = p;
659  paint.setDrawStyle(DlDrawStyle::kStroke);
660  builder.DrawPath(SkPath::Line(p0, p1), paint);
661  };
662  // Registration marks for the edge of the SaveLayer
663  DlPaint paint;
664  paint.setColor(DlColor::kWhite());
665  DrawLine(SkPoint::Make(75, 100), SkPoint::Make(225, 100), paint);
666  DrawLine(SkPoint::Make(75, 200), SkPoint::Make(225, 200), paint);
667  DrawLine(SkPoint::Make(100, 75), SkPoint::Make(100, 225), paint);
668  DrawLine(SkPoint::Make(200, 75), SkPoint::Make(200, 225), paint);
669 
670  DlPaint save_paint;
671  save_paint.setImageFilter(filter);
672  SkRect bounds = SkRect::MakeLTRB(100, 100, 200, 200);
673  builder.SaveLayer(&bounds, &save_paint);
674 
675  {
676  // DrawPaint to verify correct behavior when the contents are unbounded.
677  DlPaint paint;
678  paint.setColor(DlColor::kYellow());
679  builder.DrawPaint(paint);
680 
681  // Contrasting rectangle to see interior blurring
682  paint.setColor(DlColor::kBlue());
683  builder.DrawRect(SkRect::MakeLTRB(125, 125, 175, 175), paint);
684  }
685  builder.Restore();
686  };
687 
688  test(std::make_shared<DlBlurImageFilter>(10.0, 10.0, DlTileMode::kDecal));
689 
690  builder.Translate(200.0, 0.0);
691 
692  test(std::make_shared<DlDilateImageFilter>(10.0, 10.0));
693 
694  builder.Translate(200.0, 0.0);
695 
696  test(std::make_shared<DlErodeImageFilter>(10.0, 10.0));
697 
698  builder.Translate(-400.0, 200.0);
699 
700  SkMatrix sk_matrix = SkMatrix::RotateDeg(10);
701 
702  auto rotate_filter = std::make_shared<DlMatrixImageFilter>(
703  sk_matrix, DlImageSampling::kLinear);
704  test(rotate_filter);
705 
706  builder.Translate(200.0, 0.0);
707 
708  const float m[20] = {
709  0, 1, 0, 0, 0, //
710  0, 0, 1, 0, 0, //
711  1, 0, 0, 0, 0, //
712  0, 0, 0, 1, 0 //
713  };
714  auto rgb_swap_filter = std::make_shared<DlColorFilterImageFilter>(
715  std::make_shared<DlMatrixColorFilter>(m));
716  test(rgb_swap_filter);
717 
718  builder.Translate(200.0, 0.0);
719 
720  test(DlComposeImageFilter::Make(rotate_filter, rgb_swap_filter));
721 
722  builder.Translate(-400.0, 200.0);
723 
724  test(std::make_shared<DlLocalMatrixImageFilter>(
725  SkMatrix::Translate(25.0, 25.0), rotate_filter));
726 
727  builder.Translate(200.0, 0.0);
728 
729  test(std::make_shared<DlLocalMatrixImageFilter>(
730  SkMatrix::Translate(25.0, 25.0), rgb_swap_filter));
731 
732  builder.Translate(200.0, 0.0);
733 
734  test(std::make_shared<DlLocalMatrixImageFilter>(
735  SkMatrix::Translate(25.0, 25.0),
736  DlComposeImageFilter::Make(rotate_filter, rgb_swap_filter)));
737 
738  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
739 }
740 
741 TEST_P(AiksTest, MatrixBackdropFilter) {
742  DisplayListBuilder builder;
743 
744  DlPaint paint;
745  paint.setColor(DlColor::kBlack());
746  builder.DrawPaint(paint);
747  builder.SaveLayer(nullptr, nullptr);
748  {
749  DlPaint paint;
750  paint.setColor(DlColor::kGreen().withAlpha(0.5 * 255));
751  paint.setBlendMode(DlBlendMode::kPlus);
752 
753  DlPaint rect_paint;
754  rect_paint.setColor(DlColor::kRed());
755  rect_paint.setStrokeWidth(4);
756  rect_paint.setDrawStyle(DlDrawStyle::kStroke);
757  builder.DrawRect(SkRect::MakeLTRB(0, 0, 300, 300), rect_paint);
758  builder.DrawCircle(SkPoint::Make(200, 200), 100, paint);
759  // Should render a second circle, centered on the bottom-right-most edge of
760  // the circle.
761  SkMatrix matrix = SkMatrix::Translate((100 + 100 * k1OverSqrt2),
762  (100 + 100 * k1OverSqrt2)) *
763  SkMatrix::Scale(0.5, 0.5) *
764  SkMatrix::Translate(-100, -100);
765  auto backdrop_filter =
766  DlMatrixImageFilter::Make(matrix, DlImageSampling::kLinear);
767  builder.SaveLayer(nullptr, nullptr, backdrop_filter.get());
768  builder.Restore();
769  }
770  builder.Restore();
771 
772  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
773 }
774 
775 TEST_P(AiksTest, MatrixSaveLayerFilter) {
776  DisplayListBuilder builder;
777 
778  DlPaint paint;
779  paint.setColor(DlColor::kBlack());
780  builder.DrawPaint(paint);
781  builder.SaveLayer(nullptr, nullptr);
782  {
783  paint.setColor(DlColor::kGreen().withAlpha(255 * 0.5));
784  paint.setBlendMode(DlBlendMode::kPlus);
785  builder.DrawCircle({200, 200}, 100, paint);
786  // Should render a second circle, centered on the bottom-right-most edge of
787  // the circle.
788 
789  SkMatrix matrix = SkMatrix::Translate((200 + 100 * k1OverSqrt2),
790  (200 + 100 * k1OverSqrt2)) *
791  SkMatrix::Scale(0.5, 0.5) *
792  SkMatrix::Translate(-200, -200);
793  DlPaint save_paint;
794  save_paint.setImageFilter(
795  DlMatrixImageFilter::Make(matrix, DlImageSampling::kLinear));
796 
797  builder.SaveLayer(nullptr, &save_paint);
798 
799  DlPaint circle_paint;
800  circle_paint.setColor(DlColor::kGreen().withAlpha(255 * 0.5));
801  circle_paint.setBlendMode(DlBlendMode::kPlus);
802  builder.DrawCircle({200, 200}, 100, circle_paint);
803  builder.Restore();
804  }
805  builder.Restore();
806 
807  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
808 }
809 
810 // Regression test for flutter/flutter#152780
811 TEST_P(AiksTest, CanDrawScaledPointsSmallScaleLargeRadius) {
812  std::vector<SkPoint> point = {
813  {0, 0}, //
814  };
815 
816  DlPaint paint;
817  paint.setStrokeCap(DlStrokeCap::kRound);
818  paint.setColor(DlColor::kRed());
819  paint.setStrokeWidth(100 * 1000000);
820 
821  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
822  builder.Translate(200, 200);
823  builder.Scale(0.000001, 0.000001);
824 
825  builder.DrawPoints(DlCanvas::PointMode::kPoints, point.size(), point.data(),
826  paint);
827 
828  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
829 }
830 
831 // Regression test for flutter/flutter#152780
832 TEST_P(AiksTest, CanDrawScaledPointsLargeScaleSmallRadius) {
833  std::vector<SkPoint> point = {
834  {0, 0}, //
835  };
836 
837  DlPaint paint;
838  paint.setStrokeCap(DlStrokeCap::kRound);
839  paint.setColor(DlColor::kRed());
840  paint.setStrokeWidth(100 * 0.000001);
841 
842  DisplayListBuilder builder(GetCullRect(GetWindowSize()));
843  builder.Translate(200, 200);
844  builder.Scale(1000000, 1000000);
845 
846  builder.DrawPoints(DlCanvas::PointMode::kPoints, point.size(), point.data(),
847  paint);
848  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
849 }
850 
851 TEST_P(AiksTest, TransparentShadowProducesCorrectColor) {
852  DisplayListBuilder builder;
853  builder.Save();
854  builder.Scale(1.618, 1.618);
855  SkPath path = SkPath{}.addRect(SkRect::MakeXYWH(0, 0, 200, 100));
856 
857  builder.DrawShadow(path, flutter::DlColor::kTransparent(), 15, false, 1);
858  builder.Restore();
859 
860  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
861 }
862 
863 // Regression test for https://github.com/flutter/flutter/issues/130613
864 TEST_P(AiksTest, DispatcherDoesNotCullPerspectiveTransformedChildDisplayLists) {
865  flutter::DisplayListBuilder sub_builder(true);
866  sub_builder.DrawRect(SkRect::MakeXYWH(0, 0, 50, 50),
867  flutter::DlPaint(flutter::DlColor::kRed()));
868  auto display_list = sub_builder.Build();
869 
870  AiksContext context(GetContext(), nullptr);
871  RenderTarget render_target =
872  context.GetContentContext().GetRenderTargetCache()->CreateOffscreen(
873  *context.GetContext(), {2400, 1800}, 1);
874 
875  DisplayListBuilder builder;
876 
877  builder.Scale(2.0, 2.0);
878  builder.Translate(-93.0, 0.0);
879 
880  // clang-format off
881  builder.TransformFullPerspective(
882  0.8, -0.2, -0.1, -0.0,
883  0.0, 1.0, 0.0, 0.0,
884  1.4, 1.3, 1.0, 0.0,
885  63.2, 65.3, 48.6, 1.1
886  );
887  // clang-format on
888  builder.Translate(35.0, 75.0);
889  builder.DrawDisplayList(display_list, 1.0f);
890 
891  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
892 }
893 
894 // Results in a 100x100 green square. If any red is drawn, there is a bug.
895 TEST_P(AiksTest, BackdropRestoreUsesCorrectCoverageForFirstRestoredClip) {
896  DisplayListBuilder builder;
897 
898  DlPaint paint;
899  // Add a difference clip that cuts out the bottom right corner
900  builder.ClipRect(SkRect::MakeLTRB(50, 50, 100, 100),
901  DlCanvas::ClipOp::kDifference);
902 
903  // Draw a red rectangle that's going to be completely covered by green later.
904  paint.setColor(DlColor::kRed());
905  builder.DrawRect(SkRect::MakeLTRB(0, 0, 100, 100), paint);
906 
907  // Add a clip restricting the backdrop filter to the top right corner.
908  auto count = builder.GetSaveCount();
909  builder.Save();
910  {
911  builder.ClipRect(SkRect::MakeLTRB(0, 0, 100, 100));
912  {
913  // Create a save layer with a backdrop blur filter.
914  auto backdrop_filter =
915  DlBlurImageFilter::Make(10.0, 10.0, DlTileMode::kDecal);
916  builder.SaveLayer(nullptr, nullptr, backdrop_filter.get());
917  }
918  }
919  builder.RestoreToCount(count);
920 
921  // Finally, overwrite all the previous stuff with green.
922  paint.setColor(DlColor::kGreen());
923  builder.DrawRect(SkRect::MakeLTRB(0, 0, 100, 100), paint);
924 
925  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
926 }
927 
928 TEST_P(AiksTest, CanPictureConvertToImage) {
929  DisplayListBuilder recorder_canvas;
930  DlPaint paint;
931  paint.setColor(DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0));
932  recorder_canvas.DrawRect(SkRect::MakeXYWH(100.0, 100.0, 600, 600), paint);
933  paint.setColor(DlColor::RGBA(0.1294, 0.5882, 0.9529, 1.0));
934  recorder_canvas.DrawRect(SkRect::MakeXYWH(200.0, 200.0, 600, 600), paint);
935 
936  DisplayListBuilder canvas;
937  AiksContext renderer(GetContext(), nullptr);
938  paint.setColor(DlColor::kTransparent());
939  canvas.DrawPaint(paint);
940 
941  auto image =
942  DisplayListToTexture(recorder_canvas.Build(), {1000, 1000}, renderer);
943  if (image) {
944  canvas.DrawImage(DlImageImpeller::Make(image), {}, {});
945  paint.setColor(DlColor::RGBA(0.1, 0.1, 0.1, 0.2));
946  canvas.DrawRect(SkRect::MakeSize({1000, 1000}), paint);
947  }
948 
949  ASSERT_TRUE(OpenPlaygroundHere(canvas.Build()));
950 }
951 
952 // Regression test for https://github.com/flutter/flutter/issues/142358 .
953 // Without a change to force render pass construction the image is left in an
954 // undefined layout and triggers a validation error.
955 TEST_P(AiksTest, CanEmptyPictureConvertToImage) {
956  DisplayListBuilder recorder_builder;
957 
958  DisplayListBuilder builder;
959  AiksContext renderer(GetContext(), nullptr);
960 
961  DlPaint paint;
962  paint.setColor(DlColor::kTransparent());
963  builder.DrawPaint(paint);
964 
965  auto result_image =
966  DisplayListToTexture(builder.Build(), ISize{1000, 1000}, renderer);
967  if (result_image) {
968  recorder_builder.DrawImage(DlImageImpeller::Make(result_image), {}, {});
969 
970  paint.setColor(DlColor::RGBA(0.1, 0.1, 0.1, 0.2));
971  recorder_builder.DrawRect(SkRect::MakeSize({1000, 1000}), paint);
972  }
973 
974  ASSERT_TRUE(OpenPlaygroundHere(recorder_builder.Build()));
975 }
976 
977 } // namespace testing
978 } // namespace impeller
impeller::DeviceBuffer::AsBufferView
static BufferView AsBufferView(std::shared_ptr< DeviceBuffer > buffer)
Create a buffer view of this entire buffer.
Definition: device_buffer.cc:18
impeller::ISize
ISize64 ISize
Definition: size.h:140
impeller::AiksPlayground
Definition: aiks_playground.h:16
impeller::k1OverSqrt2
constexpr float k1OverSqrt2
Definition: constants.h:50
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::AiksContext
Definition: aiks_context.h:19
impeller::AiksContext::GetContentContext
ContentContext & GetContentContext() const
Definition: aiks_context.cc:42
aiks_unittests.h
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:41
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
dl_dispatcher.h
impeller::TextureDescriptor::mip_count
size_t mip_count
Definition: texture_descriptor.h:43
impeller::StorageMode::kHostVisible
@ kHostVisible
impeller::DlImageImpeller::Make
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
Definition: dl_image_impeller.cc:23
impeller::TSize
Definition: size.h:19
flutter
Definition: dl_golden_blur_unittests.cc:15
impeller::RenderTarget
Definition: render_target.h:38
impeller::testing::TEST_P
TEST_P(AiksTest, DrawAtlasNoColor)
Definition: aiks_dl_atlas_unittests.cc:78
scalar.h
impeller::AiksContext::GetContext
std::shared_ptr< Context > GetContext() const
Definition: aiks_context.cc:38
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:42
impeller::ContentContext::GetRenderTargetCache
const std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
Definition: content_context.h:725
impeller::TextureDescriptor::GetByteSizeOfBaseMipLevel
constexpr size_t GetByteSizeOfBaseMipLevel() const
Definition: texture_descriptor.h:48
scale
const Scalar scale
Definition: stroke_path_geometry.cc:301
impeller::AiksPlayground::ImGuiBegin
static bool ImGuiBegin(const char *name, bool *p_open, ImGuiWindowFlags flags)
Definition: aiks_playground.cc:30
impeller::DisplayListToTexture
std::shared_ptr< Texture > DisplayListToTexture(const sk_sp< flutter::DisplayList > &display_list, ISize size, AiksContext &context, bool reset_host_buffer, bool generate_mips)
Render the provided display list to a texture with the given size.
Definition: dl_dispatcher.cc:1195
impeller::TextureDescriptor::storage_mode
StorageMode storage_mode
Definition: texture_descriptor.h:39
impeller::TRect::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:38
impeller::TSize::MipCount
constexpr size_t MipCount() const
Definition: size.h:115
impeller
Definition: allocation.cc:12
dl_image_impeller.h