mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add service protocol to get SkSLs (#17300)
Fixes https://github.com/flutter/flutter/issues/53114
This commit is contained in:
parent
cd974c3471
commit
bb35963050
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user