mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Read SkSL from json asset (#17861)
Fixes https://github.com/flutter/flutter/issues/55219
This commit is contained in:
parent
d3f1c08f52
commit
31ecf878aa
@ -8,6 +8,9 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "third_party/skia/include/utils/SkBase64.h"
|
||||
|
||||
#include "flutter/fml/base32.h"
|
||||
#include "flutter/fml/file.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
@ -103,21 +106,35 @@ static std::shared_ptr<fml::UniqueFD> MakeCacheDirectory(
|
||||
}
|
||||
} // namespace
|
||||
|
||||
sk_sp<SkData> ParseBase32(const std::string& input) {
|
||||
std::pair<bool, std::string> decode_result = fml::Base32Decode(input);
|
||||
if (!decode_result.first) {
|
||||
FML_LOG(ERROR) << "Base32 can't decode: " << input;
|
||||
return nullptr;
|
||||
}
|
||||
const std::string& data_string = decode_result.second;
|
||||
return SkData::MakeWithCopy(data_string.data(), data_string.length());
|
||||
}
|
||||
|
||||
sk_sp<SkData> ParseBase64(const std::string& input) {
|
||||
SkBase64 decoder;
|
||||
auto error = decoder.decode(input.c_str(), input.length());
|
||||
if (error != SkBase64::Error::kNoError) {
|
||||
FML_LOG(ERROR) << "Base64 decode error: " << error;
|
||||
FML_LOG(ERROR) << "Base64 can't decode: " << input;
|
||||
return nullptr;
|
||||
}
|
||||
return SkData::MakeWithCopy(decoder.getData(), decoder.getDataSize());
|
||||
}
|
||||
|
||||
std::vector<PersistentCache::SkSLCache> PersistentCache::LoadSkSLs() {
|
||||
TRACE_EVENT0("flutter", "PersistentCache::LoadSkSLs");
|
||||
std::vector<PersistentCache::SkSLCache> result;
|
||||
fml::FileVisitor visitor = [&result](const fml::UniqueFD& directory,
|
||||
const std::string& filename) {
|
||||
std::pair<bool, std::string> decode_result = fml::Base32Decode(filename);
|
||||
if (!decode_result.first) {
|
||||
FML_LOG(ERROR) << "Base32 can't decode: " << filename;
|
||||
return true; // continue to visit other files
|
||||
}
|
||||
const std::string& data_string = decode_result.second;
|
||||
sk_sp<SkData> key =
|
||||
SkData::MakeWithCopy(data_string.data(), data_string.length());
|
||||
sk_sp<SkData> key = ParseBase32(filename);
|
||||
sk_sp<SkData> data = LoadFile(directory, filename);
|
||||
if (data != nullptr) {
|
||||
if (key != nullptr && data != nullptr) {
|
||||
result.push_back({key, data});
|
||||
} else {
|
||||
FML_LOG(ERROR) << "Failed to load: " << filename;
|
||||
@ -136,11 +153,29 @@ std::vector<PersistentCache::SkSLCache> PersistentCache::LoadSkSLs() {
|
||||
fml::FilePermission::kRead);
|
||||
fml::UniqueFD sksl_asset_dir =
|
||||
fml::OpenDirectoryReadOnly(root_asset_dir, kSkSLSubdirName);
|
||||
if (sksl_asset_dir.is_valid()) {
|
||||
FML_LOG(INFO) << "Found sksl asset directory. Loading SkSLs from it...";
|
||||
fml::VisitFiles(sksl_asset_dir, visitor);
|
||||
auto sksl_asset_file = fml::OpenFileReadOnly(sksl_asset_dir, kAssetFileName);
|
||||
if (!sksl_asset_file.is_valid()) {
|
||||
FML_LOG(INFO) << "No sksl asset file found.";
|
||||
} else {
|
||||
FML_LOG(INFO) << "No sksl asset directory found.";
|
||||
FML_LOG(INFO) << "Found sksl asset. Loading SkSLs from it...";
|
||||
auto mapping = std::make_unique<fml::FileMapping>(sksl_asset_file);
|
||||
rapidjson::Document json_doc;
|
||||
rapidjson::ParseResult parse_result =
|
||||
json_doc.Parse(reinterpret_cast<const char*>(mapping->GetMapping()),
|
||||
mapping->GetSize());
|
||||
if (parse_result != rapidjson::ParseErrorCode::kParseErrorNone) {
|
||||
FML_LOG(ERROR) << "Failed to parse json file: " << kAssetFileName;
|
||||
} else {
|
||||
for (auto& item : json_doc["data"].GetObject()) {
|
||||
sk_sp<SkData> key = ParseBase32(item.name.GetString());
|
||||
sk_sp<SkData> sksl = ParseBase64(item.value.GetString());
|
||||
if (key != nullptr && sksl != nullptr) {
|
||||
result.push_back({key, sksl});
|
||||
} else {
|
||||
FML_LOG(ERROR) << "Failed to load: " << item.name.GetString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@ -73,6 +73,7 @@ class PersistentCache : public GrContextOptions::PersistentCache {
|
||||
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_;
|
||||
|
||||
@ -150,23 +150,28 @@ TEST_F(ShellTest, CanLoadSkSLsFromAsset) {
|
||||
auto empty_config = RunConfiguration::InferFromSettings(empty_settings);
|
||||
std::unique_ptr<Shell> empty_shell = CreateShell(empty_settings);
|
||||
|
||||
// The SkSL key is Base32 encoded. "IE" is the encoding of "A" and "II" is the
|
||||
// encoding of "B".
|
||||
//
|
||||
// The SkSL data is Base64 encoded. "eA==" is the encoding of "x" and "eQ=="
|
||||
// is the encoding of "y".
|
||||
const std::string kTestJson =
|
||||
"{\n"
|
||||
" \"data\": {\n"
|
||||
" \"IE\": \"eA==\",\n"
|
||||
" \"II\": \"eQ==\"\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
// Temp dir for the asset.
|
||||
fml::ScopedTemporaryDirectory asset_dir;
|
||||
fml::UniqueFD sksl_asset_dir =
|
||||
fml::OpenDirectory(asset_dir.fd(), PersistentCache::kSkSLSubdirName, true,
|
||||
fml::FilePermission::kReadWrite);
|
||||
|
||||
// The SkSL filenames are Base32 encoded strings. "IE" is the encoding of "A"
|
||||
// and "II" is the encoding of "B".
|
||||
const std::string kFileNames[2] = {"IE", "II"};
|
||||
const std::string kFileData[2] = {"x", "y"};
|
||||
|
||||
// Prepare 2 SkSL files in the asset directory.
|
||||
for (int i = 0; i < 2; i += 1) {
|
||||
auto data = std::make_unique<fml::DataMapping>(
|
||||
std::vector<uint8_t>{kFileData[i].begin(), kFileData[i].end()});
|
||||
fml::WriteAtomically(sksl_asset_dir, kFileNames[i].c_str(), *data);
|
||||
}
|
||||
auto data = std::make_unique<fml::DataMapping>(
|
||||
std::vector<uint8_t>{kTestJson.begin(), kTestJson.end()});
|
||||
fml::WriteAtomically(sksl_asset_dir, PersistentCache::kAssetFileName, *data);
|
||||
|
||||
// 1st, test that RunConfiguration::InferFromSettings sets the path.
|
||||
ResetAssetPath();
|
||||
@ -213,8 +218,7 @@ TEST_F(ShellTest, CanLoadSkSLsFromAsset) {
|
||||
|
||||
// Cleanup.
|
||||
DestroyShell(std::move(empty_shell));
|
||||
fml::UnlinkFile(sksl_asset_dir, kFileNames[0].c_str());
|
||||
fml::UnlinkFile(sksl_asset_dir, kFileNames[1].c_str());
|
||||
fml::UnlinkFile(sksl_asset_dir, PersistentCache::kAssetFileName);
|
||||
fml::UnlinkDirectory(asset_dir.fd(), PersistentCache::kSkSLSubdirName);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user