Skip to content

Commit

Permalink
Read SkSL from json asset (flutter#17861)
Browse files Browse the repository at this point in the history
  • Loading branch information
liyuqian authored Apr 22, 2020
1 parent d3f1c08 commit 31ecf87
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 26 deletions.
61 changes: 48 additions & 13 deletions shell/common/persistent_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions shell/common/persistent_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down
30 changes: 17 additions & 13 deletions shell/common/persistent_cache_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit 31ecf87

Please sign in to comment.