diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 1a76e58e41cec..ca5b25f3fbe34 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -127,7 +127,6 @@ ../../../flutter/impeller/.clang-format ../../../flutter/impeller/.gitignore ../../../flutter/impeller/README.md -../../../flutter/impeller/aiks/aiks_blend_unittests.cc ../../../flutter/impeller/aiks/aiks_gradient_unittests.cc ../../../flutter/impeller/aiks/aiks_unittests.cc ../../../flutter/impeller/aiks/aiks_unittests.h diff --git a/impeller/aiks/BUILD.gn b/impeller/aiks/BUILD.gn index bd7a2ad8199ab..04e4f1e366fda 100644 --- a/impeller/aiks/BUILD.gn +++ b/impeller/aiks/BUILD.gn @@ -71,7 +71,6 @@ impeller_component("context_spy") { template("aiks_unittests_component") { target_name = invoker.target_name predefined_sources = [ - "aiks_blend_unittests.cc", "aiks_gradient_unittests.cc", "aiks_unittests.cc", "aiks_unittests.h", diff --git a/impeller/aiks/aiks_blend_unittests.cc b/impeller/aiks/aiks_blend_unittests.cc deleted file mode 100644 index a1fc120aa4196..0000000000000 --- a/impeller/aiks/aiks_blend_unittests.cc +++ /dev/null @@ -1,183 +0,0 @@ -// 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 "flutter/testing/testing.h" -#include "impeller/aiks/canvas.h" -#include "impeller/aiks/color_filter.h" -#include "impeller/geometry/color.h" -#include "impeller/geometry/scalar.h" - -//////////////////////////////////////////////////////////////////////////////// -// This is for tests of Canvas that are interested the results of rendering -// blends. -//////////////////////////////////////////////////////////////////////////////// - -namespace impeller { -namespace testing { - -#define BLEND_MODE_TUPLE(blend_mode) {#blend_mode, BlendMode::k##blend_mode}, - -struct BlendModeSelection { - std::vector blend_mode_names; - std::vector blend_mode_values; -}; - -static BlendModeSelection GetBlendModeSelection() { - std::vector blend_mode_names; - std::vector blend_mode_values; - { - const std::vector> blends = { - IMPELLER_FOR_EACH_BLEND_MODE(BLEND_MODE_TUPLE)}; - assert(blends.size() == - static_cast(Entity::kLastAdvancedBlendMode) + 1); - for (const auto& [name, mode] : blends) { - blend_mode_names.push_back(name); - blend_mode_values.push_back(mode); - } - } - - return {blend_mode_names, blend_mode_values}; -} - -TEST_P(AiksTest, ColorWheel) { - // Compare with https://fiddle.skia.org/c/@BlendModes - - BlendModeSelection blend_modes = GetBlendModeSelection(); - - auto draw_color_wheel = [](Canvas& canvas) { - /// color_wheel_sampler: r=0 -> fuchsia, r=2pi/3 -> yellow, r=4pi/3 -> - /// cyan domain: r >= 0 (because modulo used is non euclidean) - auto color_wheel_sampler = [](Radians r) { - Scalar x = r.radians / k2Pi + 1; - - // https://www.desmos.com/calculator/6nhjelyoaj - auto color_cycle = [](Scalar x) { - Scalar cycle = std::fmod(x, 6.0f); - return std::max(0.0f, std::min(1.0f, 2 - std::abs(2 - cycle))); - }; - return Color(color_cycle(6 * x + 1), // - color_cycle(6 * x - 1), // - color_cycle(6 * x - 3), // - 1); - }; - - Paint paint; - paint.blend_mode = BlendMode::kSourceOver; - - // Draw a fancy color wheel for the backdrop. - // https://www.desmos.com/calculator/xw7kafthwd - const int max_dist = 900; - for (int i = 0; i <= 900; i++) { - Radians r(kPhi / k2Pi * i); - Scalar distance = r.radians / std::powf(4.12, 0.0026 * r.radians); - Scalar normalized_distance = static_cast(i) / max_dist; - - paint.color = - color_wheel_sampler(r).WithAlpha(1.0f - normalized_distance); - Point position(distance * std::sin(r.radians), - -distance * std::cos(r.radians)); - - canvas.DrawCircle(position, 9 + normalized_distance * 3, paint); - } - }; - - std::shared_ptr color_wheel_image; - Matrix color_wheel_transform; - - auto callback = [&](AiksContext& renderer) -> std::optional { - // UI state. - static bool cache_the_wheel = true; - static int current_blend_index = 3; - static float dst_alpha = 1; - static float src_alpha = 1; - static Color color0 = Color::Red(); - static Color color1 = Color::Green(); - static Color color2 = Color::Blue(); - - if (AiksTest::ImGuiBegin("Controls", nullptr, - ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Checkbox("Cache the wheel", &cache_the_wheel); - ImGui::ListBox("Blending mode", ¤t_blend_index, - blend_modes.blend_mode_names.data(), - blend_modes.blend_mode_names.size()); - ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1); - ImGui::ColorEdit4("Color A", reinterpret_cast(&color0)); - ImGui::ColorEdit4("Color B", reinterpret_cast(&color1)); - ImGui::ColorEdit4("Color C", reinterpret_cast(&color2)); - ImGui::SliderFloat("Destination alpha", &dst_alpha, 0, 1); - ImGui::End(); - } - - static Point content_scale; - Point new_content_scale = GetContentScale(); - - if (!cache_the_wheel || new_content_scale != content_scale) { - content_scale = new_content_scale; - - // Render the color wheel to an image. - - Canvas canvas; - canvas.Scale(content_scale); - - canvas.Translate(Vector2(500, 400)); - canvas.Scale(Vector2(3, 3)); - - draw_color_wheel(canvas); - auto color_wheel_picture = canvas.EndRecordingAsPicture(); - auto image = color_wheel_picture.ToImage( - renderer, ISize{GetWindowSize().width, GetWindowSize().height}); - if (!image) { - return std::nullopt; - } - color_wheel_image = image; - color_wheel_transform = Matrix(); - } - - Canvas canvas; - - // Blit the color wheel backdrop to the screen with managed alpha. - canvas.SaveLayer({.color = Color::White().WithAlpha(dst_alpha), - .blend_mode = BlendMode::kSource}); - { - canvas.DrawPaint({.color = Color::White()}); - - canvas.Save(); - canvas.Transform(color_wheel_transform); - canvas.DrawImage(color_wheel_image, Point(), Paint()); - canvas.Restore(); - } - canvas.Restore(); - - canvas.Scale(content_scale); - canvas.Translate(Vector2(500, 400)); - canvas.Scale(Vector2(3, 3)); - - // Draw 3 circles to a subpass and blend it in. - canvas.SaveLayer( - {.color = Color::White().WithAlpha(src_alpha), - .blend_mode = blend_modes.blend_mode_values[current_blend_index]}); - { - Paint paint; - paint.blend_mode = BlendMode::kPlus; - const Scalar x = std::sin(k2Pi / 3); - const Scalar y = -std::cos(k2Pi / 3); - paint.color = color0; - canvas.DrawCircle(Point(-x, y) * 45, 65, paint); - paint.color = color1; - canvas.DrawCircle(Point(0, -1) * 45, 65, paint); - paint.color = color2; - canvas.DrawCircle(Point(x, y) * 45, 65, paint); - } - canvas.Restore(); - - 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 25167d5f6fb9a..b317b82c8e6f0 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -384,6 +384,5 @@ TEST_P(AiksTest, CorrectClipDepthAssignedToEntities) { // █ the subdivisions of AiksTest to avoid having one massive file. // █ // █ Subdivisions: -// █ - aiks_blend_unittests.cc // █ - aiks_gradient_unittests.cc // █████████████████████████████████████████████████████████████████████████████ diff --git a/impeller/display_list/aiks_dl_blend_unittests.cc b/impeller/display_list/aiks_dl_blend_unittests.cc index fe7b345fba16d..cdddca598112c 100644 --- a/impeller/display_list/aiks_dl_blend_unittests.cc +++ b/impeller/display_list/aiks_dl_blend_unittests.cc @@ -18,6 +18,10 @@ #include "flutter/display_list/dl_paint.h" #include "flutter/impeller/display_list/dl_image_impeller.h" #include "flutter/impeller/geometry/scalar.h" +#include "impeller/aiks/aiks_context.h" +#include "impeller/display_list/dl_dispatcher.h" +#include "impeller/playground/playground.h" +#include "impeller/playground/playground_test.h" #include "include/core/SkMatrix.h" //////////////////////////////////////////////////////////////////////////////// @@ -566,5 +570,122 @@ TEST_P(AiksTest, FramebufferAdvancedBlendCoverage) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(AiksTest, ColorWheel) { + // Compare with https://fiddle.skia.org/c/@BlendModes + + BlendModeSelection blend_modes = GetBlendModeSelection(); + + auto draw_color_wheel = [](DisplayListBuilder& builder) -> void { + /// color_wheel_sampler: r=0 -> fuchsia, r=2pi/3 -> yellow, r=4pi/3 -> + /// cyan domain: r >= 0 (because modulo used is non euclidean) + auto color_wheel_sampler = [](Radians r) { + Scalar x = r.radians / k2Pi + 1; + + // https://www.desmos.com/calculator/6nhjelyoaj + auto color_cycle = [](Scalar x) { + Scalar cycle = std::fmod(x, 6.0f); + return std::max(0.0f, std::min(1.0f, 2 - std::abs(2 - cycle))); + }; + return Color(color_cycle(6 * x + 1), // + color_cycle(6 * x - 1), // + color_cycle(6 * x - 3), // + 1); + }; + + DlPaint paint; + paint.setBlendMode(DlBlendMode::kSrcOver); + + // Draw a fancy color wheel for the backdrop. + // https://www.desmos.com/calculator/xw7kafthwd + const int max_dist = 900; + for (int i = 0; i <= 900; i++) { + Radians r(kPhi / k2Pi * i); + Scalar distance = r.radians / std::powf(4.12, 0.0026 * r.radians); + Scalar normalized_distance = static_cast(i) / max_dist; + + auto color = color_wheel_sampler(r).WithAlpha(1.0f - normalized_distance); + paint.setColor( + DlColor::RGBA(color.red, color.green, color.blue, color.alpha)); + SkPoint position = SkPoint::Make(distance * std::sin(r.radians), + -distance * std::cos(r.radians)); + + builder.DrawCircle(position, 9 + normalized_distance * 3, paint); + } + }; + + auto callback = [&]() -> sk_sp { + // UI state. + static bool cache_the_wheel = true; + static int current_blend_index = 3; + static float dst_alpha = 1; + static float src_alpha = 1; + static DlColor color0 = DlColor::kRed(); + static DlColor color1 = DlColor::kGreen(); + static DlColor color2 = DlColor::kBlue(); + + if (AiksTest::ImGuiBegin("Controls", nullptr, + ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Checkbox("Cache the wheel", &cache_the_wheel); + ImGui::ListBox("Blending mode", ¤t_blend_index, + blend_modes.blend_mode_names.data(), + blend_modes.blend_mode_names.size()); + ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1); + ImGui::ColorEdit4("Color A", reinterpret_cast(&color0)); + ImGui::ColorEdit4("Color B", reinterpret_cast(&color1)); + ImGui::ColorEdit4("Color C", reinterpret_cast(&color2)); + ImGui::SliderFloat("Destination alpha", &dst_alpha, 0, 1); + ImGui::End(); + } + + DisplayListBuilder builder; + + DlPaint paint; + paint.setColor(DlColor::kWhite().withAlpha(dst_alpha * 255)); + paint.setBlendMode(DlBlendMode::kSrc); + builder.SaveLayer(nullptr, &paint); + { + DlPaint paint; + paint.setColor(DlColor::kWhite()); + builder.DrawPaint(paint); + + builder.SaveLayer(nullptr, nullptr); + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.Translate(500, 400); + builder.Scale(3, 3); + draw_color_wheel(builder); + builder.Restore(); + } + builder.Restore(); + + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.Translate(500, 400); + builder.Scale(3, 3); + + // Draw 3 circles to a subpass and blend it in. + DlPaint save_paint; + save_paint.setColor(DlColor::kWhite().withAlpha(src_alpha * 255)); + save_paint.setBlendMode(static_cast( + blend_modes.blend_mode_values[current_blend_index])); + builder.SaveLayer(nullptr, &save_paint); + { + DlPaint paint; + paint.setBlendMode(DlBlendMode::kPlus); + const Scalar x = std::sin(k2Pi / 3); + const Scalar y = -std::cos(k2Pi / 3); + paint.setColor(color0); + builder.DrawCircle(SkPoint::Make(-x * 45, y * 45), 65, paint); + paint.setColor(color1); + builder.DrawCircle(SkPoint::Make(0, -45), 65, paint); + paint.setColor(color2); + builder.DrawCircle(SkPoint::Make(x * 45, y * 45), 65, paint); + } + builder.Restore(); + + return builder.Build(); + }; + + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + } // namespace testing } // namespace impeller