12 #include "flutter/display_list/geometry/dl_path_builder.h"
13 #include "flutter/display_list/testing/dl_test_snippets.h"
14 #include "fml/logging.h"
15 #include "gtest/gtest.h"
58 #include "impeller/renderer/testing/mocks.h"
60 #include "third_party/abseil-cpp/absl/status/status_matchers.h"
61 #include "third_party/imgui/imgui.h"
78 auto image = CreateTextureForFixture(
"boston.jpg");
84 auto actual = filter->GetCoverage({});
87 ASSERT_TRUE(actual.has_value());
94 filter->SetCoverageHint(expected);
95 auto actual = filter->GetCoverage({});
97 ASSERT_TRUE(actual.has_value());
122 std::unique_ptr<Geometry> geom =
124 auto contents = std::make_unique<SolidColorContents>(geom.get());
127 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
131 auto bridge = CreateTextureForFixture(
"bay_bridge.jpg");
143 std::unique_ptr<Geometry> geom =
145 auto contents = std::make_unique<TiledTextureContents>(geom.get());
146 contents->SetTexture(bridge);
149 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
154 Point offset(100, 100);
185 std::unique_ptr<Geometry> geom =
187 auto contents = std::make_unique<SolidColorContents>(geom.get());
193 ASSERT_TRUE(OpenPlaygroundHere(callback));
198 const Point margin(140, 180);
204 static Scalar miter_limit = 1.41421357;
207 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
209 ImGui::SliderFloat(
"Miter limit", &miter_limit, 0, 30);
210 ImGui::SliderFloat(
"Stroke width", &width, 0, 100);
211 if (ImGui::Button(
"Reset")) {
212 miter_limit = 1.41421357;
219 auto render_path = [width = width, &
context, &pass, &world_matrix](
221 std::unique_ptr<Geometry> geom =
226 .miter_limit = miter_limit,
228 auto contents = std::make_unique<SolidColorContents>(geom.get());
236 if (coverage.has_value()) {
238 flutter::DlPath::MakeRect(entity.
GetCoverage().value()));
240 auto bounds_contents = std::make_unique<SolidColorContents>(geom.get());
241 bounds_contents->SetColor(
Color::Green().WithAlpha(0.5));
243 bounds_entity.
SetContents(std::move(bounds_contents));
250 const Point a_def(0, 0), b_def(0, 100), c_def(150, 0), d_def(150, -100),
262 render_path(flutter::DlPathBuilder{}
264 .CubicCurveTo(
b, d,
c)
278 render_path(flutter::DlPathBuilder{}
280 .CubicCurveTo(
b, d,
c)
294 render_path(flutter::DlPathBuilder{}
296 .CubicCurveTo(
b, d,
c)
313 render_path(flutter::DlPathBuilder{}
331 render_path(flutter::DlPathBuilder{}
349 render_path(flutter::DlPathBuilder{}
360 ASSERT_TRUE(OpenPlaygroundHere(callback));
366 flutter::DlPathBuilder{}
367 .MoveTo({237.164, 125.003})
368 .CubicCurveTo({236.709, 125.184}, {236.262, 125.358},
370 .CubicCurveTo({235.413, 125.68}, {234.994, 125.832},
372 .CubicCurveTo({234.592, 125.977}, {234.591, 125.977},
374 .CubicCurveTo({222.206, 130.435}, {207.708, 135.753},
376 .CubicCurveTo({162.77, 151.336}, {122.17, 156.894}, {84.1123, 160})
384 auto contents = std::make_shared<SolidColorContents>(geom.get());
388 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
393 const char* input_axis[] = {
"X",
"Y",
"Z"};
394 static int rotation_axis_index = 0;
395 static float rotation = 0;
396 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
397 ImGui::SliderFloat(
"Rotation", &rotation, -
kPi,
kPi);
398 ImGui::Combo(
"Rotation Axis", &rotation_axis_index, input_axis,
399 sizeof(input_axis) /
sizeof(
char*));
401 switch (rotation_axis_index) {
412 rotation_matrix =
Matrix{};
416 if (ImGui::Button(
"Reset")) {
420 Matrix current_transform =
424 pass.GetRenderTargetSize().height / 2.0)));
425 Matrix result_transform = current_transform * rotation_matrix;
434 auto contents = std::make_shared<SolidColorContents>(geom.get());
440 ASSERT_TRUE(OpenPlaygroundHere(callback));
446 flutter::DlPathBuilder{}
447 .MoveTo({359.934, 96.6335})
448 .CubicCurveTo({358.189, 96.7055}, {356.436, 96.7908},
450 .CubicCurveTo({354.571, 96.8953}, {354.469, 96.9016},
452 .CubicCurveTo({352.672, 97.0038}, {350.969, 97.113},
454 .CubicCurveTo({349.048, 97.2506}, {348.836, 97.2678},
456 .CubicCurveTo({347.019, 97.4014}, {345.407, 97.5299},
458 .CubicCurveTo({343.428, 97.704}, {343.065, 97.7402},
460 .CubicCurveTo({341.221, 97.9086}, {339.736, 98.0505},
462 .CubicCurveTo({337.702, 98.2642}, {337.156, 98.3292},
464 .CubicCurveTo({335.284, 98.5356}, {333.956, 98.6837},
466 .CubicCurveTo({332.495, 98.8635}, {332.366, 98.8818},
468 .
LineTo({332.237, 102.601})
469 .
LineTo({321.778, 102.601})
470 .
LineTo({321.778, 100.382})
471 .CubicCurveTo({321.572, 100.413}, {321.367, 100.442},
473 .CubicCurveTo({319.22, 100.79}, {317.277, 101.123},
475 .CubicCurveTo({315.322, 101.481}, {315.311, 101.482},
477 .
LineTo({310.017, 105.94})
478 .
LineTo({309.779, 105.427})
479 .
LineTo({314.403, 101.651})
480 .CubicCurveTo({314.391, 101.653}, {314.379, 101.656},
482 .CubicCurveTo({312.528, 102.001}, {310.687, 102.366},
484 .CubicCurveTo({307.85, 102.955}, {306.855, 103.182}, {305.859, 103.4})
485 .CubicCurveTo({305.048, 103.579}, {304.236, 103.75},
487 .
LineTo({299.105, 107.578})
488 .
LineTo({298.867, 107.065})
489 .
LineTo({302.394, 104.185})
490 .
LineTo({302.412, 104.171})
491 .CubicCurveTo({301.388, 104.409}, {300.366, 104.67},
493 .CubicCurveTo({298.618, 105.1}, {297.89, 105.269}, {297.165, 105.455})
494 .CubicCurveTo({295.262, 105.94}, {293.36, 106.445},
496 .CubicCurveTo({291.132, 107.072}, {290.802, 107.163},
498 .CubicCurveTo({289.463, 107.544}, {288.455, 107.839},
500 .CubicCurveTo({286.476, 108.431}, {285.506, 108.73},
502 .CubicCurveTo({283.674, 109.304}, {282.812, 109.579},
504 .CubicCurveTo({281.177, 110.112}, {280.406, 110.377},
506 .CubicCurveTo({278.458, 111.037}, {277.256, 111.449},
508 .CubicCurveTo({276.76, 111.622}, {276.716, 111.637},
510 .CubicCurveTo({275.017, 112.239}, {273.365, 112.836},
512 .
LineTo({271.717, 113.449})
513 .CubicCurveTo({271.496, 113.496}, {271.238, 113.559},
515 .CubicCurveTo({270.893, 113.645}, {270.822, 113.663},
517 .CubicCurveTo({270.468, 113.755}, {270.169, 113.834},
519 .CubicCurveTo({269.789, 113.94}, {269.732, 113.957},
521 .CubicCurveTo({269.391, 114.053}, {269.081, 114.143},
523 .CubicCurveTo({268.628, 114.276}, {268.5, 114.314},
525 .CubicCurveTo({268.172, 114.412}, {267.959, 114.478},
527 .CubicCurveTo({263.349, 115.964}, {258.058, 117.695},
529 .CubicCurveTo({253.556, 119.255}, {253.547, 119.258},
531 .CubicCurveTo({251.844, 119.849}, {250.056, 120.474},
533 .CubicCurveTo({248, 121.197}, {247.812, 121.264}, {247.621, 121.331})
534 .CubicCurveTo({247.079, 121.522}, {246.531, 121.715},
536 .CubicCurveTo({245.554, 122.06}, {245.126, 122.212},
538 .CubicCurveTo({244.071, 122.586}, {243.437, 122.811},
540 .CubicCurveTo({242.189, 123.255}, {241.58, 123.472},
542 .CubicCurveTo({240.659, 123.801}, {240.357, 123.909},
544 .CubicCurveTo({239.12, 124.351}, {238.18, 124.687}, {237.22, 125.032})
545 .
LineTo({237.164, 125.003})
546 .CubicCurveTo({236.709, 125.184}, {236.262, 125.358},
548 .CubicCurveTo({235.413, 125.68}, {234.994, 125.832},
550 .CubicCurveTo({234.592, 125.977}, {234.591, 125.977},
552 .CubicCurveTo({222.206, 130.435}, {207.708, 135.753},
554 .CubicCurveTo({162.77, 151.336}, {122.17, 156.894}, {84.1123, 160})
559 .CubicCurveTo({359.978, 96.6317}, {359.956, 96.6326},
562 .MoveTo({337.336, 124.143})
563 .CubicCurveTo({337.274, 122.359}, {338.903, 121.511},
565 .CubicCurveTo({338.903, 121.511}, {338.96, 123.303},
568 .MoveTo({340.082, 121.849})
569 .CubicCurveTo({340.074, 121.917}, {340.062, 121.992},
571 .CubicCurveTo({340.039, 122.109}, {340.031, 122.142},
573 .CubicCurveTo({340.005, 122.26}, {339.98, 122.346},
575 .CubicCurveTo({339.941, 122.473}, {339.931, 122.507},
577 .CubicCurveTo({339.873, 122.672}, {339.819, 122.804},
579 .CubicCurveTo({339.747, 122.944}, {339.743, 122.949},
581 .CubicCurveTo({339.674, 123.08}, {339.593, 123.205},
583 .CubicCurveTo({339.473, 123.366}, {339.441, 123.401},
585 .CubicCurveTo({339.332, 123.534}, {339.243, 123.625},
587 .CubicCurveTo({339.105, 123.75}, {339.068, 123.786},
589 .CubicCurveTo({338.881, 123.937}, {338.724, 124.048},
591 .CubicCurveTo({338.532, 123.959}, {338.554, 123.79},
593 .CubicCurveTo({338.58, 123.625}, {338.58, 123.625}, {338.58, 123.625})
594 .CubicCurveTo({338.607, 123.455}, {338.65, 123.299},
596 .CubicCurveTo({338.708, 123.14}, {338.71, 123.127},
598 .CubicCurveTo({338.769, 122.971}, {338.833, 122.838},
600 .CubicCurveTo({338.911, 122.702}, {338.916, 122.69200000000001},
602 .CubicCurveTo({338.996, 122.557}, {339.072, 122.444},
604 .CubicCurveTo({339.161, 122.333}, {339.166, 122.326},
606 .CubicCurveTo({339.256, 122.215}, {339.339, 122.12},
608 .CubicCurveTo({339.428, 122.033}, {339.431, 122.03},
610 .CubicCurveTo({339.785, 121.687}, {340.106, 121.511},
612 .CubicCurveTo({340.106, 121.511}, {340.107, 121.645},
615 .MoveTo({340.678, 113.245})
616 .CubicCurveTo({340.594, 113.488}, {340.356, 113.655},
618 .CubicCurveTo({339.817, 113.948}, {339.465, 114.059},
620 .CubicCurveTo({338.251, 114.379}, {337.34, 114.516},
622 .CubicCurveTo({335.761, 114.516}, {335.072, 114.527},
624 .CubicCurveTo({334.125, 114.508}, {333.862, 114.462},
626 .CubicCurveTo({332.865, 114.318}, {332.096, 114.184},
628 .CubicCurveTo({330.979, 113.695}, {330.442, 113.34},
630 .CubicCurveTo({331.135, 111.755}, {333.219, 112.946},
632 .CubicCurveTo({334.54, 113.816}, {334.554, 113.8}, {334.569, 113.784})
633 .CubicCurveTo({333.38, 112.708}, {331.749, 110.985},
635 .CubicCurveTo({333.769, 109.82}, {334.713, 111.93},
637 .CubicCurveTo({334.915, 111.889}, {334.59, 109.636},
639 .CubicCurveTo({336.733, 109.636}, {336.408, 111.889},
641 .CubicCurveTo({336.609, 111.93}, {337.553, 109.82},
643 .CubicCurveTo({339.574, 110.984}, {337.942, 112.708},
645 .CubicCurveTo({336.768, 113.8}, {336.782, 113.816},
647 .CubicCurveTo({338.104, 112.946}, {340.187, 111.755},
649 .CubicCurveTo({340.71, 112.95}, {340.728, 113.102},
652 .MoveTo({346.357, 106.771})
653 .CubicCurveTo({346.295, 104.987}, {347.924, 104.139},
655 .CubicCurveTo({347.924, 104.139}, {347.982, 105.931},
658 .MoveTo({347.56, 106.771})
659 .CubicCurveTo({347.498, 104.987}, {349.127, 104.139},
661 .CubicCurveTo({349.127, 104.139}, {349.185, 105.931},
670 auto contents = std::make_shared<SolidColorContents>(geom.get());
674 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
682 ASSERT_EQ(path_geometry->GetStrokeCap(),
Cap::kButt);
683 ASSERT_EQ(path_geometry->GetStrokeJoin(),
Join::kMiter);
705 ASSERT_EQ(path_geometry->GetStrokeCap(),
Cap::kRound);
713 ASSERT_FLOAT_EQ(path_geometry->GetMiterLimit(), 4);
723 ASSERT_FLOAT_EQ(path_geometry->GetMiterLimit(), 8);
730 .miter_limit = -1.0f,
733 ASSERT_FLOAT_EQ(path_geometry->GetMiterLimit(), 4);
738 std::vector<const char*> blend_mode_names;
739 std::vector<BlendMode> blend_mode_values;
752 blend_mode_names.push_back(
"Clear");
755 blend_mode_names.push_back(
"Source");
758 blend_mode_names.push_back(
"Destination");
761 blend_mode_names.push_back(
"SourceOver");
764 blend_mode_names.push_back(
"DestinationOver");
767 blend_mode_names.push_back(
"SourceIn");
770 blend_mode_names.push_back(
"DestinationIn");
773 blend_mode_names.push_back(
"SourceOut");
776 blend_mode_names.push_back(
"DestinationOut");
779 blend_mode_names.push_back(
"SourceATop");
782 blend_mode_names.push_back(
"DestinationATop");
785 blend_mode_names.push_back(
"Xor");
788 blend_mode_names.push_back(
"Plus");
791 blend_mode_names.push_back(
"Modulate");
798 auto draw_rect = [&
context, &pass, &world_matrix](
805 auto r = rect.GetLTRB();
816 pass.SetCommandLabel(
"Blended Rectangle");
818 options.blend_mode = blend_mode;
820 pass.SetPipeline(
context.GetSolidFillPipeline(options));
821 pass.SetVertexBuffer(
823 context.GetTransientsIndexesBuffer()));
825 VS::FrameInfo frame_info;
826 frame_info.mvp = pass.GetOrthographicTransform() * world_matrix;
828 pass,
context.GetTransientsDataBuffer().EmplaceUniform(frame_info));
829 FS::FragInfo frag_info;
830 frag_info.color = color.Premultiply();
832 pass,
context.GetTransientsDataBuffer().EmplaceUniform(frag_info));
833 return pass.Draw().ok();
836 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
837 static Color color1(1, 0, 0, 0.5), color2(0, 1, 0, 0.5);
838 ImGui::ColorEdit4(
"Color 1",
reinterpret_cast<float*
>(&color1));
839 ImGui::ColorEdit4(
"Color 2",
reinterpret_cast<float*
>(&color2));
840 static int current_blend_index = 3;
841 ImGui::ListBox(
"Blending mode", ¤t_blend_index,
842 blend_mode_names.data(), blend_mode_names.size());
845 BlendMode selected_mode = blend_mode_values[current_blend_index];
858 pass.GetRenderTargetSize().height),
866 ASSERT_TRUE(OpenPlaygroundHere(callback));
871 static float scale = 20;
873 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
874 ImGui::SliderFloat(
"Scale", &scale, 1, 100);
879 auto path = flutter::DlPathBuilder{}
880 .MoveTo({97.325, 34.818})
881 .CubicCurveTo({98.50862885295136, 34.81812293973836},
882 {99.46822048142015, 33.85863261475589},
883 {99.46822048142015, 32.67499810206613})
884 .CubicCurveTo({99.46822048142015, 31.491363589376355},
885 {98.50862885295136, 30.53187326439389},
886 {97.32499434685802, 30.531998226542708})
887 .CubicCurveTo({96.14153655073771, 30.532123170035373},
888 {95.18222070648729, 31.491540299350355},
889 {95.18222070648729, 32.67499810206613})
890 .CubicCurveTo({95.18222070648729, 33.85845590478189},
891 {96.14153655073771, 34.81787303409686},
892 {97.32499434685802, 34.81799797758954})
900 auto contents = std::make_shared<SolidColorContents>(geom.get());
906 ASSERT_TRUE(OpenPlaygroundHere(callback));
910 auto bridge = CreateTextureForFixture(
"bay_bridge.jpg");
911 auto boston = CreateTextureForFixture(
"boston.jpg");
912 auto kalimba = CreateTextureForFixture(
"kalimba.jpg");
913 ASSERT_TRUE(bridge && boston && kalimba);
931 entity.SetContents(blend1);
932 return entity.Render(
context, pass);
934 ASSERT_TRUE(OpenPlaygroundHere(callback));
939 CreateTextureForFixture(
"boston.jpg",
true);
943 const char* input_type_names[] = {
"Texture",
"Solid Color"};
944 const char* blur_type_names[] = {
"Image blur",
"Mask blur"};
945 const char* pass_variation_names[] = {
"New"};
946 const char* blur_style_names[] = {
"Normal",
"Solid",
"Outer",
"Inner"};
947 const char* tile_mode_names[] = {
"Clamp",
"Repeat",
"Mirror",
"Decal"};
956 static int selected_input_type = 0;
958 static int selected_blur_type = 0;
959 static int selected_pass_variation = 0;
960 static bool combined_sigma =
false;
961 static float blur_amount_coarse[2] = {0, 0};
962 static float blur_amount_fine[2] = {10, 10};
963 static int selected_blur_style = 0;
964 static int selected_tile_mode = 3;
965 static Color cover_color(1, 0, 0, 0.2);
966 static Color bounds_color(0, 1, 0, 0.1);
967 static float offset[2] = {500, 400};
968 static float rotation = 0;
969 static float scale[2] = {0.65, 0.65};
970 static float skew[2] = {0, 0};
971 static float path_rect[4] = {0, 0,
972 static_cast<float>(boston->GetSize().width),
973 static_cast<float>(boston->GetSize().height)};
975 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
977 ImGui::Combo(
"Input type", &selected_input_type, input_type_names,
978 sizeof(input_type_names) /
sizeof(
char*));
979 if (selected_input_type == 0) {
980 ImGui::SliderFloat(
"Input opacity", &input_color.
alpha, 0, 1);
982 ImGui::ColorEdit4(
"Input color",
983 reinterpret_cast<float*
>(&input_color));
985 ImGui::Combo(
"Blur type", &selected_blur_type, blur_type_names,
986 sizeof(blur_type_names) /
sizeof(
char*));
987 if (selected_blur_type == 0) {
988 ImGui::Combo(
"Pass variation", &selected_pass_variation,
989 pass_variation_names,
990 sizeof(pass_variation_names) /
sizeof(
char*));
992 ImGui::Checkbox(
"Combined sigma", &combined_sigma);
993 if (combined_sigma) {
994 ImGui::SliderFloat(
"Sigma (coarse)", blur_amount_coarse, 0, 1000);
995 ImGui::SliderFloat(
"Sigma (fine)", blur_amount_fine, 0, 10);
996 blur_amount_coarse[1] = blur_amount_coarse[0];
997 blur_amount_fine[1] = blur_amount_fine[0];
999 ImGui::SliderFloat2(
"Sigma (coarse)", blur_amount_coarse, 0, 1000);
1000 ImGui::SliderFloat2(
"Sigma (fine)", blur_amount_fine, 0, 10);
1002 ImGui::Combo(
"Blur style", &selected_blur_style, blur_style_names,
1003 sizeof(blur_style_names) /
sizeof(
char*));
1004 ImGui::Combo(
"Tile mode", &selected_tile_mode, tile_mode_names,
1005 sizeof(tile_mode_names) /
sizeof(
char*));
1006 ImGui::ColorEdit4(
"Cover color",
reinterpret_cast<float*
>(&cover_color));
1007 ImGui::ColorEdit4(
"Bounds color ",
1008 reinterpret_cast<float*
>(&bounds_color));
1009 ImGui::SliderFloat2(
"Translation", offset, 0,
1010 pass.GetRenderTargetSize().width);
1011 ImGui::SliderFloat(
"Rotation", &rotation, 0,
kPi * 2);
1012 ImGui::SliderFloat2(
"Scale", scale, 0, 3);
1013 ImGui::SliderFloat2(
"Skew", skew, -3, 3);
1014 ImGui::SliderFloat4(
"Path XYWH", path_rect, -1000, 1000);
1018 auto blur_sigma_x =
Sigma{blur_amount_coarse[0] + blur_amount_fine[0]};
1019 auto blur_sigma_y =
Sigma{blur_amount_coarse[1] + blur_amount_fine[1]};
1021 std::shared_ptr<Contents> input;
1025 Rect::MakeXYWH(path_rect[0], path_rect[1], path_rect[2], path_rect[3]);
1027 std::unique_ptr<Geometry> solid_color_input;
1028 if (selected_input_type == 0) {
1029 auto texture = std::make_shared<TextureContents>();
1031 texture->SetDestinationRect(input_rect);
1032 texture->SetTexture(boston);
1033 texture->SetOpacity(input_color.
alpha);
1036 input_size = input_rect.GetSize();
1040 auto fill = std::make_shared<SolidColorContents>(solid_color_input.get());
1041 fill->SetColor(input_color);
1044 input_size = input_rect.GetSize();
1047 std::shared_ptr<FilterContents> blur;
1048 switch (selected_pass_variation) {
1050 blur = std::make_shared<GaussianBlurFilterContents>(
1051 blur_sigma_x.sigma, blur_sigma_y.sigma,
1052 tile_modes[selected_tile_mode], std::nullopt,
1053 blur_styles[selected_blur_style],
1060 tile_modes[selected_tile_mode],
1061 std::nullopt, blur_styles[selected_blur_style]);
1068 blur_styles[selected_blur_style]);
1077 auto target_contents = selected_blur_type == 0 ? blur : mask_blur;
1089 auto contents = std::make_shared<SolidColorContents>(geom.get());
1090 contents->SetColor(cover_color);
1097 std::optional<Rect> target_contents_coverage =
1099 if (target_contents_coverage.has_value()) {
1100 std::unique_ptr<Geometry> geom =
1102 target_contents->GetCoverage(entity).value()));
1103 auto contents = std::make_shared<SolidColorContents>(geom.get());
1104 contents->SetColor(bounds_color);
1113 ASSERT_TRUE(OpenPlaygroundHere(callback));
1117 auto boston = CreateTextureForFixture(
"boston.jpg");
1118 ASSERT_TRUE(boston);
1121 const char* morphology_type_names[] = {
"Dilate",
"Erode"};
1126 static int selected_morphology_type = 0;
1127 static float radius[2] = {20, 20};
1128 static Color cover_color(1, 0, 0, 0.2);
1129 static Color bounds_color(0, 1, 0, 0.1);
1130 static float offset[2] = {500, 400};
1131 static float rotation = 0;
1132 static float scale[2] = {0.65, 0.65};
1133 static float skew[2] = {0, 0};
1134 static float path_rect[4] = {0, 0,
1135 static_cast<float>(boston->GetSize().width),
1136 static_cast<float>(boston->GetSize().height)};
1137 static float effect_transform_scale = 1;
1139 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1141 ImGui::Combo(
"Morphology type", &selected_morphology_type,
1142 morphology_type_names,
1143 sizeof(morphology_type_names) /
sizeof(
char*));
1144 ImGui::SliderFloat2(
"Radius", radius, 0, 200);
1145 ImGui::SliderFloat(
"Input opacity", &input_color.
alpha, 0, 1);
1146 ImGui::ColorEdit4(
"Cover color",
reinterpret_cast<float*
>(&cover_color));
1147 ImGui::ColorEdit4(
"Bounds color ",
1148 reinterpret_cast<float*
>(&bounds_color));
1149 ImGui::SliderFloat2(
"Translation", offset, 0,
1150 pass.GetRenderTargetSize().width);
1151 ImGui::SliderFloat(
"Rotation", &rotation, 0,
kPi * 2);
1152 ImGui::SliderFloat2(
"Scale", scale, 0, 3);
1153 ImGui::SliderFloat2(
"Skew", skew, -3, 3);
1154 ImGui::SliderFloat4(
"Path XYWH", path_rect, -1000, 1000);
1155 ImGui::SliderFloat(
"Effect transform scale", &effect_transform_scale, 0,
1160 std::shared_ptr<Contents> input;
1164 Rect::MakeXYWH(path_rect[0], path_rect[1], path_rect[2], path_rect[3]);
1165 auto texture = std::make_shared<TextureContents>();
1167 texture->SetDestinationRect(input_rect);
1168 texture->SetTexture(boston);
1169 texture->SetOpacity(input_color.
alpha);
1172 input_size = input_rect.GetSize();
1176 morphology_types[selected_morphology_type]);
1178 Vector2{effect_transform_scale, effect_transform_scale}));
1197 auto cover_contents = std::make_shared<SolidColorContents>(geom.get());
1198 cover_contents->SetColor(cover_color);
1206 flutter::DlPath::MakeRect(contents->GetCoverage(entity).value()));
1207 auto bounds_contents =
1208 std::make_shared<SolidColorContents>(bounds_geom.get());
1209 bounds_contents->SetColor(bounds_color);
1210 bounds_entity.
SetContents(std::move(bounds_contents));
1217 ASSERT_TRUE(OpenPlaygroundHere(callback));
1229 entity.
SetContents(std::make_shared<SolidColorContents>(
nullptr));
1237 auto geometry = std::make_unique<UberSDFGeometry>(params);
1242 ASSERT_TRUE(coverage.has_value());
1252 auto geometry = std::make_unique<UberSDFGeometry>(params);
1257 ASSERT_TRUE(coverage.has_value());
1266 10.0f, std::nullopt);
1267 auto geometry = std::make_unique<UberSDFGeometry>(params);
1272 ASSERT_TRUE(coverage.has_value());
1282 auto geometry = std::make_unique<UberSDFGeometry>(params);
1287 ASSERT_TRUE(coverage.has_value());
1296 flutter::DlPath::MakeLine({0, 0}, {10, 10}),
1301 .miter_limit = 4.0f,
1305 auto contents = std::make_unique<SolidColorContents>(geometry.get());
1307 entity.SetContents(std::move(contents));
1308 auto actual = entity.GetCoverage();
1311 ASSERT_TRUE(actual.has_value());
1318 flutter::DlPath::MakeLine({0, 0}, {10, 10}),
1327 auto contents = std::make_unique<SolidColorContents>(geometry.get());
1329 entity.SetContents(std::move(contents));
1330 auto actual = entity.GetCoverage();
1334 ASSERT_TRUE(actual.has_value());
1341 flutter::DlPath::MakeLine({0, 0}, {10, 10}),
1346 .miter_limit = 2.0f,
1350 auto contents = std::make_unique<SolidColorContents>(geometry.get());
1352 entity.SetContents(std::move(contents));
1353 auto actual = entity.GetCoverage();
1356 ASSERT_TRUE(actual.has_value());
1364 auto fill = std::make_shared<SolidColorContents>(geom.get());
1372 auto actual = border_mask_blur->GetCoverage(e);
1374 ASSERT_TRUE(actual.has_value());
1381 auto actual = border_mask_blur->GetCoverage(e);
1382 auto expected =
Rect::MakeXYWH(-287.792, -4.94975, 504.874, 504.874);
1383 ASSERT_TRUE(actual.has_value());
1393 auto fill = std::make_shared<SolidColorContents>(geom.get());
1396 auto coverage = fill->GetCoverage({});
1397 ASSERT_TRUE(coverage.has_value());
1405 auto fill = std::make_shared<SolidColorContents>(geom.get());
1414 ASSERT_TRUE(coverage.has_value());
1422 auto fill = std::make_shared<SolidColorContents>(geom.get());
1425 auto coverage = fill->GetCoverage({});
1426 ASSERT_FALSE(coverage.has_value());
1433 static float corner_radius = 100;
1435 static bool show_coverage =
false;
1441 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1442 ImGui::SliderFloat(
"Corner radius", &corner_radius, 0, 300);
1443 ImGui::SliderFloat(
"Blur radius", &
blur_radius, 0, 300);
1444 ImGui::ColorEdit4(
"Color",
reinterpret_cast<Scalar*
>(&color));
1445 ImGui::Checkbox(
"Show coverage", &show_coverage);
1446 if (show_coverage) {
1447 ImGui::ColorEdit4(
"Coverage color",
1448 reinterpret_cast<Scalar*
>(&coverage_color));
1452 auto [top_left, bottom_right] =
1455 Rect::MakeLTRB(top_left.x, top_left.y, bottom_right.x, bottom_right.y);
1457 auto contents = std::make_unique<SolidRRectBlurContents>();
1458 contents->SetShape(rect, corner_radius);
1459 contents->SetColor(color);
1468 if (show_coverage && coverage.has_value()) {
1470 flutter::DlPath::MakeRect(entity.
GetCoverage().value()));
1471 auto bounds_contents = std::make_unique<SolidColorContents>(geom.get());
1472 bounds_contents->SetColor(coverage_color.
Premultiply());
1474 bounds_entity.
SetContents(std::move(bounds_contents));
1480 ASSERT_TRUE(OpenPlaygroundHere(callback));
1487 auto fill = std::make_shared<SolidColorContents>(geom.get());
1505 auto actual = filter->GetCoverage(e);
1508 ASSERT_TRUE(actual.has_value());
1513 auto bay_bridge = CreateTextureForFixture(
"bay_bridge.jpg");
1514 ASSERT_TRUE(bay_bridge);
1524 static float offset[2] = {500, 400};
1525 static float rotation = 0;
1526 static float scale[2] = {0.65, 0.65};
1527 static float skew[2] = {0, 0};
1530 ImGui::Begin(
"Color Matrix",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1532 std::string label =
"##1";
1533 for (
int i = 0; i < 20; i += 5) {
1534 ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
1535 &(color_matrix.
array[i]), 5,
nullptr,
nullptr,
1540 ImGui::SliderFloat2(
"Translation", &offset[0], 0,
1541 pass.GetRenderTargetSize().width);
1542 ImGui::SliderFloat(
"Rotation", &rotation, 0,
kPi * 2);
1543 ImGui::SliderFloat2(
"Scale", &scale[0], 0, 3);
1544 ImGui::SliderFloat2(
"Skew", &skew[0], -3, 3);
1567 ASSERT_TRUE(OpenPlaygroundHere(callback));
1574 auto fill = std::make_shared<SolidColorContents>(geom.get());
1584 auto actual = filter->GetCoverage(e);
1587 ASSERT_TRUE(actual.has_value());
1592 auto image = CreateTextureForFixture(
"kalimba.jpg");
1619 ASSERT_TRUE(OpenPlaygroundHere(callback));
1626 auto fill = std::make_shared<SolidColorContents>(geom.get());
1636 auto actual = filter->GetCoverage(e);
1639 ASSERT_TRUE(actual.has_value());
1644 auto image = CreateTextureForFixture(
"embarcadero.jpg");
1671 ASSERT_TRUE(OpenPlaygroundHere(callback));
1676 switch (yuv_color_space) {
1678 yuv.
x = rgb.
x * 0.299 + rgb.
y * 0.587 + rgb.
z * 0.114;
1679 yuv.
y = rgb.
x * -0.169 + rgb.
y * -0.331 + rgb.
z * 0.5 + 0.5;
1680 yuv.
z = rgb.
x * 0.5 + rgb.
y * -0.419 + rgb.
z * -0.081 + 0.5;
1683 yuv.
x = rgb.
x * 0.257 + rgb.
y * 0.516 + rgb.
z * 0.100 + 0.063;
1684 yuv.
y = rgb.
x * -0.145 + rgb.
y * -0.291 + rgb.
z * 0.439 + 0.5;
1685 yuv.
z = rgb.
x * 0.429 + rgb.
y * -0.368 + rgb.
z * -0.071 + 0.5;
1694 Vector3 red = {244.0 / 255.0, 67.0 / 255.0, 54.0 / 255.0};
1695 Vector3 green = {76.0 / 255.0, 175.0 / 255.0, 80.0 / 255.0};
1696 Vector3 blue = {33.0 / 255.0, 150.0 / 255.0, 243.0 / 255.0};
1697 Vector3 white = {1.0, 1.0, 1.0};
1702 std::vector<Vector3> yuvs{red_yuv, green_yuv, blue_yuv, white_yuv};
1703 std::vector<uint8_t> y_data;
1704 std::vector<uint8_t> uv_data;
1705 for (
int i = 0; i < 4; i++) {
1707 uint8_t y = std::round(yuv.x * 255.0);
1708 uint8_t u = std::round(yuv.y * 255.0);
1709 uint8_t v = std::round(yuv.z * 255.0);
1710 for (
int j = 0; j < 16; j++) {
1711 y_data.push_back(y);
1713 for (
int j = 0; j < 8; j++) {
1714 uv_data.push_back(j % 2 == 0 ? u : v);
1717 auto cmd_buffer =
context->CreateCommandBuffer();
1718 auto blit_pass = cmd_buffer->CreateBlitPass();
1723 y_texture_descriptor.
size = {8, 8};
1725 context->GetResourceAllocator()->CreateTexture(y_texture_descriptor);
1726 auto y_mapping = std::make_shared<fml::DataMapping>(y_data);
1727 auto y_mapping_buffer =
1728 context->GetResourceAllocator()->CreateBufferWithCopy(*y_mapping);
1735 uv_texture_descriptor.
size = {4, 4};
1737 context->GetResourceAllocator()->CreateTexture(uv_texture_descriptor);
1738 auto uv_mapping = std::make_shared<fml::DataMapping>(uv_data);
1739 auto uv_mapping_buffer =
1740 context->GetResourceAllocator()->CreateBufferWithCopy(*uv_mapping);
1744 if (!blit_pass->EncodeCommands() ||
1745 !
context->GetCommandQueue()->Submit({cmd_buffer}).ok()) {
1746 FML_DLOG(ERROR) <<
"Could not copy contents into Y/UV texture.";
1749 return {y_texture, uv_texture};
1757 <<
"YUV to RGB filter is not supported on OpenGLES backend yet.";
1763 for (
int i = 0; i < 2; i++) {
1764 auto yuv_color_space = yuv_color_space_array[i];
1768 textures[0], textures[1], yuv_color_space);
1772 filter_contents->RenderToSnapshot(
context, filter_entity, {});
1776 contents->SetTexture(snapshot->texture);
1777 contents->SetSourceRect(
Rect::MakeSize(snapshot->texture->GetSize()));
1785 ASSERT_TRUE(OpenPlaygroundHere(callback));
1789 auto runtime_stages_result =
1790 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
1791 ABSL_ASSERT_OK(runtime_stages_result);
1792 std::shared_ptr<RuntimeStage> runtime_stage =
1794 ASSERT_TRUE(runtime_stage);
1795 ASSERT_TRUE(runtime_stage->IsDirty());
1797 bool expect_dirty =
true;
1803 EXPECT_EQ(runtime_stage->IsDirty(), expect_dirty);
1805 auto contents = std::make_shared<RuntimeEffectContents>(geom.get());
1806 contents->SetRuntimeStage(runtime_stage);
1808 struct FragUniforms {
1812 .iResolution =
Vector2(GetWindowSize().width, GetWindowSize().height),
1813 .iTime =
static_cast<Scalar>(GetSecondsElapsed()),
1815 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
1816 uniform_data->resize(
sizeof(FragUniforms));
1817 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
1818 contents->SetUniformData(uniform_data);
1822 bool result = contents->Render(
context, entity, pass);
1825 first_pipeline = pass.GetCommands().back().pipeline;
1827 EXPECT_EQ(pass.GetCommands().back().pipeline, first_pipeline);
1829 expect_dirty =
false;
1840 testing::MockRenderPass mock_pass(GetContext(), target);
1841 callback(content_context, mock_pass);
1842 callback(content_context, mock_pass);
1845 auto runtime_stages_result =
1846 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
1847 ABSL_ASSERT_OK(runtime_stages_result);
1850 ASSERT_TRUE(runtime_stage->IsDirty());
1851 expect_dirty =
true;
1853 callback(content_context, mock_pass);
1858 auto runtime_stages_result =
1859 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
1860 ABSL_ASSERT_OK(runtime_stages_result);
1862 ASSERT_TRUE(runtime_stage);
1863 ASSERT_TRUE(runtime_stage->IsDirty());
1866 auto contents = std::make_shared<RuntimeEffectContents>(geom.get());
1867 contents->SetRuntimeStage(runtime_stage);
1869 struct FragUniforms {
1873 .iResolution =
Vector2(GetWindowSize().width, GetWindowSize().height),
1874 .iTime =
static_cast<Scalar>(GetSecondsElapsed()),
1876 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
1877 uniform_data->resize(
sizeof(FragUniforms));
1878 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
1879 contents->SetUniformData(uniform_data);
1887 GetContentContext().GetRenderTargetCache()->CreateOffscreenMSAA(
1888 *GetContext(), {GetWindowSize().width, GetWindowSize().height}, 1,
1889 "RuntimeEffect Texture");
1890 testing::MockRenderPass pass(GetContext(), target);
1892 ASSERT_TRUE(contents->Render(GetContentContext(), entity, pass));
1893 ASSERT_EQ(pass.GetCommands().size(), 1u);
1894 const auto& command = pass.GetCommands()[0];
1895 ASSERT_TRUE(command.pipeline->GetDescriptor()
1896 .GetDepthStencilAttachmentDescriptor()
1898 ASSERT_TRUE(command.pipeline->GetDescriptor()
1899 .GetFrontStencilAttachmentDescriptor()
1904 auto runtime_stages_result =
1905 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
1906 ABSL_ASSERT_OK(runtime_stages_result);
1907 std::shared_ptr<RuntimeStage> runtime_stage =
1909 ASSERT_TRUE(runtime_stage);
1910 ASSERT_TRUE(runtime_stage->IsDirty());
1913 auto contents = std::make_shared<RuntimeEffectContents>(geom.get());
1914 contents->SetRuntimeStage(runtime_stage);
1916 EXPECT_TRUE(contents->BootstrapShader(GetContentContext()));
1921 GTEST_SKIP() <<
"Test only applies to Vulkan";
1924 auto runtime_stages_result =
1925 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
1926 ABSL_ASSERT_OK(runtime_stages_result);
1928 ASSERT_TRUE(runtime_stage);
1929 ASSERT_TRUE(runtime_stage->IsDirty());
1932 auto contents = std::make_shared<RuntimeEffectContents>(geom.get());
1933 contents->SetRuntimeStage(runtime_stage);
1935 struct FragUniforms {
1939 .iResolution =
Vector2(GetWindowSize().width, GetWindowSize().height),
1940 .iTime =
static_cast<Scalar>(GetSecondsElapsed()),
1942 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
1943 uniform_data->resize(
sizeof(FragUniforms));
1944 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
1947 uniform_data->data(), GetContentContext().GetTransientsDataBuffer(),
1948 runtime_stage->GetUniforms()[0]);
1954 EXPECT_EQ(buffer_view.GetRange().length, 16u);
1958 auto image = CreateTextureForFixture(
"boston.jpg");
1970 ASSERT_TRUE(OpenPlaygroundHere(callback));
1974 auto image = CreateTextureForFixture(
"boston.jpg");
1986 ASSERT_TRUE(OpenPlaygroundHere(callback));
1990 auto image = CreateTextureForFixture(
"boston.jpg");
2002 ASSERT_TRUE(OpenPlaygroundHere(callback));
2006 auto image = CreateTextureForFixture(
"boston.jpg");
2018 ASSERT_TRUE(OpenPlaygroundHere(callback));
2022 auto image = CreateTextureForFixture(
"boston.jpg");
2034 ASSERT_TRUE(OpenPlaygroundHere(callback));
2038 auto arrow_head = flutter::DlPathBuilder{}
2048 .miter_limit = 4.0f,
2058 auto coverage = geometry->GetCoverage(
transform);
2068 EXPECT_TRUE(contents.
IsOpaque(matrix));
2070 EXPECT_FALSE(contents.
IsOpaque(matrix));
2074 flutter::DlPath::MakeLine({0, 0}, {100, 100}), {.width = 0.05});
2078 EXPECT_FALSE(contents2.IsOpaque(matrix));
2087 EXPECT_FALSE(contents.
IsOpaque(matrix));
2089 EXPECT_FALSE(contents.
IsOpaque(matrix));
2093 flutter::DlPathBuilder{}.MoveTo({0, 0}).
LineTo({100, 100}).TakePath(),
2098 EXPECT_FALSE(contents2.IsOpaque(matrix));
2107 EXPECT_TRUE(contents.
IsOpaque(matrix));
2109 EXPECT_FALSE(contents.
IsOpaque(matrix));
2112 EXPECT_FALSE(contents.
IsOpaque(matrix));
2116 flutter::DlPathBuilder{}.MoveTo({0, 0}).
LineTo({100, 100}).TakePath(),
2121 EXPECT_FALSE(contents2.IsOpaque(matrix));
2130 EXPECT_TRUE(contents.
IsOpaque(matrix));
2132 EXPECT_FALSE(contents.
IsOpaque(matrix));
2135 EXPECT_FALSE(contents.
IsOpaque(matrix));
2139 flutter::DlPathBuilder{}.MoveTo({0, 0}).
LineTo({100, 100}).TakePath(),
2144 EXPECT_FALSE(contents2.IsOpaque(matrix));
2153 EXPECT_TRUE(contents.
IsOpaque(matrix));
2155 EXPECT_FALSE(contents.
IsOpaque(matrix));
2158 EXPECT_FALSE(contents.
IsOpaque(matrix));
2162 flutter::DlPathBuilder{}.MoveTo({0, 0}).
LineTo({100, 100}).TakePath(),
2167 EXPECT_FALSE(contents2.IsOpaque(matrix));
2172 auto bay_bridge = CreateTextureForFixture(
"bay_bridge.jpg");
2179 EXPECT_FALSE(contents.
IsOpaque(matrix));
2183 std::vector<Point>
points = {{10, 20}, {100, 200}};
2194 auto src_contents = std::make_shared<SolidColorContents>(src_geom.get());
2198 auto dst_contents = std::make_shared<SolidColorContents>(dst_geom.get());
2205 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
2221 .has_depth_stencil_attachments =
false,
2225 .has_depth_stencil_attachments =
true});
2227 EXPECT_NE(default_gyph, alt_gyph);
2228 EXPECT_EQ(default_gyph->GetDescriptor().GetSpecializationConstants(),
2229 alt_gyph->GetDescriptor().GetSpecializationConstants());
2231 auto use_a8 = GetContext()->GetCapabilities()->GetDefaultGlyphAtlasFormat() ==
2234 std::vector<Scalar> expected_constants = {
static_cast<Scalar>(use_a8)};
2235 EXPECT_EQ(default_gyph->GetDescriptor().GetSpecializationConstants(),
2236 expected_constants);
2245 auto decal_supported =
static_cast<Scalar>(
2246 GetContext()->GetCapabilities()->SupportsDecalSamplerAddressMode());
2247 std::vector<Scalar> expected_constants = {decal_supported};
2248 ASSERT_EQ(default_color_burn->GetDescriptor().GetSpecializationConstants(),
2249 expected_constants);
2257 auto hash_a = opts.
ToKey();
2260 auto hash_b = opts.
ToKey();
2263 auto hash_c = opts.
ToKey();
2266 auto hash_d = opts.
ToKey();
2268 EXPECT_NE(hash_a, hash_b);
2269 EXPECT_NE(hash_b, hash_c);
2270 EXPECT_NE(hash_c, hash_d);
2287 bool expected_layout =
false;
2289 FragmentShader::kDescriptorSetLayouts) {
2290 if (layout.binding == 64 &&
2292 expected_layout =
true;
2295 EXPECT_TRUE(expected_layout);
2301 testing::MockRenderPass mock_pass(GetContext(), target);
2306 return geometry->GetPositionBuffer(GetContentContext(), {}, mock_pass);
2312 get_result(flutter::DlPath::MakeRect(
Rect::MakeLTRB(0, 0, 100, 100)));
2332 testing::MockRenderPass mock_pass(GetContext(), target);
2339 for (
auto sweep = 0; sweep < 360; sweep += 12) {
2344 geometry->GetPositionBuffer(GetContentContext(), {}, mock_pass);
2347 <<
"start: " <<
start <<
" sweep: " << sweep;
2356 for (
auto sweep = 0; sweep < 360; sweep += 12) {
2361 geometry->GetPositionBuffer(GetContentContext(), {}, mock_pass);
2363 if (sweep < 348.6) {
2365 <<
"start: " <<
start <<
" sweep: " << sweep;
2368 <<
"start: " <<
start <<
" sweep: " << sweep;
2378 for (
auto sweep = 0; sweep < 360; sweep += 12) {
2383 geometry->GetPositionBuffer(GetContentContext(), {}, mock_pass);
2385 if (sweep < 300.0) {
2387 <<
"start: " <<
start <<
" sweep: " << sweep;
2390 <<
"start: " <<
start <<
" sweep: " << sweep;
2400 for (
auto sweep = 0; sweep < 360; sweep += 12) {
2405 geometry->GetPositionBuffer(GetContentContext(), {}, mock_pass);
2407 if (sweep < 347.4) {
2409 <<
"start: " <<
start <<
" sweep: " << sweep;
2412 <<
"start: " <<
start <<
" sweep: " << sweep;
2422 for (
auto sweep = 0; sweep < 360; sweep += 12) {
2427 geometry->GetPositionBuffer(GetContentContext(), {}, mock_pass);
2429 if (sweep < 270.1) {
2431 <<
"start: " <<
start <<
" sweep: " << sweep;
2434 <<
"start: " <<
start <<
" sweep: " << sweep;
2443 GTEST_SKIP() <<
"Validation is only fatal on Vulkan backend.";
2448 GetContentContext().GetBlendColorBurnPipeline({
2450 .has_depth_stencil_attachments =
false,
2458 EXPECT_TRUE(path.GetBounds().IsEmpty());
2464 GetContentContext().GetRenderTargetCache()->CreateOffscreen(*GetContext(),
2466 testing::MockRenderPass
render_pass(GetContext(), target);
2467 auto position_result =
2468 geom->GetPositionBuffer(GetContentContext(), entity,
render_pass);
2470 EXPECT_EQ(position_result.vertex_buffer.vertex_count, 0u);
2478 EXPECT_TRUE(path.GetBounds().IsEmpty());
2481 auto contents = std::make_shared<SolidColorContents>(geom.get());
2488 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
2494 static float alpha = 10;
2495 static float beta = 10;
2496 static float radius = 40;
2497 static int degree = 4;
2500 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
2501 ImGui::SliderFloat(
"Alpha", &alpha, 0, 100);
2502 ImGui::SliderFloat(
"Beta", &beta, 0, 100);
2503 ImGui::SliderInt(
"Degreee", °ree, 1, 20);
2504 ImGui::SliderFloat(
"Radius", &radius, 0, 400);
2505 ImGui::ColorEdit4(
"Color",
reinterpret_cast<float*
>(&color));
2508 std::unique_ptr<SuperellipseGeometry> geom =
2509 std::make_unique<SuperellipseGeometry>(
Point{400, 400}, radius, degree,
2511 auto contents = std::make_shared<SolidColorContents>(geom.get());
2512 contents->SetColor(color);
2520 ASSERT_TRUE(OpenPlaygroundHere(callback));
2526 static int style_index = 0;
2527 static Point center = {830, 830};
2528 static Point size = {600, 600};
2529 static bool horizontal_symmetry =
true;
2530 static bool vertical_symmetry =
true;
2531 static bool corner_symmetry =
true;
2533 const char* style_options[] = {
"Fill",
"Stroke"};
2537 static std::array<float, 2> radius_tl = {200};
2538 static std::array<float, 2> radius_tr;
2539 static std::array<float, 2> radius_bl;
2540 static std::array<float, 2> radius_br;
2542 auto AddRadiusControl = [](std::array<float, 2>& radii,
const char* tb_name,
2543 const char* lr_name) {
2544 std::string name =
"Radius";
2545 if (!horizontal_symmetry || !vertical_symmetry) {
2548 if (!vertical_symmetry) {
2549 name = name +
" " + tb_name;
2551 if (!horizontal_symmetry) {
2552 name = name +
" " + lr_name;
2554 if (corner_symmetry) {
2555 ImGui::SliderFloat(name.c_str(), radii.data(), 0, 1000);
2557 ImGui::SliderFloat2(name.c_str(), radii.data(), 0, 1000);
2561 if (corner_symmetry) {
2562 radius_tl[1] = radius_tl[0];
2563 radius_tr[1] = radius_tr[0];
2564 radius_bl[1] = radius_bl[0];
2565 radius_br[1] = radius_br[0];
2568 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
2570 ImGui::Combo(
"Style", &style_index, style_options,
2571 sizeof(style_options) /
sizeof(
char*));
2572 ImGui::SliderFloat2(
"Center", ¢er.
x, 0, 1000);
2573 ImGui::SliderFloat2(
"Size", &size.
x, 0, 1000);
2574 ImGui::Checkbox(
"Symmetry: Horizontal", &horizontal_symmetry);
2575 ImGui::Checkbox(
"Symmetry: Vertical", &vertical_symmetry);
2576 ImGui::Checkbox(
"Symmetry: Corners", &corner_symmetry);
2577 AddRadiusControl(radius_tl,
"Top",
"Left");
2578 if (!horizontal_symmetry) {
2579 AddRadiusControl(radius_tr,
"Top",
"Right");
2581 radius_tr = radius_tl;
2583 if (!vertical_symmetry) {
2584 AddRadiusControl(radius_bl,
"Bottom",
"Left");
2586 radius_bl = radius_tl;
2588 if (!horizontal_symmetry && !vertical_symmetry) {
2589 AddRadiusControl(radius_br,
"Bottom",
"Right");
2591 if (horizontal_symmetry) {
2592 radius_br = radius_bl;
2594 radius_br = radius_tr;
2602 .
top_left = {radius_tl[0], radius_tl[1]},
2603 .top_right = {radius_tr[0], radius_tr[1]},
2604 .bottom_left = {radius_bl[0], radius_bl[1]},
2605 .bottom_right = {radius_br[0], radius_br[1]},
2612 std::unique_ptr<Geometry> geom;
2613 if (style_index == 0) {
2614 geom = std::make_unique<RoundSuperellipseGeometry>(
2617 path = flutter::DlPath::MakeRoundSuperellipse(rse);
2621 auto contents = std::make_shared<SolidColorContents>(geom.get());
2630 ASSERT_TRUE(OpenPlaygroundHere(callback));
2638 constexpr
float corner_radius = 100.0;
2641 static float logarithm_of_ratio = 1.5;
2643 float ratio = std::exp(logarithm_of_ratio);
2645 float rect_size = corner_radius * ratio;
2647 constexpr
float screen_canvas_padding = 200.0f;
2648 constexpr
float screen_canvas_size = 1000.0f;
2651 float scale = screen_canvas_size / 2 / corner_radius;
2653 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
2655 ImGui::SliderFloat(
"log(Ratio)", &logarithm_of_ratio, 1.0, 8.0);
2656 ImGui::LabelText(
"Ratio",
"%.2g",
static_cast<double>(ratio));
2657 ImGui::Text(
" where Ratio = RectSize / CornerRadius");
2661 auto top_right =
Vector2(screen_canvas_size * 1.3f, screen_canvas_padding);
2665 bool success =
true;
2668 std::make_unique<RoundSuperellipseGeometry>(rect, corner_radius);
2671 auto contents = std::make_shared<SolidColorContents>(fill_geom.get());
2682 auto path = flutter::DlPath::MakeRoundSuperellipse(
2686 auto contents = std::make_shared<SolidColorContents>(stroke_geom.get());
2697 auto screen_top_right =
2700 for (
int i = -1; i < 100; i++) {
2701 float screen_offset_y =
static_cast<float>(i) * 20.0f;
2704 label =
"Ruler: (in portion of rect size)";
2705 }
else if (i == 0) {
2708 float portion_of_rect =
2709 screen_offset_y * GetContentScale().y / scale / rect_size;
2710 label = std::format(
"- {:.2g}", portion_of_rect);
2712 ImGui::GetBackgroundDrawList()->AddText(
2719 {screen_top_right.x - 500,
2720 screen_top_right.y + screen_offset_y -
font_size / 2},
2721 IM_COL32_WHITE, label.c_str());
2726 ASSERT_TRUE(OpenPlaygroundHere(callback));
2740 auto cmd_buffer = content_context.
GetContext()->CreateCommandBuffer();
2743 content_context.
GetContext()->GetResourceAllocator());
2746 *content_context.
GetContext(), {500, 500}, 1);
2747 auto pass = cmd_buffer->CreateRenderPass(render_target);
2750 geom->GetPositionBuffer(content_context, entity, *pass);
2753 Point* written_data =
reinterpret_cast<Point*
>(
2757 std::vector<Point> expected = {
Point(300.0, 200.0),
Point(300.0, 300.0),
2760 for (
size_t i = 0; i < expected.size(); i++) {
2761 const Point& point = written_data[i];
2762 EXPECT_NEAR(point.
x, expected[i].x, 0.1);
2763 EXPECT_NEAR(point.
y, expected[i].y, 0.1);
2778 auto cmd_buffer = content_context.
GetContext()->CreateCommandBuffer();
2781 content_context.
GetContext()->GetResourceAllocator());
2784 *content_context.
GetContext(), {500, 500}, 1);
2785 auto pass = cmd_buffer->CreateRenderPass(render_target);
2788 geom->GetPositionBuffer(content_context, entity, *pass);
2791 Point* written_data =
reinterpret_cast<Point*
>(
2795 std::vector<Point> expected_head = {
Point(250.0, 200.0),
Point(299.9, 200.0),
2798 for (
size_t i = 0; i < expected_head.size(); i++) {
2799 const Point& point = written_data[i];
2800 EXPECT_NEAR(point.
x, expected_head[i].x, 0.1);
2801 EXPECT_NEAR(point.
y, expected_head[i].y, 0.1);
2809 auto result = contents.ApplyColorFilter([](
const Color& color) {
2812 ASSERT_TRUE(result);
2814 Color(0.424452, 0.828743, 0.79105, 0.9375));
2817 #define APPLY_COLOR_FILTER_GRADIENT_TEST(name) \
2818 TEST_P(EntityTest, name##GradientApplyColorFilter) { \
2819 auto geom = Geometry::MakeCover(); \
2820 auto contents = name##GradientContents(geom.get()); \
2821 contents.SetColors({Color::CornflowerBlue().WithAlpha(0.75)}); \
2822 auto result = contents.ApplyColorFilter([](const Color& color) { \
2823 return color.Blend(Color::LimeGreen().WithAlpha(0.75), \
2824 BlendMode::kScreen); \
2826 ASSERT_TRUE(result); \
2828 std::vector<Color> expected = {Color(0.433247, 0.879523, 0.825324, 0.75)}; \
2829 ASSERT_COLORS_NEAR(contents.GetColors(), expected); \
2838 flutter::DlPathBuilder builder;
2839 for (
int i = 0; i < 10000; i++) {
2840 builder.LineTo(
Point(i, i));
2848 auto cmd_buffer = content_context.GetContext()->CreateCommandBuffer();
2851 content_context.GetContext()->GetResourceAllocator());
2854 *content_context.GetContext(), {10, 10}, 1);
2855 auto pass = cmd_buffer->CreateRenderPass(render_target);
2858 geom->GetPositionBuffer(content_context, entity, *pass);
2864 Point* written_data =
reinterpret_cast<Point*
>(
2868 std::vector<Point> expected = {
2869 Point(2043.46, 2050.54),
2870 Point(2050.54, 2043.46),
2871 Point(2044.46, 2051.54),
2872 Point(2051.54, 2044.46),
2873 Point(2045.46, 2052.54)
2877 EXPECT_NEAR(point.
x, expected[0].x, 0.1);
2878 EXPECT_NEAR(point.
y, expected[0].y, 0.1);
2881 EXPECT_NEAR(point.
x, expected[1].x, 0.1);
2882 EXPECT_NEAR(point.
y, expected[1].y, 0.1);
2885 EXPECT_NEAR(point.
x, expected[2].x, 0.1);
2886 EXPECT_NEAR(point.
y, expected[2].y, 0.1);
2889 EXPECT_NEAR(point.
x, expected[3].x, 0.1);
2890 EXPECT_NEAR(point.
y, expected[3].y, 0.1);
2893 EXPECT_NEAR(point.
x, expected[4].x, 0.1);
2894 EXPECT_NEAR(point.
y, expected[4].y, 0.1);
2902 bool SetLabel(std::string_view label)
override {
return true; }
2911 return const_cast<uint8_t*
>(storage_.data());
2914 void Flush(std::optional<Range> range)
const override {
2915 flush_called_ =
true;
2921 std::vector<uint8_t> storage_;
2922 mutable bool flush_called_ =
false;
2928 return ISize(1024, 1024);
2933 return std::make_shared<FlushTestDeviceBuffer>(desc);
2937 bool threadsafe)
override {
2945 const std::shared_ptr<Context>&
context,
2946 const std::shared_ptr<TypographerContext>& typographer_context,
2947 const std::shared_ptr<Allocator>& allocator)
2950 allocator,
context->GetIdleWaiter(),
2951 context->GetCapabilities()->GetMinimumUniformAlignment()));
2953 allocator,
context->GetIdleWaiter(),
2954 context->GetCapabilities()->GetMinimumUniformAlignment()));
2960 testing::MockRenderPass mock_pass(GetContext(), target);
2962 auto content_context = std::make_shared<FlushTestContentContext>(
2963 GetContext(), GetTypographerContext(),
2964 std::make_shared<FlushTestAllocator>());
2967 auto result = geometry->GetPositionBuffer(*content_context, {}, mock_pass);
2970 result.vertex_buffer.vertex_buffer.GetBuffer());
2971 EXPECT_TRUE(device_buffer->flush_called());
An object that allocates device memory.
static std::shared_ptr< ColorFilterContents > MakeColorMatrix(FilterInput::Ref input, const ColorMatrix &color_matrix)
static std::shared_ptr< ColorFilterContents > MakeSrgbToLinearFilter(FilterInput::Ref input)
static std::shared_ptr< ColorFilterContents > MakeLinearToSrgbFilter(FilterInput::Ref input)
static std::shared_ptr< ColorFilterContents > MakeBlend(BlendMode blend_mode, FilterInput::Vector inputs, std::optional< Color > foreground_color=std::nullopt)
the [inputs] are expected to be in the order of dst, src.
void SetColors(std::vector< Color > colors)
void SetTransientsDataBuffer(std::shared_ptr< HostBuffer > host_buffer)
PipelineRef GetMorphologyFilterPipeline(ContentContextOptions opts) const
PipelineRef GetGlyphAtlasPipeline(ContentContextOptions opts) const
const std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
void SetTransientsIndexesBuffer(std::shared_ptr< HostBuffer > host_buffer)
std::shared_ptr< Context > GetContext() const
virtual bool IsOpaque(const Matrix &transform) const
Whether this Contents only emits opaque source colors from the fragment stage. This value does not ac...
To do anything rendering related with Impeller, you need a context.
static BufferView AsBufferView(std::shared_ptr< DeviceBuffer > buffer)
Create a buffer view of this entire buffer.
virtual uint8_t * OnGetContents() const =0
void SetTransform(const Matrix &transform)
Set the global transform matrix for this Entity.
std::optional< Rect > GetCoverage() const
BlendMode GetBlendMode() const
void SetContents(std::shared_ptr< Contents > contents)
void SetBlendMode(BlendMode blend_mode)
bool Render(const ContentContext &renderer, RenderPass &parent_pass) const
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
static constexpr BlendMode kLastPipelineBlendMode
static std::shared_ptr< FilterContents > MakeGaussianBlur(const FilterInput::Ref &input, Sigma sigma_x, Sigma sigma_y, Entity::TileMode tile_mode=Entity::TileMode::kDecal, std::optional< Rect > bounds=std::nullopt, BlurStyle mask_blur_style=BlurStyle::kNormal, const Geometry *mask_geometry=nullptr)
@ kNormal
Blurred inside and outside.
@ kOuter
Nothing inside, blurred outside.
@ kInner
Blurred inside, nothing outside.
@ kSolid
Solid inside, blurred outside.
static std::shared_ptr< FilterContents > MakeMorphology(FilterInput::Ref input, Radius radius_x, Radius radius_y, MorphType morph_type)
static std::shared_ptr< FilterContents > MakeBorderMaskBlur(FilterInput::Ref input, Sigma sigma_x, Sigma sigma_y, BlurStyle blur_style=BlurStyle::kNormal)
static std::shared_ptr< FilterContents > MakeYUVToRGBFilter(std::shared_ptr< Texture > y_texture, std::shared_ptr< Texture > uv_texture, YUVColorSpace yuv_color_space)
static std::unique_ptr< Geometry > MakeFillPath(const flutter::DlPath &path, std::optional< Rect > inner_rect=std::nullopt)
static std::unique_ptr< Geometry > MakeRect(const Rect &rect)
static std::unique_ptr< Geometry > MakeStrokePath(const flutter::DlPath &path, const StrokeParameters &stroke={})
static std::unique_ptr< Geometry > MakeRoundSuperellipse(const Rect &rect, Scalar corner_radius)
static std::unique_ptr< Geometry > MakeCover()
static std::unique_ptr< Geometry > MakeStrokedArc(const Rect &oval_bounds, Degrees start, Degrees sweep, const StrokeParameters &stroke)
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator, const std::shared_ptr< const IdleWaiter > &idle_waiter, size_t minimum_uniform_alignment)
void SetTileMode(Entity::TileMode tile_mode)
void SetColors(std::vector< Color > colors)
bool IsOpaque(const Matrix &transform) const override
Whether this Contents only emits opaque source colors from the fragment stage. This value does not ac...
A geometry class specialized for Canvas::DrawPoints.
std::optional< Rect > GetCoverage(const Matrix &transform) const override
The coverage rectangle of this geometry, transformed by the transform argument.
bool IsOpaque(const Matrix &transform) const override
Whether this Contents only emits opaque source colors from the fragment stage. This value does not ac...
void SetTileMode(Entity::TileMode tile_mode)
void SetColors(std::vector< Color > colors)
Render passes encode render commands directed as one specific render target into an underlying comman...
VertexShader_ VertexShader
FragmentShader_ FragmentShader
a wrapper around the impeller [Allocator] instance that can be used to provide caching of allocated r...
virtual RenderTarget CreateOffscreen(const Context &context, ISize size, int mip_count, std::string_view label="Offscreen", RenderTarget::AttachmentConfig color_attachment_config=RenderTarget::kDefaultColorAttachmentConfig, std::optional< RenderTarget::AttachmentConfig > stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &existing_color_texture=nullptr, const std::shared_ptr< Texture > &existing_depth_stencil_texture=nullptr, std::optional< PixelFormat > target_pixel_format=std::nullopt)
static BufferView EmplaceUniform(const uint8_t *source_data, HostBuffer &host_buffer, const RuntimeUniformDescription &uniform)
bool IsOpaque(const Matrix &transform) const override
Whether this Contents only emits opaque source colors from the fragment stage. This value does not ac...
void SetColor(Color color)
A Geometry that produces fillable vertices representing the stroked outline of a |DlPath| object usin...
void SetTileMode(Entity::TileMode tile_mode)
bool IsOpaque(const Matrix &transform) const override
Whether this Contents only emits opaque source colors from the fragment stage. This value does not ac...
void SetColors(std::vector< Color > colors)
static Rational RoundScaledFontSize(Scalar scale)
static std::shared_ptr< TextureContents > MakeRect(Rect destination)
bool IsOpaque(const Matrix &transform) const override
Whether this Contents only emits opaque source colors from the fragment stage. This value does not ac...
void SetTexture(std::shared_ptr< Texture > texture)
static std::unique_ptr< UberSDFContents > Make(const UberSDFParameters ¶ms, std::unique_ptr< Geometry > geometry)
VertexBuffer CreateVertexBuffer(HostBuffer &data_host_buffer, HostBuffer &indexes_host_buffer) const
VertexBufferBuilder & AddVertices(std::initializer_list< VertexType_ > vertices)
std::shared_ptr< Texture > OnCreateTexture(const TextureDescriptor &desc, bool threadsafe) override
std::shared_ptr< DeviceBuffer > OnCreateBuffer(const DeviceBufferDescriptor &desc) override
ISize GetMaxTextureSizeSupported() const override
FlushTestContentContext(const std::shared_ptr< Context > &context, const std::shared_ptr< TypographerContext > &typographer_context, const std::shared_ptr< Allocator > &allocator)
bool OnCopyHostBuffer(const uint8_t *source, Range source_range, size_t offset)
void Flush(std::optional< Range > range) const override
bool SetLabel(std::string_view label, Range range) override
bool SetLabel(std::string_view label) override
uint8_t * OnGetContents() const override
FlushTestDeviceBuffer(const DeviceBufferDescriptor &desc)
bool flush_called() const
Vector2 blur_radius
Blur radius in source pixels based on scaled_sigma.
Vector2 padding
The halo padding in source space.
#define ASSERT_RECT_NEAR(a, b)
#define ASSERT_COLOR_NEAR(a, b)
static std::optional< RuntimeStageBackend > GetRuntimeStageBackend(TargetPlatform target_platform)
EntityPlayground EntityTest
TEST(AllocationSizeTest, CanCreateTypedAllocations)
TEST_P(AiksTest, DrawAtlasNoColor)
APPLY_COLOR_FILTER_GRADIENT_TEST(Linear)
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
static Vector3 RGBToYUV(Vector3 rgb, YUVColorSpace yuv_color_space)
static std::vector< std::shared_ptr< Texture > > CreateTestYUVTextures(Context *context, YUVColorSpace yuv_color_space)
Join
An enum that describes ways to join two segments of a path.
@ kPoint
Draws a point at each input vertex.
Point DrawPlaygroundPoint(PlaygroundPoint &point)
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
constexpr float kEhCloseEnough
Cap
An enum that describes ways to decorate the end of a path contour.
LinePipeline::FragmentShader FS
LinePipeline::VertexShader VS
void MoveTo(PathBuilder *builder, Scalar x, Scalar y)
static constexpr size_t kPointArenaSize
The size of the point arena buffer stored on the tessellator.
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
ContentContextOptions OptionsFromPass(const RenderPass &pass)
void Close(PathBuilder *builder)
std::shared_ptr< ContextGLES > context
std::shared_ptr< RenderPass > render_pass
const DeviceBuffer * GetBuffer() const
static constexpr Color LimeGreen()
static constexpr Color MintCream()
static constexpr Color DeepPink()
static constexpr Color Black()
static constexpr Color CornflowerBlue()
static constexpr Color White()
constexpr Color WithAlpha(Scalar new_alpha) const
static constexpr Color WhiteTransparent()
static constexpr Color Coral()
static constexpr Color Red()
constexpr Color Premultiply() const
Color Blend(Color source, BlendMode blend_mode) const
Blends an unpremultiplied destination color into a given unpremultiplied source color to form a new u...
static constexpr Color Blue()
static constexpr Color Green()
PrimitiveType primitive_type
bool has_depth_stencil_attachments
constexpr uint64_t ToKey() const
@ kNormal
The geometry has no overlapping triangles.
VertexBuffer vertex_buffer
A 4x4 matrix using column-major storage.
static constexpr Matrix MakeTranslation(const Vector3 &t)
constexpr bool IsIdentity() const
static Matrix MakeRotationY(Radians r)
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
static Matrix MakeRotationZ(Radians r)
static constexpr Matrix MakeScale(const Vector3 &s)
static Matrix MakeRotationX(Radians r)
For convolution filters, the "radius" is the size of the convolution kernel to use on the local space...
static RoundSuperellipse MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
static RoundSuperellipse MakeRectRadius(const Rect &rect, Scalar radius)
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
A structure to store all of the parameters related to stroking a path or basic geometry object.
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr static TRect MakeSize(const TSize< U > &size)
constexpr static TRect MakeEllipseBounds(const TPoint< Type > ¢er, const TSize< Type > &radii)
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
static UberSDFParameters MakeCircle(Color color, const Point ¢er, Scalar radius, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for a circle.
static UberSDFParameters MakeRect(Color color, const Rect &rect, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for a rectangle.
std::vector< Point > points