// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef FLUTTER_COMMON_GRAPHICS_PERSISTENT_CACHE_H_ #define FLUTTER_COMMON_GRAPHICS_PERSISTENT_CACHE_H_ #include #include #include #include "flutter/assets/asset_manager.h" #include "flutter/fml/macros.h" #include "flutter/fml/task_runner.h" #include "flutter/fml/unique_fd.h" #include "third_party/skia/include/gpu/GrContextOptions.h" class GrDirectContext; namespace flutter { namespace testing { class ShellTest; } /// A cache of SkData that gets stored to disk. /// /// This is mainly used for Shaders but is also written to by Dart. It is /// thread-safe for reading and writing from multiple threads. class PersistentCache : public GrContextOptions::PersistentCache { public: // Mutable static switch that can be set before GetCacheForProcess. If true, // we'll only read existing caches but not generate new ones. Some clients // (e.g., embedded devices) prefer generating persistent cache files for the // specific device beforehand, and ship them as readonly files in OTA // packages. static bool gIsReadOnly; static PersistentCache* GetCacheForProcess(); static void ResetCacheForProcess(); // This must be called before |GetCacheForProcess|. Otherwise, it won't // affect the cache directory returned by |GetCacheForProcess|. static void SetCacheDirectoryPath(std::string path); // Convert a binary SkData key into a Base32 encoded string. // // This is used to specify persistent cache filenames and service protocol // json keys. static std::string SkKeyToFilePath(const SkData& key); // Allocate a MallocMapping containing the given key and value in the file // format used by the cache. static std::unique_ptr BuildCacheObject( const SkData& key, const SkData& data); // Header written into the files used to store cached Skia objects. struct CacheObjectHeader { // A prefix used to identify the cache object file format. static const uint32_t kSignature = 0xA869593F; static const uint32_t kVersion1 = 1; explicit CacheObjectHeader(uint32_t p_key_size) : key_size(p_key_size) {} uint32_t signature = kSignature; uint32_t version = kVersion1; uint32_t key_size; }; ~PersistentCache() override; void AddWorkerTaskRunner(const fml::RefPtr& task_runner); void RemoveWorkerTaskRunner(const 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; } // Remove all files inside the persistent cache directory. // Return whether the purge is successful. bool Purge(); // |GrContextOptions::PersistentCache| sk_sp load(const SkData& key) override; struct SkSLCache { sk_sp key; sk_sp value; }; /// Load all the SkSL shader caches in the right directory. std::vector LoadSkSLs() const; //---------------------------------------------------------------------------- /// @brief Precompile SkSLs packaged with the application and gathered /// during previous runs in the given context. /// /// @warning The context must be the rendering context. This context may be /// destroyed during application suspension and subsequently /// recreated. The SkSLs must be precompiled again in the new /// context. /// /// @param context The rendering context to precompile shaders in. /// /// @return The number of SkSLs precompiled. /// size_t PrecompileKnownSkSLs(GrDirectContext* context) const; // Return mappings for all skp's accessible through the AssetManager std::vector> GetSkpsFromAssetManager() const; /// Set the asset manager from which PersistentCache can load SkLSs. A nullptr /// can be provided to clear the asset manager. static void SetAssetManager(std::shared_ptr value); static std::shared_ptr asset_manager() { return asset_manager_; } static bool cache_sksl() { return cache_sksl_; } static void SetCacheSkSL(bool value); static void MarkStrategySet() { strategy_set_ = true; } static constexpr char kSkSLSubdirName[] = "sksl"; static constexpr char kAssetFileName[] = "io.flutter.shaders.json"; private: static std::string cache_base_path_; static std::shared_ptr asset_manager_; static std::mutex instance_mutex_; static std::unique_ptr gPersistentCache; // Mutable static switch that can be set before GetCacheForProcess is called // and GrContextOptions.fShaderCacheStrategy is set. If true, it means that // we'll set `GrContextOptions::fShaderCacheStrategy` to `kSkSL`, and all the // persistent cache should be stored and loaded from the "sksl" directory. static std::atomic cache_sksl_; // Guard flag to make sure that cache_sksl_ is not modified after // strategy_set_ becomes true. static std::atomic strategy_set_; const bool is_read_only_; const std::shared_ptr cache_directory_; const std::shared_ptr sksl_cache_directory_; mutable std::mutex worker_task_runners_mutex_; std::multiset> worker_task_runners_; bool stored_new_shaders_ = false; bool is_dumping_skp_ = false; static SkSLCache LoadFile(const fml::UniqueFD& dir, const std::string& file_name, bool need_key); bool IsValid() const; explicit PersistentCache(bool read_only = false); // |GrContextOptions::PersistentCache| void store(const SkData& key, const SkData& data) override; fml::RefPtr GetWorkerTaskRunner() const; friend class testing::ShellTest; FML_DISALLOW_COPY_AND_ASSIGN(PersistentCache); }; } // namespace flutter #endif // FLUTTER_COMMON_GRAPHICS_PERSISTENT_CACHE_H_