From 869f90866e339bdd869cd96d87d2abe1ce67df7f Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 3 Apr 2023 15:28:20 -0700 Subject: [PATCH] [Impeller] Add subpass blend goldens (flutter/engine#40879) --- .../flutter/impeller/aiks/aiks_unittests.cc | 52 +++++++------------ engine/src/flutter/impeller/geometry/color.cc | 22 ++++++++ engine/src/flutter/impeller/geometry/color.h | 34 ++++++++++++ 3 files changed, 76 insertions(+), 32 deletions(-) diff --git a/engine/src/flutter/impeller/aiks/aiks_unittests.cc b/engine/src/flutter/impeller/aiks/aiks_unittests.cc index c9db82e09d5..94022971632 100644 --- a/engine/src/flutter/impeller/aiks/aiks_unittests.cc +++ b/engine/src/flutter/impeller/aiks/aiks_unittests.cc @@ -1287,6 +1287,8 @@ TEST_P(AiksTest, PaintBlendModeIsRespected) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +#define BLEND_MODE_TUPLE(blend_mode) {#blend_mode, BlendMode::k##blend_mode}, + TEST_P(AiksTest, ColorWheel) { // Compare with https://fiddle.skia.org/c/@BlendModes @@ -1294,38 +1296,7 @@ TEST_P(AiksTest, ColorWheel) { std::vector blend_mode_values; { const std::vector> blends = { - // Pipeline blends (Porter-Duff alpha compositing) - {"Clear", BlendMode::kClear}, - {"Source", BlendMode::kSource}, - {"Destination", BlendMode::kDestination}, - {"SourceOver", BlendMode::kSourceOver}, - {"DestinationOver", BlendMode::kDestinationOver}, - {"SourceIn", BlendMode::kSourceIn}, - {"DestinationIn", BlendMode::kDestinationIn}, - {"SourceOut", BlendMode::kSourceOut}, - {"DestinationOut", BlendMode::kDestinationOut}, - {"SourceATop", BlendMode::kSourceATop}, - {"DestinationATop", BlendMode::kDestinationATop}, - {"Xor", BlendMode::kXor}, - {"Plus", BlendMode::kPlus}, - {"Modulate", BlendMode::kModulate}, - // Advanced blends (color component blends) - {"Screen", BlendMode::kScreen}, - {"Overlay", BlendMode::kOverlay}, - {"Darken", BlendMode::kDarken}, - {"Lighten", BlendMode::kLighten}, - {"ColorDodge", BlendMode::kColorDodge}, - {"ColorBurn", BlendMode::kColorBurn}, - {"HardLight", BlendMode::kHardLight}, - {"SoftLight", BlendMode::kSoftLight}, - {"Difference", BlendMode::kDifference}, - {"Exclusion", BlendMode::kExclusion}, - {"Multiply", BlendMode::kMultiply}, - {"Hue", BlendMode::kHue}, - {"Saturation", BlendMode::kSaturation}, - {"Color", BlendMode::kColor}, - {"Luminosity", BlendMode::kLuminosity}, - }; + IMPELLER_FOR_EACH_BLEND_MODE(BLEND_MODE_TUPLE)}; assert(blends.size() == static_cast(Entity::kLastAdvancedBlendMode) + 1); for (const auto& [name, mode] : blends) { @@ -1939,5 +1910,22 @@ TEST_P(AiksTest, DrawPaintAbsorbsClears) { ASSERT_EQ(picture.pass->GetClearColor(), Color::CornflowerBlue()); } +static Picture BlendModeSaveLayerTest(BlendMode blend_mode) { + Canvas canvas; + canvas.DrawPaint({.color = Color::CornflowerBlue().WithAlpha(0.75)}); + canvas.SaveLayer({.blend_mode = blend_mode}); + for (auto& color : {Color::White(), Color::LimeGreen(), Color::Black()}) { + canvas.DrawRect({100, 100, 200, 200}, {.color = color.WithAlpha(0.75)}); + canvas.Translate(Vector2(150, 100)); + } + return canvas.EndRecordingAsPicture(); +} + +#define BLEND_MODE_TEST(blend_mode) \ + TEST_P(AiksTest, BlendModeSaveLayer##blend_mode) { \ + OpenPlaygroundHere(BlendModeSaveLayerTest(BlendMode::k##blend_mode)); \ + } +IMPELLER_FOR_EACH_BLEND_MODE(BLEND_MODE_TEST) + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/geometry/color.cc b/engine/src/flutter/impeller/geometry/color.cc index 70946f66a85..bc72252756f 100644 --- a/engine/src/flutter/impeller/geometry/color.cc +++ b/engine/src/flutter/impeller/geometry/color.cc @@ -13,6 +13,28 @@ namespace impeller { +#define _IMPELLER_ASSERT_BLEND_MODE(blend_mode) \ + auto enum_##blend_mode = static_cast>( \ + BlendMode::k##blend_mode); \ + if (i != enum_##blend_mode) { \ + return false; \ + } \ + ++i; + +static constexpr inline bool ValidateBlendModes() { + std::underlying_type_t i = 0; + // Ensure the order of the blend modes match. + IMPELLER_FOR_EACH_BLEND_MODE(_IMPELLER_ASSERT_BLEND_MODE) + // Ensure the total number of blend modes match. + if (i - 1 != + static_cast>(BlendMode::kLast)) { + return false; + } + return true; +} +static_assert(ValidateBlendModes(), + "IMPELLER_FOR_EACH_BLEND_MODE must match impeller::BlendMode."); + ColorHSB ColorHSB::FromRGB(Color rgb) { Scalar R = rgb.red; Scalar G = rgb.green; diff --git a/engine/src/flutter/impeller/geometry/color.h b/engine/src/flutter/impeller/geometry/color.h index 8faf9c08154..c1e0da44ea4 100644 --- a/engine/src/flutter/impeller/geometry/color.h +++ b/engine/src/flutter/impeller/geometry/color.h @@ -8,8 +8,40 @@ #include #include #include +#include #include "impeller/geometry/scalar.h" +#define IMPELLER_FOR_EACH_BLEND_MODE(V) \ + V(Clear) \ + V(Source) \ + V(Destination) \ + V(SourceOver) \ + V(DestinationOver) \ + V(SourceIn) \ + V(DestinationIn) \ + V(SourceOut) \ + V(DestinationOut) \ + V(SourceATop) \ + V(DestinationATop) \ + V(Xor) \ + V(Plus) \ + V(Modulate) \ + V(Screen) \ + V(Overlay) \ + V(Darken) \ + V(Lighten) \ + V(ColorDodge) \ + V(ColorBurn) \ + V(HardLight) \ + V(SoftLight) \ + V(Difference) \ + V(Exclusion) \ + V(Multiply) \ + V(Hue) \ + V(Saturation) \ + V(Color) \ + V(Luminosity) + namespace impeller { struct ColorHSB; @@ -55,6 +87,8 @@ enum class BlendMode { kSaturation, kColor, kLuminosity, + + kLast = kLuminosity, }; /**