From c2677872093bc415ee427015be29db8f8224611e 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 (flutter/engine#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. --- engine/src/flutter/common/settings.cc | 3 +++ engine/src/flutter/common/settings.h | 1 + .../flutter/shell/common/persistent_cache.cc | 20 +++++++++++++++++++ .../flutter/shell/common/persistent_cache.h | 12 +++++++++++ engine/src/flutter/shell/common/rasterizer.cc | 12 +++++++++++ engine/src/flutter/shell/common/shell.cc | 3 +++ engine/src/flutter/shell/common/switches.cc | 3 +++ engine/src/flutter/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/engine/src/flutter/common/settings.cc b/engine/src/flutter/common/settings.cc index d2d1c70278..b292d376be 100644 --- a/engine/src/flutter/common/settings.cc +++ b/engine/src/flutter/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/engine/src/flutter/common/settings.h b/engine/src/flutter/common/settings.h index 812e2167d3..bfbfd4139d 100644 --- a/engine/src/flutter/common/settings.h +++ b/engine/src/flutter/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/engine/src/flutter/shell/common/persistent_cache.cc b/engine/src/flutter/shell/common/persistent_cache.cc index 6e52a810e5..e771ab502a 100644 --- a/engine/src/flutter/shell/common/persistent_cache.cc +++ b/engine/src/flutter/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/engine/src/flutter/shell/common/persistent_cache.h b/engine/src/flutter/shell/common/persistent_cache.h index 51662994dd..7b3310e849 100644 --- a/engine/src/flutter/shell/common/persistent_cache.h +++ b/engine/src/flutter/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/engine/src/flutter/shell/common/rasterizer.cc b/engine/src/flutter/shell/common/rasterizer.cc index 39766a5877..b86e7cf19c 100644 --- a/engine/src/flutter/shell/common/rasterizer.cc +++ b/engine/src/flutter/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/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc index ef177eacab..3c43ef2d12 100644 --- a/engine/src/flutter/shell/common/shell.cc +++ b/engine/src/flutter/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/engine/src/flutter/shell/common/switches.cc b/engine/src/flutter/shell/common/switches.cc index 997cd846ec..215e043f78 100644 --- a/engine/src/flutter/shell/common/switches.cc +++ b/engine/src/flutter/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/engine/src/flutter/shell/common/switches.h b/engine/src/flutter/shell/common/switches.h index a5da872d6d..951bf7ad55 100644 --- a/engine/src/flutter/shell/common/switches.h +++ b/engine/src/flutter/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/engine/src/flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java b/engine/src/flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java index 4230208eb4..c56908db64 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java +++ b/engine/src/flutter/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/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java index c3b2c9b715..6e5ec8c7ba 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java +++ b/engine/src/flutter/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); }