未验证 提交 bb359630 编写于 作者: L liyuqian 提交者: GitHub

Add service protocol to get SkSLs (#17300)

Fixes https://github.com/flutter/flutter/issues/53114
上级 cd974c34
......@@ -33,6 +33,8 @@ const std::string_view ServiceProtocol::kSetAssetBundlePathExtensionName =
"_flutter.setAssetBundlePath";
const std::string_view ServiceProtocol::kGetDisplayRefreshRateExtensionName =
"_flutter.getDisplayRefreshRate";
const std::string_view ServiceProtocol::kGetSkSLsExtensionName =
"_flutter.getSkSLs";
static constexpr std::string_view kViewIdPrefx = "_flutterView/";
static constexpr std::string_view kListViewsExtensionName =
......@@ -50,6 +52,7 @@ ServiceProtocol::ServiceProtocol()
kFlushUIThreadTasksExtensionName,
kSetAssetBundlePathExtensionName,
kGetDisplayRefreshRateExtensionName,
kGetSkSLsExtensionName,
}),
handlers_mutex_(fml::SharedMutex::Create()) {}
......
......@@ -27,6 +27,7 @@ class ServiceProtocol {
static const std::string_view kFlushUIThreadTasksExtensionName;
static const std::string_view kSetAssetBundlePathExtensionName;
static const std::string_view kGetDisplayRefreshRateExtensionName;
static const std::string_view kGetSkSLsExtensionName;
class Handler {
public:
......
......@@ -24,7 +24,7 @@ std::string PersistentCache::cache_base_path_;
std::mutex PersistentCache::instance_mutex_;
std::unique_ptr<PersistentCache> PersistentCache::gPersistentCache;
static std::string SkKeyToFilePath(const SkData& data) {
std::string PersistentCache::SkKeyToFilePath(const SkData& data) {
if (data.data() == nullptr || data.size() == 0) {
return "";
}
......
......@@ -32,8 +32,16 @@ class PersistentCache : public GrContextOptions::PersistentCache {
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& data);
~PersistentCache() override;
void AddWorkerTaskRunner(fml::RefPtr<fml::TaskRunner> task_runner);
......
......@@ -30,6 +30,7 @@
#include "rapidjson/writer.h"
#include "third_party/dart/runtime/include/dart_tools_api.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/utils/SkBase64.h"
#include "third_party/tonic/common/log.h"
namespace flutter {
......@@ -373,6 +374,10 @@ Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings)
task_runners_.GetUITaskRunner(),
std::bind(&Shell::OnServiceProtocolGetDisplayRefreshRate, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_[ServiceProtocol::kGetSkSLsExtensionName] = {
task_runners_.GetIOTaskRunner(),
std::bind(&Shell::OnServiceProtocolGetSkSLs, this, std::placeholders::_1,
std::placeholders::_2)};
}
Shell::~Shell() {
......@@ -1341,6 +1346,32 @@ bool Shell::OnServiceProtocolGetDisplayRefreshRate(
return true;
}
bool Shell::OnServiceProtocolGetSkSLs(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetIOTaskRunner()->RunsTasksOnCurrentThread());
response.SetObject();
response.AddMember("type", "GetSkSLs", response.GetAllocator());
rapidjson::Value shaders_json(rapidjson::kObjectType);
PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
std::vector<PersistentCache::SkSLCache> sksls = persistent_cache->LoadSkSLs();
for (const auto& sksl : sksls) {
size_t b64_size =
SkBase64::Encode(sksl.second->data(), sksl.second->size(), nullptr);
sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
char* b64_char = static_cast<char*>(b64_data->writable_data());
SkBase64::Encode(sksl.second->data(), sksl.second->size(), b64_char);
b64_char[b64_size] = 0; // make it null terminated for printing
rapidjson::Value shader_value(b64_char, response.GetAllocator());
rapidjson::Value shader_key(PersistentCache::SkKeyToFilePath(*sksl.first),
response.GetAllocator());
shaders_json.AddMember(shader_key, shader_value, response.GetAllocator());
}
response.AddMember("SkSLs", shaders_json, response.GetAllocator());
return true;
}
// Service protocol handler
bool Shell::OnServiceProtocolSetAssetBundlePath(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
......
......@@ -561,6 +561,13 @@ class Shell final : public PlatformView::Delegate,
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
//
// The returned SkSLs are base64 encoded. Decode before storing them to files.
bool OnServiceProtocolGetSkSLs(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
fml::WeakPtrFactory<Shell> weak_factory_;
// For accessing the Shell via the GPU thread, necessary for various
......
......@@ -202,6 +202,20 @@ bool ShellTest::GetNeedsReportTimings(Shell* shell) {
return shell->needs_report_timings_;
}
void ShellTest::OnServiceProtocolGetSkSLs(
Shell* shell,
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
std::promise<bool> finished;
fml::TaskRunner::RunNowOrPostTask(shell->GetTaskRunners().GetIOTaskRunner(),
[shell, params, &response, &finished]() {
shell->OnServiceProtocolGetSkSLs(
params, response);
finished.set_value(true);
});
finished.get_future().wait();
}
std::shared_ptr<txt::FontCollection> ShellTest::GetFontCollection(
Shell* shell) {
return shell->weak_engine_->GetFontCollection().GetFontCollection();
......
......@@ -72,6 +72,14 @@ class ShellTest : public ThreadTest {
static bool GetNeedsReportTimings(Shell* shell);
static void SetNeedsReportTimings(Shell* shell, bool value);
// Helper method to test private method Shell::OnServiceProtocolGetSkSLs.
// (ShellTest is a friend class of Shell.) We'll also make sure that it is
// running on the UI thread.
static void OnServiceProtocolGetSkSLs(
Shell* shell,
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
std::shared_ptr<txt::FontCollection> GetFontCollection(Shell* shell);
// Do not assert |UnreportedTimingsCount| to be positive in any tests.
......
......@@ -19,6 +19,7 @@
#include "flutter/fml/synchronization/count_down_latch.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/shell/common/persistent_cache.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/shell_test.h"
......@@ -26,7 +27,9 @@
#include "flutter/shell/common/switches.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/shell/common/vsync_waiter_fallback.h"
#include "flutter/shell/version/version.h"
#include "flutter/testing/testing.h"
#include "rapidjson/writer.h"
#include "third_party/tonic/converter/dart_converter.h"
namespace flutter {
......@@ -1129,5 +1132,57 @@ TEST_F(ShellTest, CanDecompressImageFromAsset) {
DestroyShell(std::move(shell));
}
TEST_F(ShellTest, OnServiceProtocolGetSkSLsWorks) {
// Create 2 dummpy SkSL cache file IE (base32 encoding of A), II (base32
// encoding of B) with content x and y.
fml::ScopedTemporaryDirectory temp_dir;
PersistentCache::SetCacheDirectoryPath(temp_dir.path());
PersistentCache::ResetCacheForProcess();
std::vector<std::string> components = {"flutter_engine",
GetFlutterEngineVersion(), "skia",
GetSkiaVersion(), "sksl"};
auto sksl_dir = fml::CreateDirectory(temp_dir.fd(), components,
fml::FilePermission::kReadWrite);
const std::string x = "x";
const std::string y = "y";
auto x_data = std::make_unique<fml::DataMapping>(
std::vector<uint8_t>{x.begin(), x.end()});
auto y_data = std::make_unique<fml::DataMapping>(
std::vector<uint8_t>{y.begin(), y.end()});
ASSERT_TRUE(fml::WriteAtomically(sksl_dir, "IE", *x_data));
ASSERT_TRUE(fml::WriteAtomically(sksl_dir, "II", *y_data));
Settings settings = CreateSettingsForFixture();
std::unique_ptr<Shell> shell = CreateShell(settings);
ServiceProtocol::Handler::ServiceProtocolMap empty_params;
rapidjson::Document document;
OnServiceProtocolGetSkSLs(shell.get(), empty_params, document);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
document.Accept(writer);
DestroyShell(std::move(shell));
// Base64 encoding of x, y are eQ, eA.
ASSERT_STREQ(
buffer.GetString(),
"{\"type\":\"GetSkSLs\",\"SkSLs\":{\"II\":\"eQ==\",\"IE\":\"eA==\"}}");
// Cleanup files
fml::FileVisitor recursive_cleanup = [&recursive_cleanup](
const fml::UniqueFD& directory,
const std::string& filename) {
if (fml::IsDirectory(directory, filename.c_str())) {
fml::UniqueFD sub_dir =
OpenDirectoryReadOnly(directory, filename.c_str());
VisitFiles(sub_dir, recursive_cleanup);
fml::UnlinkDirectory(directory, filename.c_str());
} else {
fml::UnlinkFile(directory, filename.c_str());
}
return true;
};
VisitFiles(temp_dir.fd(), recursive_cleanup);
}
} // namespace testing
} // namespace flutter
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册