1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef FLUTTER_SHELL_COMMON_PERSISTENT_CACHE_H_
6#define FLUTTER_SHELL_COMMON_PERSISTENT_CACHE_H_
7
8#include <memory>
9#include <mutex>
10#include <set>
11
12#include "flutter/assets/asset_manager.h"
13#include "flutter/fml/macros.h"
14#include "flutter/fml/task_runner.h"
15#include "flutter/fml/unique_fd.h"
16#include "third_party/skia/include/gpu/GrContextOptions.h"
17
18namespace flutter {
19
20/// A cache of SkData that gets stored to disk.
21///
22/// This is mainly used for Shaders but is also written to by Dart. It is
23/// thread-safe for reading and writing from multiple threads.
24class PersistentCache : public GrContextOptions::PersistentCache {
25 public:
26 // Mutable static switch that can be set before GetCacheForProcess. If true,
27 // we'll only read existing caches but not generate new ones. Some clients
28 // (e.g., embedded devices) prefer generating persistent cache files for the
29 // specific device beforehand, and ship them as readonly files in OTA
30 // packages.
31 static bool gIsReadOnly;
32
33 static PersistentCache* GetCacheForProcess();
34 static void ResetCacheForProcess();
35
36 // This must be called before |GetCacheForProcess|. Otherwise, it won't
37 // affect the cache directory returned by |GetCacheForProcess|.
38 static void SetCacheDirectoryPath(std::string path);
39
40 // Convert a binary SkData key into a Base32 encoded string.
41 //
42 // This is used to specify persistent cache filenames and service protocol
43 // json keys.
44 static std::string SkKeyToFilePath(const SkData& data);
45
46 ~PersistentCache() override;
47
48 void AddWorkerTaskRunner(fml::RefPtr<fml::TaskRunner> task_runner);
49
50 void RemoveWorkerTaskRunner(fml::RefPtr<fml::TaskRunner> task_runner);
51
52 // Whether Skia tries to store any shader into this persistent cache after
53 // |ResetStoredNewShaders| is called. This flag is usually reset before each
54 // frame so we can know if Skia tries to compile new shaders in that frame.
55 bool StoredNewShaders() const { return stored_new_shaders_; }
56 void ResetStoredNewShaders() { stored_new_shaders_ = false; }
57 void DumpSkp(const SkData& data);
58 bool IsDumpingSkp() const { return is_dumping_skp_; }
59 void SetIsDumpingSkp(bool value) { is_dumping_skp_ = value; }
60
61 // Remove all files inside the persistent cache directory.
62 // Return whether the purge is successful.
63 bool Purge();
64
65 // |GrContextOptions::PersistentCache|
66 sk_sp<SkData> load(const SkData& key) override;
67
68 using SkSLCache = std::pair<sk_sp<SkData>, sk_sp<SkData>>;
69
70 /// Load all the SkSL shader caches in the right directory.
71 std::vector<SkSLCache> LoadSkSLs();
72
73 /// Set the asset manager from which PersistentCache can load SkLSs. A nullptr
74 /// can be provided to clear the asset manager.
75 static void SetAssetManager(std::shared_ptr<AssetManager> value);
76
77 static bool cache_sksl() { return cache_sksl_; }
78 static void SetCacheSkSL(bool value);
79 static void MarkStrategySet() { strategy_set_ = true; }
80
81 static constexpr char kSkSLSubdirName[] = "sksl";
82 static constexpr char kAssetFileName[] = "io.flutter.shaders.json";
83
84 private:
85 static std::string cache_base_path_;
86
87 static std::shared_ptr<AssetManager> asset_manager_;
88
89 static std::mutex instance_mutex_;
90 static std::unique_ptr<PersistentCache> gPersistentCache;
91
92 // Mutable static switch that can be set before GetCacheForProcess is called
93 // and GrContextOptions.fShaderCacheStrategy is set. If true, it means that
94 // we'll set `GrContextOptions::fShaderCacheStrategy` to `kSkSL`, and all the
95 // persistent cache should be stored and loaded from the "sksl" directory.
96 static std::atomic<bool> cache_sksl_;
97
98 // Guard flag to make sure that cache_sksl_ is not modified after
99 // strategy_set_ becomes true.
100 static std::atomic<bool> strategy_set_;
101
102 const bool is_read_only_;
103 const std::shared_ptr<fml::UniqueFD> cache_directory_;
104 const std::shared_ptr<fml::UniqueFD> sksl_cache_directory_;
105 mutable std::mutex worker_task_runners_mutex_;
106 std::multiset<fml::RefPtr<fml::TaskRunner>> worker_task_runners_;
107
108 bool stored_new_shaders_ = false;
109 bool is_dumping_skp_ = false;
110
111 static sk_sp<SkData> LoadFile(const fml::UniqueFD& dir,
112 const std::string& filen_ame);
113
114 bool IsValid() const;
115
116 PersistentCache(bool read_only = false);
117
118 // |GrContextOptions::PersistentCache|
119 void store(const SkData& key, const SkData& data) override;
120
121 fml::RefPtr<fml::TaskRunner> GetWorkerTaskRunner() const;
122
123 FML_DISALLOW_COPY_AND_ASSIGN(PersistentCache);
124};
125
126} // namespace flutter
127
128#endif // FLUTTER_SHELL_COMMON_PERSISTENT_CACHE_H_
129