1313#include " flutter/display_list/skia/dl_sk_dispatcher.h"
1414#include " flutter/display_list/testing/dl_test_surface_provider.h"
1515#include " flutter/display_list/utils/dl_comparable.h"
16+ #include " flutter/fml/file.h"
1617#include " flutter/fml/math.h"
1718#include " flutter/testing/display_list_testing.h"
1819#include " flutter/testing/testing.h"
@@ -1102,8 +1103,10 @@ class TestParameters {
11021103
11031104class CanvasCompareTester {
11041105 public:
1105- static std::vector<BackendType> kTestBackends ;
1106- static std::string kTempDirectory ;
1106+ static std::vector<BackendType> TestBackends;
1107+ static std::string ImpellerFailureImageDirectory;
1108+ static bool SaveImpellerFailureImages;
1109+ static std::vector<std::string> ImpellerFailureImages;
11071110
11081111 static std::unique_ptr<DlSurfaceProvider> GetProvider (BackendType type) {
11091112 auto provider = DlSurfaceProvider::Create (type);
@@ -1122,15 +1125,15 @@ class CanvasCompareTester {
11221125 if (!provider) {
11231126 return false ;
11241127 }
1125- CanvasCompareTester::kTestBackends .push_back (type);
1128+ CanvasCompareTester::TestBackends .push_back (type);
11261129 return true ;
11271130 }
11281131
11291132 static BoundsTolerance DefaultTolerance;
11301133
11311134 static void RenderAll (const TestParameters& params,
11321135 const BoundsTolerance& tolerance = DefaultTolerance) {
1133- for (auto & back_end : kTestBackends ) {
1136+ for (auto & back_end : TestBackends ) {
11341137 auto provider = GetProvider (back_end);
11351138 RenderEnvironment env = RenderEnvironment::MakeN32 (provider.get ());
11361139 env.init_ref (kEmptySkSetup , params.sk_renderer (), //
@@ -1142,8 +1145,8 @@ class CanvasCompareTester {
11421145 " Impeller reference" )) {
11431146 std::string test_name =
11441147 ::testing::UnitTest::GetInstance ()->current_test_info()->name();
1145- impeller_result-> write (
1146- to_png_filename (test_name + " (Impeller reference) " ) );
1148+ save_to_png ( impeller_result, test_name + " (Impeller reference) " ,
1149+ " base rendering was blank or out of bounds " );
11471150 }
11481151 } else {
11491152 static OncePerBackendWarning warnings (" No Impeller output tests" );
@@ -2264,16 +2267,75 @@ class CanvasCompareTester {
22642267 .with_diff_clip ());
22652268 }
22662269
2267- static std::string to_png_filename (const std::string& desc) {
2268- if (kTempDirectory .length () == 0 ) {
2269- kTempDirectory = fml::CreateTemporaryDirectory ();
2270+ enum class DirectoryStatus {
2271+ kExisted ,
2272+ kCreated ,
2273+ kFailed ,
2274+ };
2275+
2276+ static DirectoryStatus CheckDir (const std::string& dir) {
2277+ auto ret =
2278+ fml::OpenDirectory (dir.c_str (), false , fml::FilePermission::kRead );
2279+ if (ret.is_valid ()) {
2280+ return DirectoryStatus::kExisted ;
2281+ }
2282+ ret =
2283+ fml::OpenDirectory (dir.c_str (), true , fml::FilePermission::kReadWrite );
2284+ if (ret.is_valid ()) {
2285+ return DirectoryStatus::kCreated ;
22702286 }
2287+ FML_LOG (ERROR) << " Could not create directory (" << dir
2288+ << " ) for impeller failure images"
2289+ << " , ret = " << ret.get () << " , errno = " << errno;
2290+ return DirectoryStatus::kFailed ;
2291+ }
22712292
2272- std::string ret = kTempDirectory + " /" ;
2273- for (const char & ch : desc) {
2274- ret += (ch == ' :' || ch == ' ' ) ? ' _' : ch;
2293+ static void SetupImpellerFailureImageDirectory () {
2294+ std::string base_dir = " ./impeller_failure_images" ;
2295+ if (CheckDir (base_dir) == DirectoryStatus::kFailed ) {
2296+ return ;
2297+ }
2298+ for (int i = 0 ; i < 10000 ; i++) {
2299+ std::string sub_dir = std::to_string (i);
2300+ while (sub_dir.length () < 4 ) {
2301+ sub_dir = " 0" + sub_dir;
2302+ }
2303+ std::string try_dir = base_dir + " /" + sub_dir;
2304+ switch (CheckDir (try_dir)) {
2305+ case DirectoryStatus::kExisted :
2306+ break ;
2307+ case DirectoryStatus::kCreated :
2308+ ImpellerFailureImageDirectory = try_dir;
2309+ return ;
2310+ case DirectoryStatus::kFailed :
2311+ return ;
2312+ }
22752313 }
2276- return ret + " .png" ;
2314+ FML_LOG (ERROR) << " Too many output directories for Impeller failure images" ;
2315+ }
2316+
2317+ static void save_to_png (const RenderResult* result,
2318+ const std::string& op_desc,
2319+ const std::string& reason) {
2320+ if (!SaveImpellerFailureImages) {
2321+ return ;
2322+ }
2323+ if (ImpellerFailureImageDirectory.length () == 0 ) {
2324+ SetupImpellerFailureImageDirectory ();
2325+ if (ImpellerFailureImageDirectory.length () == 0 ) {
2326+ SaveImpellerFailureImages = false ;
2327+ return ;
2328+ }
2329+ }
2330+
2331+ std::string filename = ImpellerFailureImageDirectory + " /" ;
2332+ for (const char & ch : op_desc) {
2333+ filename += (ch == ' :' || ch == ' ' ) ? ' _' : ch;
2334+ }
2335+ filename = filename + " .png" ;
2336+ result->write (filename);
2337+ ImpellerFailureImages.push_back (filename);
2338+ FML_LOG (ERROR) << reason << " : " << filename;
22772339 }
22782340
22792341 static void RenderWith (const TestParameters& testP,
@@ -2352,23 +2414,17 @@ class CanvasCompareTester {
23522414 env.ref_impeller_result (), imp_result.get (), false ,
23532415 imp_info + " (attribute should affect rendering)" );
23542416 }
2355- if (!success) {
2417+ if (SaveImpellerFailureImages && !success) {
23562418 FML_LOG (ERROR) << " Impeller issue encountered for: "
23572419 << *imp_job.MakeDisplayList (base_info);
2358- std::string filename = to_png_filename (info + " (Impeller Output)" );
2359- imp_result->write (filename);
2360- FML_LOG (ERROR) << " output saved in: " << filename;
2361- std::string src_filename = to_png_filename (info + " (Impeller Input)" );
2362- env.ref_impeller_result ()->write (src_filename);
2363- FML_LOG (ERROR) << " compare to reference without attributes: "
2364- << src_filename;
2365- std::string sk_filename = to_png_filename (info + " (Skia Output)" );
2366- sk_result->write (sk_filename);
2367- FML_LOG (ERROR) << " and to Skia reference with attributes: "
2368- << sk_filename;
2369- std::string sk_src_filename = to_png_filename (info + " (Skia Input)" );
2370- env.ref_sk_result ()->write (sk_src_filename);
2371- FML_LOG (ERROR) << " operating on Skia source image: " << sk_src_filename;
2420+ save_to_png (imp_result.get (), info + " (Impeller Result)" ,
2421+ " output saved in" );
2422+ save_to_png (env.ref_impeller_result (), info + " (Impeller Reference)" ,
2423+ " compare to reference without attributes" );
2424+ save_to_png (sk_result.get (), info + " (Skia Result)" ,
2425+ " and to Skia reference with attributes" );
2426+ save_to_png (env.ref_sk_result (), info + " (Skia Reference)" ,
2427+ " and to Skia reference without attributes" );
23722428 }
23732429 }
23742430
@@ -2755,8 +2811,10 @@ class CanvasCompareTester {
27552811 }
27562812};
27572813
2758- std::vector<BackendType> CanvasCompareTester::kTestBackends ;
2759- std::string CanvasCompareTester::kTempDirectory = " " ;
2814+ std::vector<BackendType> CanvasCompareTester::TestBackends;
2815+ std::string CanvasCompareTester::ImpellerFailureImageDirectory = " " ;
2816+ bool CanvasCompareTester::SaveImpellerFailureImages = false ;
2817+ std::vector<std::string> CanvasCompareTester::ImpellerFailureImages;
27602818
27612819BoundsTolerance CanvasCompareTester::DefaultTolerance =
27622820 BoundsTolerance ().addAbsolutePadding(1 , 1 );
@@ -2790,6 +2848,10 @@ class DisplayListRenderingTestBase : public BaseT,
27902848 for (auto p_arg = std::next (args.begin ()); p_arg != args.end (); p_arg++) {
27912849 std::string arg = *p_arg;
27922850 bool enable = true ;
2851+ if (arg == " --save-impeller-failures" ) {
2852+ CanvasCompareTester::SaveImpellerFailureImages = true ;
2853+ continue ;
2854+ }
27932855 if (StartsWith (arg, " --no" )) {
27942856 enable = false ;
27952857 arg = " -" + arg.substr (4 );
@@ -2812,12 +2874,25 @@ class DisplayListRenderingTestBase : public BaseT,
28122874 CanvasCompareTester::AddProvider (BackendType::kMetalBackend );
28132875 }
28142876 std::string providers = " " ;
2815- for (auto & back_end : CanvasCompareTester::kTestBackends ) {
2877+ for (auto & back_end : CanvasCompareTester::TestBackends ) {
28162878 providers += " " + DlSurfaceProvider::BackendName (back_end);
28172879 }
28182880 FML_LOG (INFO) << " Running tests on [" << providers << " ]" ;
28192881 }
28202882
2883+ static void TearDownTestSuite () {
2884+ if (CanvasCompareTester::ImpellerFailureImages.size () > 0 ) {
2885+ FML_LOG (INFO);
2886+ FML_LOG (INFO) << CanvasCompareTester::ImpellerFailureImages.size ()
2887+ << " images saved in "
2888+ << CanvasCompareTester::ImpellerFailureImageDirectory;
2889+ for (auto filename : CanvasCompareTester::ImpellerFailureImages) {
2890+ FML_LOG (INFO) << " " << filename;
2891+ }
2892+ FML_LOG (INFO);
2893+ }
2894+ }
2895+
28212896 private:
28222897 FML_DISALLOW_COPY_AND_ASSIGN (DisplayListRenderingTestBase);
28232898};
@@ -3811,7 +3886,7 @@ TEST_F(DisplayListRendering, SaveLayerClippedContentStillFilters) {
38113886 CaseParameters case_params (" Filtered SaveLayer with clipped content" );
38123887 BoundsTolerance tolerance = BoundsTolerance ().addAbsolutePadding (6 .0f , 6 .0f );
38133888
3814- for (auto & back_end : CanvasCompareTester::kTestBackends ) {
3889+ for (auto & back_end : CanvasCompareTester::TestBackends ) {
38153890 auto provider = CanvasCompareTester::GetProvider (back_end);
38163891 RenderEnvironment env = RenderEnvironment::MakeN32 (provider.get ());
38173892 env.init_ref (kEmptySkSetup , test_params.sk_renderer (), //
@@ -3926,7 +4001,7 @@ TEST_F(DisplayListRendering, SaveLayerConsolidation) {
39264001 bool same, bool rev_same,
39274002 const std::string& desc1,
39284003 const std::string& desc2) {
3929- for (auto & back_end : CanvasCompareTester::kTestBackends ) {
4004+ for (auto & back_end : CanvasCompareTester::TestBackends ) {
39304005 auto provider = CanvasCompareTester::GetProvider (back_end);
39314006 auto env = std::make_unique<RenderEnvironment>(
39324007 provider.get (), PixelFormat::kN32PremulPixelFormat );
@@ -4039,7 +4114,7 @@ TEST_F(DisplayListRendering, MatrixColorFilterModifyTransparencyCheck) {
40394114 builder2.Restore ();
40404115 auto display_list2 = builder2.Build ();
40414116
4042- for (auto & back_end : CanvasCompareTester::kTestBackends ) {
4117+ for (auto & back_end : CanvasCompareTester::TestBackends ) {
40434118 auto provider = CanvasCompareTester::GetProvider (back_end);
40444119 auto env = std::make_unique<RenderEnvironment>(
40454120 provider.get (), PixelFormat::kN32PremulPixelFormat );
@@ -4110,7 +4185,7 @@ TEST_F(DisplayListRendering, MatrixColorFilterOpacityCommuteCheck) {
41104185 builder2.Restore ();
41114186 auto display_list2 = builder2.Build ();
41124187
4113- for (auto & back_end : CanvasCompareTester::kTestBackends ) {
4188+ for (auto & back_end : CanvasCompareTester::TestBackends ) {
41144189 auto provider = CanvasCompareTester::GetProvider (back_end);
41154190 auto env = std::make_unique<RenderEnvironment>(
41164191 provider.get (), PixelFormat::kN32PremulPixelFormat );
@@ -4215,7 +4290,7 @@ TEST_F(DisplayListRendering, BlendColorFilterModifyTransparencyCheck) {
42154290 builder2.Restore ();
42164291 auto display_list2 = builder2.Build ();
42174292
4218- for (auto & back_end : CanvasCompareTester::kTestBackends ) {
4293+ for (auto & back_end : CanvasCompareTester::TestBackends ) {
42194294 auto provider = CanvasCompareTester::GetProvider (back_end);
42204295 auto env = std::make_unique<RenderEnvironment>(
42214296 provider.get (), PixelFormat::kN32PremulPixelFormat );
@@ -4279,7 +4354,7 @@ TEST_F(DisplayListRendering, BlendColorFilterOpacityCommuteCheck) {
42794354 builder2.Restore ();
42804355 auto display_list2 = builder2.Build ();
42814356
4282- for (auto & back_end : CanvasCompareTester::kTestBackends ) {
4357+ for (auto & back_end : CanvasCompareTester::TestBackends ) {
42834358 auto provider = CanvasCompareTester::GetProvider (back_end);
42844359 auto env = std::make_unique<RenderEnvironment>(
42854360 provider.get (), PixelFormat::kN32PremulPixelFormat );
@@ -4538,7 +4613,7 @@ class DisplayListNopTest : public DisplayListRendering {
45384613 SkPaint sk_paint;
45394614 sk_paint.setBlendMode (sk_mode);
45404615 sk_paint.setColor (ToSk (color));
4541- for (auto & back_end : CanvasCompareTester::kTestBackends ) {
4616+ for (auto & back_end : CanvasCompareTester::TestBackends ) {
45424617 auto provider = CanvasCompareTester::GetProvider (back_end);
45434618 auto result_surface = provider->MakeOffscreenSurface (
45444619 test_image->width (), test_image->height (),
@@ -4601,7 +4676,7 @@ class DisplayListNopTest : public DisplayListRendering {
46014676 sk_paint.setColor (ToSk (color));
46024677 sk_paint.setColorFilter (ToSk (color_filter));
46034678 sk_paint.setImageFilter (ToSk (image_filter));
4604- for (auto & back_end : CanvasCompareTester::kTestBackends ) {
4679+ for (auto & back_end : CanvasCompareTester::TestBackends ) {
46054680 auto provider = CanvasCompareTester::GetProvider (back_end);
46064681 auto result_surface = provider->MakeOffscreenSurface (
46074682 w, h, DlSurfaceProvider::kN32PremulPixelFormat );
0 commit comments