diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 9c6d91a904c7c..6642e72f8d919 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -123,7 +123,9 @@ ../../../flutter/impeller/.clang-format ../../../flutter/impeller/.gitignore ../../../flutter/impeller/README.md +../../../flutter/impeller/aiks/aiks_gradient_unittests.cc ../../../flutter/impeller/aiks/aiks_unittests.cc +../../../flutter/impeller/aiks/aiks_unittests.h ../../../flutter/impeller/aiks/canvas_recorder_unittests.cc ../../../flutter/impeller/aiks/canvas_unittests.cc ../../../flutter/impeller/aiks/testing diff --git a/impeller/aiks/BUILD.gn b/impeller/aiks/BUILD.gn index 89113c7dabdaf..845a2bde8eb71 100644 --- a/impeller/aiks/BUILD.gn +++ b/impeller/aiks/BUILD.gn @@ -67,28 +67,60 @@ impeller_component("aiks_playground") { ] } -impeller_component("aiks_unittests") { +impeller_component("context_spy") { testonly = true sources = [ - "aiks_unittests.cc", - "canvas_recorder_unittests.cc", - "canvas_unittests.cc", "testing/context_mock.h", "testing/context_spy.cc", "testing/context_spy.h", - "trace_serializer_unittests.cc", ] deps = [ - ":aiks", - ":aiks_playground", - "//flutter/impeller/geometry:geometry_asserts", - "//flutter/impeller/golden_tests:golden_playground_test", - "//flutter/impeller/playground:playground_test", - "//flutter/impeller/scene", - "//flutter/impeller/typographer/backends/stb:typographer_stb_backend", + "//flutter/impeller/renderer", "//flutter/testing:testing_lib", - "//flutter/third_party/txt", + ] +} + +template("aiks_unittests_component") { + target_name = invoker.target_name + predefined_sources = [ + "aiks_gradient_unittests.cc", + "aiks_unittests.cc", + "aiks_unittests.h", + ] + additional_sources = [] + if (defined(invoker.sources)) { + additional_sources = invoker.sources + } + impeller_component(target_name) { + testonly = true + if (defined(invoker.defines)) { + defines = invoker.defines + } + sources = predefined_sources + additional_sources + deps = [ + ":aiks", + ":aiks_playground", + ":context_spy", + "//flutter/impeller/geometry:geometry_asserts", + "//flutter/impeller/golden_tests:golden_playground_test", + "//flutter/impeller/playground:playground_test", + "//flutter/impeller/scene", + "//flutter/impeller/typographer/backends/stb:typographer_stb_backend", + "//flutter/testing:testing_lib", + "//flutter/third_party/txt", + ] + if (defined(invoker.public_configs)) { + public_configs = invoker.public_configs + } + } +} + +aiks_unittests_component("aiks_unittests") { + sources = [ + "canvas_recorder_unittests.cc", + "canvas_unittests.cc", + "trace_serializer_unittests.cc", ] if (!impeller_trace_canvas) { @@ -97,31 +129,11 @@ impeller_component("aiks_unittests") { } } -impeller_component("aiks_unittests_golden") { - testonly = true - +aiks_unittests_component("aiks_unittests_golden") { defines = [ "IMPELLER_GOLDEN_TESTS", "IMPELLER_ENABLE_VALIDATION=1", ] - - sources = [ - "aiks_unittests.cc", - "testing/context_mock.h", - "testing/context_spy.cc", - "testing/context_spy.h", - ] - deps = [ - ":aiks", - ":aiks_playground", - "//flutter/impeller/geometry:geometry_asserts", - "//flutter/impeller/golden_tests:golden_playground_test", - "//flutter/impeller/playground:playground_test", - "//flutter/impeller/scene", - "//flutter/impeller/typographer/backends/stb:typographer_stb_backend", - "//flutter/testing:testing_lib", - "//flutter/third_party/txt", - ] } executable("canvas_benchmarks") { diff --git a/impeller/aiks/aiks_gradient_unittests.cc b/impeller/aiks/aiks_gradient_unittests.cc new file mode 100644 index 0000000000000..bfecaac904e63 --- /dev/null +++ b/impeller/aiks/aiks_gradient_unittests.cc @@ -0,0 +1,729 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/impeller/aiks/aiks_unittests.h" + +#include "impeller/aiks/canvas.h" +#include "impeller/entity/contents/conical_gradient_contents.h" +#include "impeller/entity/contents/filters/inputs/filter_input.h" +#include "impeller/entity/contents/linear_gradient_contents.h" +#include "impeller/entity/contents/radial_gradient_contents.h" +#include "impeller/entity/contents/solid_color_contents.h" +#include "impeller/entity/contents/sweep_gradient_contents.h" +#include "impeller/geometry/geometry_asserts.h" +#include "impeller/geometry/path_builder.h" +#include "impeller/playground/widgets.h" +#include "third_party/imgui/imgui.h" +#include "txt/platform.h" + +//////////////////////////////////////////////////////////////////////////////// +// This is for tests of Canvas that are interested the results of rendering +// gradients. +//////////////////////////////////////////////////////////////////////////////// + +namespace impeller { +namespace testing { + +namespace { +void CanRenderLinearGradient(AiksTest* aiks_test, Entity::TileMode tile_mode) { + Canvas canvas; + canvas.Scale(aiks_test->GetContentScale()); + Paint paint; + canvas.Translate({100.0f, 0, 0}); + + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 0.0}}; + std::vector stops = {0.0, 1.0}; + + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {}); + + paint.color = Color(1.0, 1.0, 1.0, 1.0); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} +} // namespace + +TEST_P(AiksTest, CanRenderLinearGradientClamp) { + CanRenderLinearGradient(this, Entity::TileMode::kClamp); +} +TEST_P(AiksTest, CanRenderLinearGradientRepeat) { + CanRenderLinearGradient(this, Entity::TileMode::kRepeat); +} +TEST_P(AiksTest, CanRenderLinearGradientMirror) { + CanRenderLinearGradient(this, Entity::TileMode::kMirror); +} +TEST_P(AiksTest, CanRenderLinearGradientDecal) { + CanRenderLinearGradient(this, Entity::TileMode::kDecal); +} + +TEST_P(AiksTest, CanRenderLinearGradientDecalWithColorFilter) { + Canvas canvas; + canvas.Scale(GetContentScale()); + Paint paint; + canvas.Translate({100.0f, 0, 0}); + + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 0.0}}; + std::vector stops = {0.0, 1.0}; + + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {200, 200}, std::move(colors), std::move(stops), + Entity::TileMode::kDecal, {}); + // Overlay the gradient with 25% green. This should appear as the entire + // rectangle being drawn with 25% green, including the border area outside the + // decal gradient. + paint.color_filter = ColorFilter::MakeBlend(BlendMode::kSourceOver, + Color::Green().WithAlpha(0.25)); + + paint.color = Color(1.0, 1.0, 1.0, 1.0); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +static void CanRenderLinearGradientWithDithering(AiksTest* aiks_test, + bool use_dithering) { + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + + // 0xffcccccc --> 0xff333333, taken from + // https://github.com/flutter/flutter/issues/118073#issue-1521699748 + std::vector colors = {Color{0.8, 0.8, 0.8, 1.0}, + Color{0.2, 0.2, 0.2, 1.0}}; + std::vector stops = {0.0, 1.0}; + + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {800, 500}, std::move(colors), std::move(stops), + Entity::TileMode::kClamp, {}); + paint.dither = use_dithering; + canvas.DrawRect(Rect::MakeXYWH(0, 0, 800, 500), paint); + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, CanRenderLinearGradientWithDitheringDisabled) { + CanRenderLinearGradientWithDithering(this, false); +} + +TEST_P(AiksTest, CanRenderLinearGradientWithDitheringEnabled) { + CanRenderLinearGradientWithDithering(this, true); +} // namespace + +static void CanRenderRadialGradientWithDithering(AiksTest* aiks_test, + bool use_dithering) { + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + + // #FFF -> #000 + std::vector colors = {Color{1.0, 1.0, 1.0, 1.0}, + Color{0.0, 0.0, 0.0, 1.0}}; + std::vector stops = {0.0, 1.0}; + + paint.color_source = ColorSource::MakeRadialGradient( + {600, 600}, 600, std::move(colors), std::move(stops), + Entity::TileMode::kClamp, {}); + paint.dither = use_dithering; + canvas.DrawRect(Rect::MakeXYWH(0, 0, 1200, 1200), paint); + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, CanRenderRadialGradientWithDitheringDisabled) { + CanRenderRadialGradientWithDithering(this, false); +} + +TEST_P(AiksTest, CanRenderRadialGradientWithDitheringEnabled) { + CanRenderRadialGradientWithDithering(this, true); +} + +static void CanRenderSweepGradientWithDithering(AiksTest* aiks_test, + bool use_dithering) { + Canvas canvas; + canvas.Scale(aiks_test->GetContentScale()); + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + + // #FFF -> #000 + std::vector colors = {Color{1.0, 1.0, 1.0, 1.0}, + Color{0.0, 0.0, 0.0, 1.0}}; + std::vector stops = {0.0, 1.0}; + + paint.color_source = ColorSource::MakeSweepGradient( + {100, 100}, Degrees(45), Degrees(135), std::move(colors), + std::move(stops), Entity::TileMode::kMirror, {}); + paint.dither = use_dithering; + + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, CanRenderSweepGradientWithDitheringDisabled) { + CanRenderSweepGradientWithDithering(this, false); +} + +TEST_P(AiksTest, CanRenderSweepGradientWithDitheringEnabled) { + CanRenderSweepGradientWithDithering(this, true); +} + +static void CanRenderConicalGradientWithDithering(AiksTest* aiks_test, + bool use_dithering) { + Canvas canvas; + canvas.Scale(aiks_test->GetContentScale()); + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + + // #FFF -> #000 + std::vector colors = {Color{1.0, 1.0, 1.0, 1.0}, + Color{0.0, 0.0, 0.0, 1.0}}; + std::vector stops = {0.0, 1.0}; + + paint.color_source = ColorSource::MakeConicalGradient( + {100, 100}, 100, std::move(colors), std::move(stops), {0, 1}, 0, + Entity::TileMode::kMirror, {}); + paint.dither = use_dithering; + + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, CanRenderConicalGradientWithDitheringDisabled) { + CanRenderConicalGradientWithDithering(this, false); +} + +TEST_P(AiksTest, CanRenderConicalGradientWithDitheringEnabled) { + CanRenderConicalGradientWithDithering(this, true); +} + +namespace { +void CanRenderLinearGradientWithOverlappingStops(AiksTest* aiks_test, + Entity::TileMode tile_mode) { + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + + std::vector colors = { + Color{0.9568, 0.2627, 0.2118, 1.0}, Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}, Color{0.1294, 0.5882, 0.9529, 1.0}}; + std::vector stops = {0.0, 0.5, 0.5, 1.0}; + + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {500, 500}, std::move(colors), std::move(stops), tile_mode, {}); + + paint.color = Color(1.0, 1.0, 1.0, 1.0); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 500, 500), paint); + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} +} // namespace + +// Only clamp is necessary. All tile modes are the same output. +TEST_P(AiksTest, CanRenderLinearGradientWithOverlappingStopsClamp) { + CanRenderLinearGradientWithOverlappingStops(this, Entity::TileMode::kClamp); +} + +namespace { +void CanRenderLinearGradientManyColors(AiksTest* aiks_test, + Entity::TileMode tile_mode) { + Canvas canvas; + canvas.Scale(aiks_test->GetContentScale()); + Paint paint; + canvas.Translate({100, 100, 0}); + + std::vector colors = { + Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}, + Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}, + Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}, + Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}, + Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}, + Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}, + Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}}; + std::vector stops = { + 0.0, + (1.0 / 6.0) * 1, + (1.0 / 6.0) * 2, + (1.0 / 6.0) * 3, + (1.0 / 6.0) * 4, + (1.0 / 6.0) * 5, + 1.0, + }; + + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {}); + + paint.color = Color(1.0, 1.0, 1.0, 1.0); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + canvas.Restore(); + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} +} // namespace + +TEST_P(AiksTest, CanRenderLinearGradientManyColorsClamp) { + CanRenderLinearGradientManyColors(this, Entity::TileMode::kClamp); +} +TEST_P(AiksTest, CanRenderLinearGradientManyColorsRepeat) { + CanRenderLinearGradientManyColors(this, Entity::TileMode::kRepeat); +} +TEST_P(AiksTest, CanRenderLinearGradientManyColorsMirror) { + CanRenderLinearGradientManyColors(this, Entity::TileMode::kMirror); +} +TEST_P(AiksTest, CanRenderLinearGradientManyColorsDecal) { + CanRenderLinearGradientManyColors(this, Entity::TileMode::kDecal); +} + +namespace { +void CanRenderLinearGradientWayManyColors(AiksTest* aiks_test, + Entity::TileMode tile_mode) { + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + auto color = Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}; + std::vector colors; + std::vector stops; + auto current_stop = 0.0; + for (int i = 0; i < 2000; i++) { + colors.push_back(color); + stops.push_back(current_stop); + current_stop += 1 / 2000.0; + } + stops[2000 - 1] = 1.0; + + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {}); + + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} +} // namespace + +// Only test clamp on purpose since they all look the same. +TEST_P(AiksTest, CanRenderLinearGradientWayManyColorsClamp) { + CanRenderLinearGradientWayManyColors(this, Entity::TileMode::kClamp); +} + +TEST_P(AiksTest, CanRenderLinearGradientManyColorsUnevenStops) { + auto callback = [&](AiksContext& renderer) -> std::optional { + const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; + const Entity::TileMode tile_modes[] = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + + static int selected_tile_mode = 0; + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, + sizeof(tile_mode_names) / sizeof(char*)); + static Matrix matrix = { + 1, 0, 0, 0, // + 0, 1, 0, 0, // + 0, 0, 1, 0, // + 0, 0, 0, 1 // + }; + std::string label = "##1"; + for (int i = 0; i < 4; i++) { + ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.vec[i]), + 4, NULL, NULL, "%.2f", 0); + label[2]++; + } + ImGui::End(); + + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + auto tile_mode = tile_modes[selected_tile_mode]; + + std::vector colors = { + Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}, + Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}, + Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}, + Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}, + Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}, + Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}, + Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}}; + std::vector stops = { + 0.0, 2.0 / 62.0, 4.0 / 62.0, 8.0 / 62.0, 16.0 / 62.0, 32.0 / 62.0, 1.0, + }; + + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {}); + + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + return canvas.EndRecordingAsPicture(); + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + +TEST_P(AiksTest, CanRenderLinearGradientMaskBlur) { + Canvas canvas; + + Paint paint = { + .color = Color::White(), + .color_source = ColorSource::MakeLinearGradient( + {200, 200}, {400, 400}, + {Color::Red(), Color::White(), Color::Red(), Color::White(), + Color::Red(), Color::White(), Color::Red(), Color::White(), + Color::Red(), Color::White(), Color::Red()}, + {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}, + Entity::TileMode::kClamp, {}), + .mask_blur_descriptor = + Paint::MaskBlurDescriptor{ + .style = FilterContents::BlurStyle::kNormal, + .sigma = Sigma(20), + }, + }; + + canvas.DrawCircle({300, 300}, 200, paint); + canvas.DrawRect(Rect::MakeLTRB(100, 300, 500, 600), paint); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, CanRenderRadialGradient) { + auto callback = [&](AiksContext& renderer) -> std::optional { + const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; + const Entity::TileMode tile_modes[] = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + + static int selected_tile_mode = 0; + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, + sizeof(tile_mode_names) / sizeof(char*)); + static Matrix matrix = { + 1, 0, 0, 0, // + 0, 1, 0, 0, // + 0, 0, 1, 0, // + 0, 0, 0, 1 // + }; + std::string label = "##1"; + for (int i = 0; i < 4; i++) { + ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.vec[i]), + 4, NULL, NULL, "%.2f", 0); + label[2]++; + } + ImGui::End(); + + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + auto tile_mode = tile_modes[selected_tile_mode]; + + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; + std::vector stops = {0.0, 1.0}; + + paint.color_source = ColorSource::MakeRadialGradient( + {100, 100}, 100, std::move(colors), std::move(stops), tile_mode, {}); + + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + return canvas.EndRecordingAsPicture(); + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + +TEST_P(AiksTest, CanRenderRadialGradientManyColors) { + auto callback = [&](AiksContext& renderer) -> std::optional { + const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; + const Entity::TileMode tile_modes[] = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + + static int selected_tile_mode = 0; + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, + sizeof(tile_mode_names) / sizeof(char*)); + static Matrix matrix = { + 1, 0, 0, 0, // + 0, 1, 0, 0, // + 0, 0, 1, 0, // + 0, 0, 0, 1 // + }; + std::string label = "##1"; + for (int i = 0; i < 4; i++) { + ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.vec[i]), + 4, NULL, NULL, "%.2f", 0); + label[2]++; + } + ImGui::End(); + + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + auto tile_mode = tile_modes[selected_tile_mode]; + + std::vector colors = { + Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}, + Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}, + Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}, + Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}, + Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}, + Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}, + Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}}; + std::vector stops = { + 0.0, + (1.0 / 6.0) * 1, + (1.0 / 6.0) * 2, + (1.0 / 6.0) * 3, + (1.0 / 6.0) * 4, + (1.0 / 6.0) * 5, + 1.0, + }; + + paint.color_source = ColorSource::MakeRadialGradient( + {100, 100}, 100, std::move(colors), std::move(stops), tile_mode, {}); + + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + return canvas.EndRecordingAsPicture(); + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + +namespace { +void CanRenderSweepGradient(AiksTest* aiks_test, Entity::TileMode tile_mode) { + Canvas canvas; + canvas.Scale(aiks_test->GetContentScale()); + Paint paint; + canvas.Translate({100, 100, 0}); + + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; + std::vector stops = {0.0, 1.0}; + + paint.color_source = ColorSource::MakeSweepGradient( + {100, 100}, Degrees(45), Degrees(135), std::move(colors), + std::move(stops), tile_mode, {}); + + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} +} // namespace + +TEST_P(AiksTest, CanRenderSweepGradientClamp) { + CanRenderSweepGradient(this, Entity::TileMode::kClamp); +} +TEST_P(AiksTest, CanRenderSweepGradientRepeat) { + CanRenderSweepGradient(this, Entity::TileMode::kRepeat); +} +TEST_P(AiksTest, CanRenderSweepGradientMirror) { + CanRenderSweepGradient(this, Entity::TileMode::kMirror); +} +TEST_P(AiksTest, CanRenderSweepGradientDecal) { + CanRenderSweepGradient(this, Entity::TileMode::kDecal); +} + +namespace { +void CanRenderSweepGradientManyColors(AiksTest* aiks_test, + Entity::TileMode tile_mode) { + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + + std::vector colors = { + Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}, + Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}, + Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}, + Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}, + Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}, + Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}, + Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}}; + std::vector stops = { + 0.0, + (1.0 / 6.0) * 1, + (1.0 / 6.0) * 2, + (1.0 / 6.0) * 3, + (1.0 / 6.0) * 4, + (1.0 / 6.0) * 5, + 1.0, + }; + + paint.color_source = ColorSource::MakeSweepGradient( + {100, 100}, Degrees(45), Degrees(135), std::move(colors), + std::move(stops), tile_mode, {}); + + canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); + ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} +} // namespace + +TEST_P(AiksTest, CanRenderSweepGradientManyColorsClamp) { + CanRenderSweepGradientManyColors(this, Entity::TileMode::kClamp); +} +TEST_P(AiksTest, CanRenderSweepGradientManyColorsRepeat) { + CanRenderSweepGradientManyColors(this, Entity::TileMode::kRepeat); +} +TEST_P(AiksTest, CanRenderSweepGradientManyColorsMirror) { + CanRenderSweepGradientManyColors(this, Entity::TileMode::kMirror); +} +TEST_P(AiksTest, CanRenderSweepGradientManyColorsDecal) { + CanRenderSweepGradientManyColors(this, Entity::TileMode::kDecal); +} + +TEST_P(AiksTest, CanRenderConicalGradient) { + Scalar size = 256; + Canvas canvas; + Paint paint; + paint.color = Color::White(); + canvas.DrawRect(Rect::MakeXYWH(0, 0, size * 3, size * 3), paint); + std::vector colors = {Color::MakeRGBA8(0xF4, 0x43, 0x36, 0xFF), + Color::MakeRGBA8(0xFF, 0xEB, 0x3B, 0xFF), + Color::MakeRGBA8(0x4c, 0xAF, 0x50, 0xFF), + Color::MakeRGBA8(0x21, 0x96, 0xF3, 0xFF)}; + std::vector stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0}; + std::array, 8> array{ + std::make_tuple(Point{size / 2.f, size / 2.f}, 0.f, + Point{size / 2.f, size / 2.f}, size / 2.f), + std::make_tuple(Point{size / 2.f, size / 2.f}, size / 4.f, + Point{size / 2.f, size / 2.f}, size / 2.f), + std::make_tuple(Point{size / 4.f, size / 4.f}, 0.f, + Point{size / 2.f, size / 2.f}, size / 2.f), + std::make_tuple(Point{size / 4.f, size / 4.f}, size / 2.f, + Point{size / 2.f, size / 2.f}, 0), + std::make_tuple(Point{size / 4.f, size / 4.f}, size / 4.f, + Point{size / 2.f, size / 2.f}, size / 2.f), + std::make_tuple(Point{size / 4.f, size / 4.f}, size / 16.f, + Point{size / 2.f, size / 2.f}, size / 8.f), + std::make_tuple(Point{size / 4.f, size / 4.f}, size / 8.f, + Point{size / 2.f, size / 2.f}, size / 16.f), + std::make_tuple(Point{size / 8.f, size / 8.f}, size / 8.f, + Point{size / 2.f, size / 2.f}, size / 8.f), + }; + for (int i = 0; i < 8; i++) { + canvas.Save(); + canvas.Translate({(i % 3) * size, i / 3 * size, 0}); + paint.color_source = ColorSource::MakeConicalGradient( + std::get<0>(array[i]), std::get<1>(array[i]), colors, stops, + std::get<2>(array[i]), std::get<3>(array[i]), Entity::TileMode::kClamp, + {}); + canvas.DrawRect(Rect::MakeXYWH(0, 0, size, size), paint); + canvas.Restore(); + } + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, CanRenderGradientDecalWithBackground) { + std::vector colors = {Color::MakeRGBA8(0xF4, 0x43, 0x36, 0xFF), + Color::MakeRGBA8(0xFF, 0xEB, 0x3B, 0xFF), + Color::MakeRGBA8(0x4c, 0xAF, 0x50, 0xFF), + Color::MakeRGBA8(0x21, 0x96, 0xF3, 0xFF)}; + std::vector stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0}; + + std::array color_sources = { + ColorSource::MakeLinearGradient({0, 0}, {100, 100}, colors, stops, + Entity::TileMode::kDecal, {}), + ColorSource::MakeRadialGradient({100, 100}, 100, colors, stops, + Entity::TileMode::kDecal, {}), + ColorSource::MakeSweepGradient({100, 100}, Degrees(45), Degrees(135), + colors, stops, Entity::TileMode::kDecal, + {}), + }; + + Canvas canvas; + Paint paint; + paint.color = Color::White(); + canvas.DrawRect(Rect::MakeLTRB(0, 0, 605, 205), paint); + for (int i = 0; i < 3; i++) { + canvas.Save(); + canvas.Translate({i * 200.0f, 0, 0}); + paint.color_source = color_sources[i]; + canvas.DrawRect(Rect::MakeLTRB(0, 0, 200, 200), paint); + canvas.Restore(); + } + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +#define APPLY_COLOR_FILTER_GRADIENT_TEST(name) \ + TEST_P(AiksTest, name##GradientApplyColorFilter) { \ + auto contents = name##GradientContents(); \ + contents.SetColors({Color::CornflowerBlue().WithAlpha(0.75)}); \ + auto result = contents.ApplyColorFilter([](const Color& color) { \ + return color.Blend(Color::LimeGreen().WithAlpha(0.75), \ + BlendMode::kScreen); \ + }); \ + ASSERT_TRUE(result); \ + \ + std::vector expected = {Color(0.433247, 0.879523, 0.825324, 0.75)}; \ + ASSERT_COLORS_NEAR(contents.GetColors(), expected); \ + } + +APPLY_COLOR_FILTER_GRADIENT_TEST(Linear); +APPLY_COLOR_FILTER_GRADIENT_TEST(Radial); +APPLY_COLOR_FILTER_GRADIENT_TEST(Conical); +APPLY_COLOR_FILTER_GRADIENT_TEST(Sweep); + +TEST_P(AiksTest, GradientStrokesRenderCorrectly) { + // Compare with https://fiddle.skia.org/c/027392122bec8ac2b5d5de00a4b9bbe2 + auto callback = [&](AiksContext& renderer) -> std::optional { + static float scale = 3; + static bool add_circle_clip = true; + const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; + const Entity::TileMode tile_modes[] = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + static int selected_tile_mode = 0; + static float alpha = 1; + + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::SliderFloat("Scale", &scale, 0, 6); + ImGui::Checkbox("Circle clip", &add_circle_clip); + ImGui::SliderFloat("Alpha", &alpha, 0, 1); + ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, + sizeof(tile_mode_names) / sizeof(char*)); + ImGui::End(); + + Canvas canvas; + canvas.Scale(GetContentScale()); + Paint paint; + paint.color = Color::White(); + canvas.DrawPaint(paint); + + paint.style = Paint::Style::kStroke; + paint.color = Color(1.0, 1.0, 1.0, alpha); + paint.stroke_width = 10; + auto tile_mode = tile_modes[selected_tile_mode]; + + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; + std::vector stops = {0.0, 1.0}; + + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {50, 50}, std::move(colors), std::move(stops), tile_mode, {}); + + Path path = PathBuilder{} + .MoveTo({20, 20}) + .QuadraticCurveTo({60, 20}, {60, 60}) + .Close() + .MoveTo({60, 20}) + .QuadraticCurveTo({60, 60}, {20, 60}) + .TakePath(); + + canvas.Scale(Vector2(scale, scale)); + + if (add_circle_clip) { + auto [handle_a, handle_b] = IMPELLER_PLAYGROUND_LINE( + Point(60, 300), Point(600, 300), 20, Color::Red(), Color::Red()); + + auto screen_to_canvas = canvas.GetCurrentTransform().Invert(); + Point point_a = screen_to_canvas * handle_a * GetContentScale(); + Point point_b = screen_to_canvas * handle_b * GetContentScale(); + + Point middle = (point_a + point_b) / 2; + auto radius = point_a.GetDistance(middle); + canvas.ClipPath(PathBuilder{}.AddCircle(middle, radius).TakePath()); + } + + for (auto join : {Join::kBevel, Join::kRound, Join::kMiter}) { + paint.stroke_join = join; + for (auto cap : {Cap::kButt, Cap::kSquare, Cap::kRound}) { + paint.stroke_cap = cap; + canvas.DrawPath(path.Clone(), paint); + canvas.Translate({80, 0}); + } + canvas.Translate({-240, 60}); + } + + return canvas.EndRecordingAsPicture(); + }; + + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + +} // namespace testing +} // namespace impeller diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index c0f88a1d3bd41..2ee53ab9ef655 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "flutter/impeller/aiks/aiks_unittests.h" + #include #include #include @@ -11,7 +13,6 @@ #include #include "flutter/testing/testing.h" -#include "impeller/aiks/aiks_playground.h" #include "impeller/aiks/canvas.h" #include "impeller/aiks/color_filter.h" #include "impeller/aiks/image.h" @@ -31,7 +32,6 @@ #include "impeller/geometry/matrix.h" #include "impeller/geometry/path.h" #include "impeller/geometry/path_builder.h" -#include "impeller/golden_tests/golden_playground_test.h" #include "impeller/playground/widgets.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/snapshot.h" @@ -51,11 +51,6 @@ namespace impeller { namespace testing { -#ifdef IMPELLER_GOLDEN_TESTS -using AiksTest = GoldenPlaygroundTest; -#else -using AiksTest = AiksPlayground; -#endif INSTANTIATE_PLAYGROUND_SUITE(AiksTest); TEST_P(AiksTest, RotateColorFilteredPath) { @@ -496,610 +491,6 @@ TEST_P(AiksTest, CanSaveLayerStandalone) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -namespace { -void CanRenderLinearGradient(AiksTest* aiks_test, Entity::TileMode tile_mode) { - Canvas canvas; - canvas.Scale(aiks_test->GetContentScale()); - Paint paint; - canvas.Translate({100.0f, 0, 0}); - - std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 0.0}}; - std::vector stops = {0.0, 1.0}; - - paint.color_source = ColorSource::MakeLinearGradient( - {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {}); - - paint.color = Color(1.0, 1.0, 1.0, 1.0); - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} -} // namespace - -TEST_P(AiksTest, CanRenderLinearGradientClamp) { - CanRenderLinearGradient(this, Entity::TileMode::kClamp); -} -TEST_P(AiksTest, CanRenderLinearGradientRepeat) { - CanRenderLinearGradient(this, Entity::TileMode::kRepeat); -} -TEST_P(AiksTest, CanRenderLinearGradientMirror) { - CanRenderLinearGradient(this, Entity::TileMode::kMirror); -} -TEST_P(AiksTest, CanRenderLinearGradientDecal) { - CanRenderLinearGradient(this, Entity::TileMode::kDecal); -} - -TEST_P(AiksTest, CanRenderLinearGradientDecalWithColorFilter) { - Canvas canvas; - canvas.Scale(GetContentScale()); - Paint paint; - canvas.Translate({100.0f, 0, 0}); - - std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 0.0}}; - std::vector stops = {0.0, 1.0}; - - paint.color_source = ColorSource::MakeLinearGradient( - {0, 0}, {200, 200}, std::move(colors), std::move(stops), - Entity::TileMode::kDecal, {}); - // Overlay the gradient with 25% green. This should appear as the entire - // rectangle being drawn with 25% green, including the border area outside the - // decal gradient. - paint.color_filter = ColorFilter::MakeBlend(BlendMode::kSourceOver, - Color::Green().WithAlpha(0.25)); - - paint.color = Color(1.0, 1.0, 1.0, 1.0); - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -static void CanRenderLinearGradientWithDithering(AiksTest* aiks_test, - bool use_dithering) { - Canvas canvas; - Paint paint; - canvas.Translate({100.0, 100.0, 0}); - - // 0xffcccccc --> 0xff333333, taken from - // https://github.com/flutter/flutter/issues/118073#issue-1521699748 - std::vector colors = {Color{0.8, 0.8, 0.8, 1.0}, - Color{0.2, 0.2, 0.2, 1.0}}; - std::vector stops = {0.0, 1.0}; - - paint.color_source = ColorSource::MakeLinearGradient( - {0, 0}, {800, 500}, std::move(colors), std::move(stops), - Entity::TileMode::kClamp, {}); - paint.dither = use_dithering; - canvas.DrawRect(Rect::MakeXYWH(0, 0, 800, 500), paint); - ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -TEST_P(AiksTest, CanRenderLinearGradientWithDitheringDisabled) { - CanRenderLinearGradientWithDithering(this, false); -} - -TEST_P(AiksTest, CanRenderLinearGradientWithDitheringEnabled) { - CanRenderLinearGradientWithDithering(this, true); -} // namespace - -static void CanRenderRadialGradientWithDithering(AiksTest* aiks_test, - bool use_dithering) { - Canvas canvas; - Paint paint; - canvas.Translate({100.0, 100.0, 0}); - - // #FFF -> #000 - std::vector colors = {Color{1.0, 1.0, 1.0, 1.0}, - Color{0.0, 0.0, 0.0, 1.0}}; - std::vector stops = {0.0, 1.0}; - - paint.color_source = ColorSource::MakeRadialGradient( - {600, 600}, 600, std::move(colors), std::move(stops), - Entity::TileMode::kClamp, {}); - paint.dither = use_dithering; - canvas.DrawRect(Rect::MakeXYWH(0, 0, 1200, 1200), paint); - ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -TEST_P(AiksTest, CanRenderRadialGradientWithDitheringDisabled) { - CanRenderRadialGradientWithDithering(this, false); -} - -TEST_P(AiksTest, CanRenderRadialGradientWithDitheringEnabled) { - CanRenderRadialGradientWithDithering(this, true); -} - -static void CanRenderSweepGradientWithDithering(AiksTest* aiks_test, - bool use_dithering) { - Canvas canvas; - canvas.Scale(aiks_test->GetContentScale()); - Paint paint; - canvas.Translate({100.0, 100.0, 0}); - - // #FFF -> #000 - std::vector colors = {Color{1.0, 1.0, 1.0, 1.0}, - Color{0.0, 0.0, 0.0, 1.0}}; - std::vector stops = {0.0, 1.0}; - - paint.color_source = ColorSource::MakeSweepGradient( - {100, 100}, Degrees(45), Degrees(135), std::move(colors), - std::move(stops), Entity::TileMode::kMirror, {}); - paint.dither = use_dithering; - - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -TEST_P(AiksTest, CanRenderSweepGradientWithDitheringDisabled) { - CanRenderSweepGradientWithDithering(this, false); -} - -TEST_P(AiksTest, CanRenderSweepGradientWithDitheringEnabled) { - CanRenderSweepGradientWithDithering(this, true); -} - -static void CanRenderConicalGradientWithDithering(AiksTest* aiks_test, - bool use_dithering) { - Canvas canvas; - canvas.Scale(aiks_test->GetContentScale()); - Paint paint; - canvas.Translate({100.0, 100.0, 0}); - - // #FFF -> #000 - std::vector colors = {Color{1.0, 1.0, 1.0, 1.0}, - Color{0.0, 0.0, 0.0, 1.0}}; - std::vector stops = {0.0, 1.0}; - - paint.color_source = ColorSource::MakeConicalGradient( - {100, 100}, 100, std::move(colors), std::move(stops), {0, 1}, 0, - Entity::TileMode::kMirror, {}); - paint.dither = use_dithering; - - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -TEST_P(AiksTest, CanRenderConicalGradientWithDitheringDisabled) { - CanRenderConicalGradientWithDithering(this, false); -} - -TEST_P(AiksTest, CanRenderConicalGradientWithDitheringEnabled) { - CanRenderConicalGradientWithDithering(this, true); -} - -namespace { -void CanRenderLinearGradientWithOverlappingStops(AiksTest* aiks_test, - Entity::TileMode tile_mode) { - Canvas canvas; - Paint paint; - canvas.Translate({100.0, 100.0, 0}); - - std::vector colors = { - Color{0.9568, 0.2627, 0.2118, 1.0}, Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}, Color{0.1294, 0.5882, 0.9529, 1.0}}; - std::vector stops = {0.0, 0.5, 0.5, 1.0}; - - paint.color_source = ColorSource::MakeLinearGradient( - {0, 0}, {500, 500}, std::move(colors), std::move(stops), tile_mode, {}); - - paint.color = Color(1.0, 1.0, 1.0, 1.0); - canvas.DrawRect(Rect::MakeXYWH(0, 0, 500, 500), paint); - ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} -} // namespace - -// Only clamp is necessary. All tile modes are the same output. -TEST_P(AiksTest, CanRenderLinearGradientWithOverlappingStopsClamp) { - CanRenderLinearGradientWithOverlappingStops(this, Entity::TileMode::kClamp); -} - -namespace { -void CanRenderLinearGradientManyColors(AiksTest* aiks_test, - Entity::TileMode tile_mode) { - Canvas canvas; - canvas.Scale(aiks_test->GetContentScale()); - Paint paint; - canvas.Translate({100, 100, 0}); - - std::vector colors = { - Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}, - Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}, - Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}, - Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}, - Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}, - Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}, - Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}}; - std::vector stops = { - 0.0, - (1.0 / 6.0) * 1, - (1.0 / 6.0) * 2, - (1.0 / 6.0) * 3, - (1.0 / 6.0) * 4, - (1.0 / 6.0) * 5, - 1.0, - }; - - paint.color_source = ColorSource::MakeLinearGradient( - {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {}); - - paint.color = Color(1.0, 1.0, 1.0, 1.0); - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - canvas.Restore(); - ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} -} // namespace - -TEST_P(AiksTest, CanRenderLinearGradientManyColorsClamp) { - CanRenderLinearGradientManyColors(this, Entity::TileMode::kClamp); -} -TEST_P(AiksTest, CanRenderLinearGradientManyColorsRepeat) { - CanRenderLinearGradientManyColors(this, Entity::TileMode::kRepeat); -} -TEST_P(AiksTest, CanRenderLinearGradientManyColorsMirror) { - CanRenderLinearGradientManyColors(this, Entity::TileMode::kMirror); -} -TEST_P(AiksTest, CanRenderLinearGradientManyColorsDecal) { - CanRenderLinearGradientManyColors(this, Entity::TileMode::kDecal); -} - -namespace { -void CanRenderLinearGradientWayManyColors(AiksTest* aiks_test, - Entity::TileMode tile_mode) { - Canvas canvas; - Paint paint; - canvas.Translate({100.0, 100.0, 0}); - auto color = Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}; - std::vector colors; - std::vector stops; - auto current_stop = 0.0; - for (int i = 0; i < 2000; i++) { - colors.push_back(color); - stops.push_back(current_stop); - current_stop += 1 / 2000.0; - } - stops[2000 - 1] = 1.0; - - paint.color_source = ColorSource::MakeLinearGradient( - {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {}); - - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} -} // namespace - -// Only test clamp on purpose since they all look the same. -TEST_P(AiksTest, CanRenderLinearGradientWayManyColorsClamp) { - CanRenderLinearGradientWayManyColors(this, Entity::TileMode::kClamp); -} - -TEST_P(AiksTest, CanRenderLinearGradientManyColorsUnevenStops) { - auto callback = [&](AiksContext& renderer) -> std::optional { - const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; - const Entity::TileMode tile_modes[] = { - Entity::TileMode::kClamp, Entity::TileMode::kRepeat, - Entity::TileMode::kMirror, Entity::TileMode::kDecal}; - - static int selected_tile_mode = 0; - ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); - ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, - sizeof(tile_mode_names) / sizeof(char*)); - static Matrix matrix = { - 1, 0, 0, 0, // - 0, 1, 0, 0, // - 0, 0, 1, 0, // - 0, 0, 0, 1 // - }; - std::string label = "##1"; - for (int i = 0; i < 4; i++) { - ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.vec[i]), - 4, NULL, NULL, "%.2f", 0); - label[2]++; - } - ImGui::End(); - - Canvas canvas; - Paint paint; - canvas.Translate({100.0, 100.0, 0}); - auto tile_mode = tile_modes[selected_tile_mode]; - - std::vector colors = { - Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}, - Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}, - Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}, - Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}, - Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}, - Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}, - Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}}; - std::vector stops = { - 0.0, 2.0 / 62.0, 4.0 / 62.0, 8.0 / 62.0, 16.0 / 62.0, 32.0 / 62.0, 1.0, - }; - - paint.color_source = ColorSource::MakeLinearGradient( - {0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {}); - - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - return canvas.EndRecordingAsPicture(); - }; - ASSERT_TRUE(OpenPlaygroundHere(callback)); -} - -TEST_P(AiksTest, CanRenderLinearGradientMaskBlur) { - Canvas canvas; - - Paint paint = { - .color = Color::White(), - .color_source = ColorSource::MakeLinearGradient( - {200, 200}, {400, 400}, - {Color::Red(), Color::White(), Color::Red(), Color::White(), - Color::Red(), Color::White(), Color::Red(), Color::White(), - Color::Red(), Color::White(), Color::Red()}, - {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}, - Entity::TileMode::kClamp, {}), - .mask_blur_descriptor = - Paint::MaskBlurDescriptor{ - .style = FilterContents::BlurStyle::kNormal, - .sigma = Sigma(20), - }, - }; - - canvas.DrawCircle({300, 300}, 200, paint); - canvas.DrawRect(Rect::MakeLTRB(100, 300, 500, 600), paint); - - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -TEST_P(AiksTest, CanRenderRadialGradient) { - auto callback = [&](AiksContext& renderer) -> std::optional { - const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; - const Entity::TileMode tile_modes[] = { - Entity::TileMode::kClamp, Entity::TileMode::kRepeat, - Entity::TileMode::kMirror, Entity::TileMode::kDecal}; - - static int selected_tile_mode = 0; - ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); - ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, - sizeof(tile_mode_names) / sizeof(char*)); - static Matrix matrix = { - 1, 0, 0, 0, // - 0, 1, 0, 0, // - 0, 0, 1, 0, // - 0, 0, 0, 1 // - }; - std::string label = "##1"; - for (int i = 0; i < 4; i++) { - ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.vec[i]), - 4, NULL, NULL, "%.2f", 0); - label[2]++; - } - ImGui::End(); - - Canvas canvas; - Paint paint; - canvas.Translate({100.0, 100.0, 0}); - auto tile_mode = tile_modes[selected_tile_mode]; - - std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - std::vector stops = {0.0, 1.0}; - - paint.color_source = ColorSource::MakeRadialGradient( - {100, 100}, 100, std::move(colors), std::move(stops), tile_mode, {}); - - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - return canvas.EndRecordingAsPicture(); - }; - ASSERT_TRUE(OpenPlaygroundHere(callback)); -} - -TEST_P(AiksTest, CanRenderRadialGradientManyColors) { - auto callback = [&](AiksContext& renderer) -> std::optional { - const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; - const Entity::TileMode tile_modes[] = { - Entity::TileMode::kClamp, Entity::TileMode::kRepeat, - Entity::TileMode::kMirror, Entity::TileMode::kDecal}; - - static int selected_tile_mode = 0; - ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); - ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, - sizeof(tile_mode_names) / sizeof(char*)); - static Matrix matrix = { - 1, 0, 0, 0, // - 0, 1, 0, 0, // - 0, 0, 1, 0, // - 0, 0, 0, 1 // - }; - std::string label = "##1"; - for (int i = 0; i < 4; i++) { - ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.vec[i]), - 4, NULL, NULL, "%.2f", 0); - label[2]++; - } - ImGui::End(); - - Canvas canvas; - Paint paint; - canvas.Translate({100.0, 100.0, 0}); - auto tile_mode = tile_modes[selected_tile_mode]; - - std::vector colors = { - Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}, - Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}, - Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}, - Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}, - Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}, - Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}, - Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}}; - std::vector stops = { - 0.0, - (1.0 / 6.0) * 1, - (1.0 / 6.0) * 2, - (1.0 / 6.0) * 3, - (1.0 / 6.0) * 4, - (1.0 / 6.0) * 5, - 1.0, - }; - - paint.color_source = ColorSource::MakeRadialGradient( - {100, 100}, 100, std::move(colors), std::move(stops), tile_mode, {}); - - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - return canvas.EndRecordingAsPicture(); - }; - ASSERT_TRUE(OpenPlaygroundHere(callback)); -} - -namespace { -void CanRenderSweepGradient(AiksTest* aiks_test, Entity::TileMode tile_mode) { - Canvas canvas; - canvas.Scale(aiks_test->GetContentScale()); - Paint paint; - canvas.Translate({100, 100, 0}); - - std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - std::vector stops = {0.0, 1.0}; - - paint.color_source = ColorSource::MakeSweepGradient( - {100, 100}, Degrees(45), Degrees(135), std::move(colors), - std::move(stops), tile_mode, {}); - - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} -} // namespace - -TEST_P(AiksTest, CanRenderSweepGradientClamp) { - CanRenderSweepGradient(this, Entity::TileMode::kClamp); -} -TEST_P(AiksTest, CanRenderSweepGradientRepeat) { - CanRenderSweepGradient(this, Entity::TileMode::kRepeat); -} -TEST_P(AiksTest, CanRenderSweepGradientMirror) { - CanRenderSweepGradient(this, Entity::TileMode::kMirror); -} -TEST_P(AiksTest, CanRenderSweepGradientDecal) { - CanRenderSweepGradient(this, Entity::TileMode::kDecal); -} - -namespace { -void CanRenderSweepGradientManyColors(AiksTest* aiks_test, - Entity::TileMode tile_mode) { - Canvas canvas; - Paint paint; - canvas.Translate({100.0, 100.0, 0}); - - std::vector colors = { - Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}, - Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}, - Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}, - Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}, - Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}, - Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}, - Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}}; - std::vector stops = { - 0.0, - (1.0 / 6.0) * 1, - (1.0 / 6.0) * 2, - (1.0 / 6.0) * 3, - (1.0 / 6.0) * 4, - (1.0 / 6.0) * 5, - 1.0, - }; - - paint.color_source = ColorSource::MakeSweepGradient( - {100, 100}, Degrees(45), Degrees(135), std::move(colors), - std::move(stops), tile_mode, {}); - - canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint); - ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} -} // namespace - -TEST_P(AiksTest, CanRenderSweepGradientManyColorsClamp) { - CanRenderSweepGradientManyColors(this, Entity::TileMode::kClamp); -} -TEST_P(AiksTest, CanRenderSweepGradientManyColorsRepeat) { - CanRenderSweepGradientManyColors(this, Entity::TileMode::kRepeat); -} -TEST_P(AiksTest, CanRenderSweepGradientManyColorsMirror) { - CanRenderSweepGradientManyColors(this, Entity::TileMode::kMirror); -} -TEST_P(AiksTest, CanRenderSweepGradientManyColorsDecal) { - CanRenderSweepGradientManyColors(this, Entity::TileMode::kDecal); -} - -TEST_P(AiksTest, CanRenderConicalGradient) { - Scalar size = 256; - Canvas canvas; - Paint paint; - paint.color = Color::White(); - canvas.DrawRect(Rect::MakeXYWH(0, 0, size * 3, size * 3), paint); - std::vector colors = {Color::MakeRGBA8(0xF4, 0x43, 0x36, 0xFF), - Color::MakeRGBA8(0xFF, 0xEB, 0x3B, 0xFF), - Color::MakeRGBA8(0x4c, 0xAF, 0x50, 0xFF), - Color::MakeRGBA8(0x21, 0x96, 0xF3, 0xFF)}; - std::vector stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0}; - std::array, 8> array{ - std::make_tuple(Point{size / 2.f, size / 2.f}, 0.f, - Point{size / 2.f, size / 2.f}, size / 2.f), - std::make_tuple(Point{size / 2.f, size / 2.f}, size / 4.f, - Point{size / 2.f, size / 2.f}, size / 2.f), - std::make_tuple(Point{size / 4.f, size / 4.f}, 0.f, - Point{size / 2.f, size / 2.f}, size / 2.f), - std::make_tuple(Point{size / 4.f, size / 4.f}, size / 2.f, - Point{size / 2.f, size / 2.f}, 0), - std::make_tuple(Point{size / 4.f, size / 4.f}, size / 4.f, - Point{size / 2.f, size / 2.f}, size / 2.f), - std::make_tuple(Point{size / 4.f, size / 4.f}, size / 16.f, - Point{size / 2.f, size / 2.f}, size / 8.f), - std::make_tuple(Point{size / 4.f, size / 4.f}, size / 8.f, - Point{size / 2.f, size / 2.f}, size / 16.f), - std::make_tuple(Point{size / 8.f, size / 8.f}, size / 8.f, - Point{size / 2.f, size / 2.f}, size / 8.f), - }; - for (int i = 0; i < 8; i++) { - canvas.Save(); - canvas.Translate({(i % 3) * size, i / 3 * size, 0}); - paint.color_source = ColorSource::MakeConicalGradient( - std::get<0>(array[i]), std::get<1>(array[i]), colors, stops, - std::get<2>(array[i]), std::get<3>(array[i]), Entity::TileMode::kClamp, - {}); - canvas.DrawRect(Rect::MakeXYWH(0, 0, size, size), paint); - canvas.Restore(); - } - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - -TEST_P(AiksTest, CanRenderGradientDecalWithBackground) { - std::vector colors = {Color::MakeRGBA8(0xF4, 0x43, 0x36, 0xFF), - Color::MakeRGBA8(0xFF, 0xEB, 0x3B, 0xFF), - Color::MakeRGBA8(0x4c, 0xAF, 0x50, 0xFF), - Color::MakeRGBA8(0x21, 0x96, 0xF3, 0xFF)}; - std::vector stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0}; - - std::array color_sources = { - ColorSource::MakeLinearGradient({0, 0}, {100, 100}, colors, stops, - Entity::TileMode::kDecal, {}), - ColorSource::MakeRadialGradient({100, 100}, 100, colors, stops, - Entity::TileMode::kDecal, {}), - ColorSource::MakeSweepGradient({100, 100}, Degrees(45), Degrees(135), - colors, stops, Entity::TileMode::kDecal, - {}), - }; - - Canvas canvas; - Paint paint; - paint.color = Color::White(); - canvas.DrawRect(Rect::MakeLTRB(0, 0, 605, 205), paint); - for (int i = 0; i < 3; i++) { - canvas.Save(); - canvas.Translate({i * 200.0f, 0, 0}); - paint.color_source = color_sources[i]; - canvas.DrawRect(Rect::MakeLTRB(0, 0, 200, 200), paint); - canvas.Restore(); - } - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); -} - TEST_P(AiksTest, CanRenderDifferentShapesWithSameColorSource) { Canvas canvas; Paint paint; @@ -2401,83 +1792,6 @@ TEST_P(AiksTest, FilledRoundRectsRenderCorrectly) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -TEST_P(AiksTest, GradientStrokesRenderCorrectly) { - // Compare with https://fiddle.skia.org/c/027392122bec8ac2b5d5de00a4b9bbe2 - auto callback = [&](AiksContext& renderer) -> std::optional { - static float scale = 3; - static bool add_circle_clip = true; - const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; - const Entity::TileMode tile_modes[] = { - Entity::TileMode::kClamp, Entity::TileMode::kRepeat, - Entity::TileMode::kMirror, Entity::TileMode::kDecal}; - static int selected_tile_mode = 0; - static float alpha = 1; - - ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); - ImGui::SliderFloat("Scale", &scale, 0, 6); - ImGui::Checkbox("Circle clip", &add_circle_clip); - ImGui::SliderFloat("Alpha", &alpha, 0, 1); - ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, - sizeof(tile_mode_names) / sizeof(char*)); - ImGui::End(); - - Canvas canvas; - canvas.Scale(GetContentScale()); - Paint paint; - paint.color = Color::White(); - canvas.DrawPaint(paint); - - paint.style = Paint::Style::kStroke; - paint.color = Color(1.0, 1.0, 1.0, alpha); - paint.stroke_width = 10; - auto tile_mode = tile_modes[selected_tile_mode]; - - std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - std::vector stops = {0.0, 1.0}; - - paint.color_source = ColorSource::MakeLinearGradient( - {0, 0}, {50, 50}, std::move(colors), std::move(stops), tile_mode, {}); - - Path path = PathBuilder{} - .MoveTo({20, 20}) - .QuadraticCurveTo({60, 20}, {60, 60}) - .Close() - .MoveTo({60, 20}) - .QuadraticCurveTo({60, 60}, {20, 60}) - .TakePath(); - - canvas.Scale(Vector2(scale, scale)); - - if (add_circle_clip) { - auto [handle_a, handle_b] = IMPELLER_PLAYGROUND_LINE( - Point(60, 300), Point(600, 300), 20, Color::Red(), Color::Red()); - - auto screen_to_canvas = canvas.GetCurrentTransform().Invert(); - Point point_a = screen_to_canvas * handle_a * GetContentScale(); - Point point_b = screen_to_canvas * handle_b * GetContentScale(); - - Point middle = (point_a + point_b) / 2; - auto radius = point_a.GetDistance(middle); - canvas.ClipPath(PathBuilder{}.AddCircle(middle, radius).TakePath()); - } - - for (auto join : {Join::kBevel, Join::kRound, Join::kMiter}) { - paint.stroke_join = join; - for (auto cap : {Cap::kButt, Cap::kSquare, Cap::kRound}) { - paint.stroke_cap = cap; - canvas.DrawPath(path.Clone(), paint); - canvas.Translate({80, 0}); - } - canvas.Translate({-240, 60}); - } - - return canvas.EndRecordingAsPicture(); - }; - - ASSERT_TRUE(OpenPlaygroundHere(callback)); -} - TEST_P(AiksTest, CoverageOriginShouldBeAccountedForInSubpasses) { auto callback = [&](AiksContext& renderer) -> std::optional { Canvas canvas; @@ -4006,25 +3320,6 @@ TEST_P(AiksTest, SolidColorApplyColorFilter) { Color(0.433247, 0.879523, 0.825324, 0.75)); } -#define APPLY_COLOR_FILTER_GRADIENT_TEST(name) \ - TEST_P(AiksTest, name##GradientApplyColorFilter) { \ - auto contents = name##GradientContents(); \ - contents.SetColors({Color::CornflowerBlue().WithAlpha(0.75)}); \ - auto result = contents.ApplyColorFilter([](const Color& color) { \ - return color.Blend(Color::LimeGreen().WithAlpha(0.75), \ - BlendMode::kScreen); \ - }); \ - ASSERT_TRUE(result); \ - \ - std::vector expected = {Color(0.433247, 0.879523, 0.825324, 0.75)}; \ - ASSERT_COLORS_NEAR(contents.GetColors(), expected); \ - } - -APPLY_COLOR_FILTER_GRADIENT_TEST(Linear); -APPLY_COLOR_FILTER_GRADIENT_TEST(Radial); -APPLY_COLOR_FILTER_GRADIENT_TEST(Conical); -APPLY_COLOR_FILTER_GRADIENT_TEST(Sweep); - TEST_P(AiksTest, DrawScaledTextWithPerspectiveNoSaveLayer) { Canvas canvas; // clang-format off diff --git a/impeller/aiks/aiks_unittests.h b/impeller/aiks/aiks_unittests.h new file mode 100644 index 0000000000000..44301f9459b1b --- /dev/null +++ b/impeller/aiks/aiks_unittests.h @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_AIKS_AIKS_UNITTESTS_H_ +#define FLUTTER_IMPELLER_AIKS_AIKS_UNITTESTS_H_ + +#include "impeller/aiks/aiks_playground.h" +#include "impeller/golden_tests/golden_playground_test.h" + +namespace impeller { +namespace testing { + +#ifdef IMPELLER_GOLDEN_TESTS +using AiksTest = GoldenPlaygroundTest; +#else +using AiksTest = AiksPlayground; +#endif + +} // namespace testing +} // namespace impeller + +#endif // FLUTTER_IMPELLER_AIKS_AIKS_UNITTESTS_H_ diff --git a/shell/platform/android/android_context_gl_impeller.cc b/shell/platform/android/android_context_gl_impeller.cc index 8c9b80645d7ab..d76910c4b317d 100644 --- a/shell/platform/android/android_context_gl_impeller.cc +++ b/shell/platform/android/android_context_gl_impeller.cc @@ -13,7 +13,8 @@ #include "impeller/entity/gles/framebuffer_blend_shaders_gles.h" #if IMPELLER_ENABLE_3D -#include "impeller/scene/shaders/gles/scene_shaders_gles.h" // nogcncheck +// This include was turned to an error since it breaks GN. +#include "impeller/scene/shaders/gles/scene_shaders_gles.h" // nogncheck #endif // IMPELLER_ENABLE_3D namespace flutter { diff --git a/shell/platform/android/android_context_vulkan_impeller.cc b/shell/platform/android/android_context_vulkan_impeller.cc index c40f997924e07..98b61db42d739 100644 --- a/shell/platform/android/android_context_vulkan_impeller.cc +++ b/shell/platform/android/android_context_vulkan_impeller.cc @@ -11,7 +11,7 @@ #include "flutter/impeller/renderer/backend/vulkan/context_vk.h" #if IMPELLER_ENABLE_3D -#include "flutter/impeller/scene/shaders/vk/scene_shaders_vk.h" +#include "flutter/impeller/scene/shaders/vk/scene_shaders_vk.h" // nogncheck #endif // IMPELLER_ENABLE_3D namespace flutter {