diff --git a/common/settings.cc b/common/settings.cc index d2d1c702787fd2fd54b00def625a1c4746096885..b292d376be0c34a08b13eaa0c3d81f9bc31cb159 100644 --- a/common/settings.cc +++ b/common/settings.cc @@ -33,6 +33,9 @@ std::string Settings::ToString() const { stream << "start_paused: " << start_paused << std::endl; stream << "trace_skia: " << trace_skia << std::endl; stream << "trace_startup: " << trace_startup << std::endl; + stream << "trace_systrace: " << trace_systrace << std::endl; + stream << "dump_skp_on_shader_compilation: " << dump_skp_on_shader_compilation + << std::endl; stream << "endless_trace_buffer: " << endless_trace_buffer << std::endl; stream << "enable_dart_profiling: " << enable_dart_profiling << std::endl; stream << "disable_dart_asserts: " << disable_dart_asserts << std::endl; diff --git a/common/settings.h b/common/settings.h index 812e2167d31e2afefd3ba4a5060dff105b5bb18e..bfbfd4139d322be63e875021fc9d64d6ae3bc784 100644 --- a/common/settings.h +++ b/common/settings.h @@ -64,6 +64,7 @@ struct Settings { bool trace_skia = false; bool trace_startup = false; bool trace_systrace = false; + bool dump_skp_on_shader_compilation = false; bool endless_trace_buffer = false; bool enable_dart_profiling = false; bool disable_dart_asserts = false; diff --git a/shell/common/persistent_cache.cc b/shell/common/persistent_cache.cc index 6e52a810e59ec5172cc29b2c7bcf7a29b1d07a23..e771ab502acb362fb418e5df96f18762820c73ae 100644 --- a/shell/common/persistent_cache.cc +++ b/shell/common/persistent_cache.cc @@ -134,6 +134,8 @@ static void PersistentCacheStore(fml::RefPtr worker, // |GrContextOptions::PersistentCache| void PersistentCache::store(const SkData& key, const SkData& data) { + stored_new_shaders_ = true; + if (is_read_only_) { return; } @@ -159,6 +161,24 @@ void PersistentCache::store(const SkData& key, const SkData& data) { std::move(file_name), std::move(mapping)); } +void PersistentCache::DumpSkp(const SkData& data) { + if (is_read_only_ || !IsValid()) { + FML_LOG(ERROR) << "Could not dump SKP from read-only or invalid persistent " + "cache."; + return; + } + + std::stringstream name_stream; + auto ticks = fml::TimePoint::Now().ToEpochDelta().ToNanoseconds(); + name_stream << "shader_dump_" << std::to_string(ticks) << ".skp"; + std::string file_name = name_stream.str(); + FML_LOG(ERROR) << "Dumping " << file_name; + auto mapping = std::make_unique( + std::vector{data.bytes(), data.bytes() + data.size()}); + PersistentCacheStore(GetWorkerTaskRunner(), cache_directory_, + std::move(file_name), std::move(mapping)); +} + void PersistentCache::AddWorkerTaskRunner( fml::RefPtr task_runner) { std::lock_guard lock(worker_task_runners_mutex_); diff --git a/shell/common/persistent_cache.h b/shell/common/persistent_cache.h index 51662994dde709ac035643a9ec09601477a47eba..7b3310e849baec9ff85003772462dbb7020b99c5 100644 --- a/shell/common/persistent_cache.h +++ b/shell/common/persistent_cache.h @@ -36,6 +36,15 @@ class PersistentCache : public GrContextOptions::PersistentCache { void RemoveWorkerTaskRunner(fml::RefPtr task_runner); + // Whether Skia tries to store any shader into this persistent cache after + // |ResetStoredNewShaders| is called. This flag is usually reset before each + // frame so we can know if Skia tries to compile new shaders in that frame. + bool StoredNewShaders() const { return stored_new_shaders_; } + void ResetStoredNewShaders() { stored_new_shaders_ = false; } + void DumpSkp(const SkData& data); + bool IsDumpingSkp() const { return is_dumping_skp_; } + void SetIsDumpingSkp(bool value) { is_dumping_skp_ = value; } + private: static std::string cache_base_path_; @@ -45,6 +54,9 @@ class PersistentCache : public GrContextOptions::PersistentCache { std::multiset> worker_task_runners_ FML_GUARDED_BY(worker_task_runners_mutex_); + bool stored_new_shaders_ = false; + bool is_dumping_skp_ = false; + bool IsValid() const; PersistentCache(bool read_only = false); diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 39766a5877c998c0612c3f287ba635ad3c941466..b86e7cf19c4698e5abb904a51a91fce709f44905 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -4,6 +4,8 @@ #include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/persistent_cache.h" + #include #include "third_party/skia/include/core/SkEncodedImageFormat.h" @@ -150,9 +152,19 @@ void Rasterizer::DoDraw(std::unique_ptr layer_tree) { return; } + PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess(); + persistent_cache->ResetStoredNewShaders(); + if (DrawToSurface(*layer_tree)) { last_layer_tree_ = std::move(layer_tree); } + + if (persistent_cache->IsDumpingSkp() && + persistent_cache->StoredNewShaders()) { + auto screenshot = + ScreenshotLastLayerTree(ScreenshotType::SkiaPicture, false); + persistent_cache->DumpSkp(*screenshot.data); + } } bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) { diff --git a/shell/common/shell.cc b/shell/common/shell.cc index ef177eacabcc38b8089c5aea605973c9971aacb3..3c43ef2d12f506df9001ee6dba59aa8d43244882 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -382,6 +382,9 @@ bool Shell::Setup(std::unique_ptr platform_view, PersistentCache::GetCacheForProcess()->AddWorkerTaskRunner( task_runners_.GetIOTaskRunner()); + PersistentCache::GetCacheForProcess()->SetIsDumpingSkp( + settings_.dump_skp_on_shader_compilation); + return true; } diff --git a/shell/common/switches.cc b/shell/common/switches.cc index 997cd846ec613b921050a5398d3a123f87b247bf..215e043f78505c5339fa543a0595838410e02e6d 100644 --- a/shell/common/switches.cc +++ b/shell/common/switches.cc @@ -276,6 +276,9 @@ blink::Settings SettingsFromCommandLine(const fml::CommandLine& command_line) { command_line.HasOption(FlagForSwitch(Switch::TraceSystrace)); #endif + settings.dump_skp_on_shader_compilation = + command_line.HasOption(FlagForSwitch(Switch::DumpSkpOnShaderCompilation)); + return settings; } diff --git a/shell/common/switches.h b/shell/common/switches.h index a5da872d6d1c916aed7c5d367037be3ab5802929..951bf7ad55b24d0d3ddf454cf79155789565a182 100644 --- a/shell/common/switches.h +++ b/shell/common/switches.h @@ -109,8 +109,13 @@ DEF_SWITCH(TraceStartup, DEF_SWITCH(TraceSkia, "trace-skia", "Trace Skia calls. This is useful when debugging the GPU threed." - "By default, Skia tracing is not enable to reduce the number of " + "By default, Skia tracing is not enabled to reduce the number of " "traced events") +DEF_SWITCH(DumpSkpOnShaderCompilation, + "dump-skp-on-shader-compilation", + "Automatically dump the skp that triggers new shader compilations. " + "This is useful for writing custom ShaderWarmUp to reduce jank. " + "By default, this is not enabled to reduce the overhead. ") DEF_SWITCH( TraceSystrace, "trace-systrace", diff --git a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java index 4230208eb4608e5fadebb53003cb5a2fa465947d..c56908db643b3ec30052590d1b2f2e9e20356779 100644 --- a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java +++ b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java @@ -315,6 +315,9 @@ public final class FlutterActivityDelegate if (intent.getBooleanExtra("trace-systrace", false)) { args.add("--trace-systrace"); } + if (intent.getBooleanExtra("dump-skp-on-shader-compilation", false)) { + args.add("--dump-skp-on-shader-compilation"); + } if (intent.getBooleanExtra("verbose-logging", false)) { args.add("--verbose-logging"); } diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java b/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java index c3b2c9b71531e12192aa96398f1607bef5037f92..6e5ec8c7ba7bceba1eab1f869811f66484d306a0 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java @@ -37,6 +37,8 @@ public class FlutterShellArgs { public static final String ARG_SKIA_DETERMINISTIC_RENDERING = "--skia-deterministic-rendering"; public static final String ARG_KEY_TRACE_SKIA = "trace-skia"; public static final String ARG_TRACE_SKIA = "--trace-skia"; + public static final String ARG_KEY_DUMP_SHADER_SKP_ON_SHADER_COMPILATION = "dump-skp-on-shader-compilation"; + public static final String ARG_DUMP_SHADER_SKP_ON_SHADER_COMPILATION = "--dump-skp-on-shader-compilation"; public static final String ARG_KEY_VERBOSE_LOGGING = "verbose-logging"; public static final String ARG_VERBOSE_LOGGING = "--verbose-logging"; @@ -69,6 +71,9 @@ public class FlutterShellArgs { if (intent.getBooleanExtra(ARG_KEY_TRACE_SKIA, false)) { args.add(ARG_TRACE_SKIA); } + if (intent.getBooleanExtra(ARG_KEY_DUMP_SHADER_SKP_ON_SHADER_COMPILATION, false)) { + args.add(ARG_KEY_DUMP_SHADER_SKP_ON_SHADER_COMPILATION); + } if (intent.getBooleanExtra(ARG_KEY_VERBOSE_LOGGING, false)) { args.add(ARG_VERBOSE_LOGGING); }