From 66fdeb163ef6fed6e9bac652bb36c7495aa17fb8 Mon Sep 17 00:00:00 2001 From: liyuqian Date: Thu, 14 Mar 2019 12:58:09 -0700 Subject: [PATCH] Add dump-shader-skp switch to help ShaderWarmUp (#8148) Allow Flutter to automatically dump the skp that triggers new shader compilations. This is useful for writing custom ShaderWarmUp to reduce jank. By default, it's not enabled to reduce the overhead. This is only available in profile or debug build. Later, we can add service protocol support to pull the skp from the client to the host. Currently, it works fine for Android-based devices (including our urgent internal clients) where we can `adb shell` into the cache directory. --- common/settings.cc | 3 +++ common/settings.h | 1 + shell/common/persistent_cache.cc | 20 +++++++++++++++++++ shell/common/persistent_cache.h | 12 +++++++++++ shell/common/rasterizer.cc | 12 +++++++++++ shell/common/shell.cc | 3 +++ shell/common/switches.cc | 3 +++ shell/common/switches.h | 7 ++++++- .../flutter/app/FlutterActivityDelegate.java | 3 +++ .../embedding/engine/FlutterShellArgs.java | 5 +++++ 10 files changed, 68 insertions(+), 1 deletion(-) diff --git a/common/settings.cc b/common/settings.cc index d2d1c702787..b292d376be0 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 812e2167d31..bfbfd4139d3 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 6e52a810e59..e771ab502ac 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 51662994dde..7b3310e849b 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 39766a5877c..b86e7cf19c4 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 ef177eacabc..3c43ef2d12f 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 997cd846ec6..215e043f785 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 a5da872d6d1..951bf7ad55b 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 4230208eb46..c56908db643 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 c3b2c9b7153..6e5ec8c7ba7 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); }