Skip to content

Commit

Permalink
SKP based shader warmup (flutter#20643)
Browse files Browse the repository at this point in the history
  • Loading branch information
freiling authored Nov 5, 2020
1 parent e66a720 commit 3105db8
Show file tree
Hide file tree
Showing 27 changed files with 443 additions and 19 deletions.
18 changes: 18 additions & 0 deletions assets/asset_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@ std::unique_ptr<fml::Mapping> AssetManager::GetAsMapping(
return nullptr;
}

// |AssetResolver|
std::vector<std::unique_ptr<fml::Mapping>> AssetManager::GetAsMappings(
const std::string& asset_pattern) const {
std::vector<std::unique_ptr<fml::Mapping>> mappings;
if (asset_pattern.size() == 0) {
return mappings;
}
TRACE_EVENT1("flutter", "AssetManager::GetAsMappings", "pattern",
asset_pattern.c_str());
for (const auto& resolver : resolvers_) {
auto resolver_mappings = resolver->GetAsMappings(asset_pattern);
mappings.insert(mappings.end(),
std::make_move_iterator(resolver_mappings.begin()),
std::make_move_iterator(resolver_mappings.end()));
}
return mappings;
}

// |AssetResolver|
bool AssetManager::IsValid() const {
return resolvers_.size() > 0;
Expand Down
4 changes: 4 additions & 0 deletions assets/asset_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class AssetManager final : public AssetResolver {
std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const override;

// |AssetResolver|
std::vector<std::unique_ptr<fml::Mapping>> GetAsMappings(
const std::string& asset_pattern) const override;

private:
std::deque<std::unique_ptr<AssetResolver>> resolvers_;

Expand Down
7 changes: 7 additions & 0 deletions assets/asset_resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ class AssetResolver {
[[nodiscard]] virtual std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const = 0;

// Same as GetAsMapping() but returns mappings for all files who's name
// matches |pattern|. Returns empty vector if no matching assets are found
[[nodiscard]] virtual std::vector<std::unique_ptr<fml::Mapping>>
GetAsMappings(const std::string& asset_pattern) const {
return {};
};

private:
FML_DISALLOW_COPY_AND_ASSIGN(AssetResolver);
};
Expand Down
29 changes: 29 additions & 0 deletions assets/directory_asset_bundle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "flutter/assets/directory_asset_bundle.h"

#include <regex>
#include <utility>

#include "flutter/fml/eintr_wrapper.h"
Expand Down Expand Up @@ -53,4 +54,32 @@ std::unique_ptr<fml::Mapping> DirectoryAssetBundle::GetAsMapping(
return mapping;
}

std::vector<std::unique_ptr<fml::Mapping>> DirectoryAssetBundle::GetAsMappings(
const std::string& asset_pattern) const {
std::vector<std::unique_ptr<fml::Mapping>> mappings;
if (!is_valid_) {
FML_DLOG(WARNING) << "Asset bundle was not valid.";
return mappings;
}

std::regex asset_regex(asset_pattern);
fml::FileVisitor visitor = [&](const fml::UniqueFD& directory,
const std::string& filename) {
if (std::regex_match(filename, asset_regex)) {
auto mapping = std::make_unique<fml::FileMapping>(fml::OpenFile(
directory, filename.c_str(), false, fml::FilePermission::kRead));

if (mapping && mapping->IsValid()) {
mappings.push_back(std::move(mapping));
} else {
FML_LOG(ERROR) << "Mapping " << filename << " failed";
}
}
return true;
};
fml::VisitFilesRecursively(descriptor_, visitor);

return mappings;
}

} // namespace flutter
4 changes: 4 additions & 0 deletions assets/directory_asset_bundle.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class DirectoryAssetBundle : public AssetResolver {
std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const override;

// |AssetResolver|
std::vector<std::unique_ptr<fml::Mapping>> GetAsMappings(
const std::string& asset_pattern) const override;

FML_DISALLOW_COPY_AND_ASSIGN(DirectoryAssetBundle);
};

Expand Down
7 changes: 4 additions & 3 deletions fml/concurrent_message_loop.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "flutter/fml/closure.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/task_runner.h"

namespace fml {

Expand Down Expand Up @@ -58,13 +59,13 @@ class ConcurrentMessageLoop
FML_DISALLOW_COPY_AND_ASSIGN(ConcurrentMessageLoop);
};

class ConcurrentTaskRunner {
class ConcurrentTaskRunner : public BasicTaskRunner {
public:
ConcurrentTaskRunner(std::weak_ptr<ConcurrentMessageLoop> weak_loop);

~ConcurrentTaskRunner();
virtual ~ConcurrentTaskRunner();

void PostTask(const fml::closure& task);
void PostTask(const fml::closure& task) override;

private:
friend ConcurrentMessageLoop;
Expand Down
10 changes: 8 additions & 2 deletions fml/task_runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@ namespace fml {

class MessageLoopImpl;

class TaskRunner : public fml::RefCountedThreadSafe<TaskRunner> {
class BasicTaskRunner {
public:
virtual void PostTask(const fml::closure& task) = 0;
};

class TaskRunner : public fml::RefCountedThreadSafe<TaskRunner>,
public BasicTaskRunner {
public:
virtual ~TaskRunner();

virtual void PostTask(const fml::closure& task);
virtual void PostTask(const fml::closure& task) override;

virtual void PostTaskForTime(const fml::closure& task,
fml::TimePoint target_time);
Expand Down
10 changes: 10 additions & 0 deletions shell/common/persistent_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -391,4 +391,14 @@ void PersistentCache::SetAssetManager(std::shared_ptr<AssetManager> value) {
asset_manager_ = value;
}

std::vector<std::unique_ptr<fml::Mapping>>
PersistentCache::GetSkpsFromAssetManager() const {
if (!asset_manager_) {
FML_LOG(ERROR)
<< "PersistentCache::GetSkpsFromAssetManager: Asset manager not set!";
return std::vector<std::unique_ptr<fml::Mapping>>();
}
return asset_manager_->GetAsMappings(".*\\.skp$");
}

} // namespace flutter
3 changes: 3 additions & 0 deletions shell/common/persistent_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class PersistentCache : public GrContextOptions::PersistentCache {
/// Load all the SkSL shader caches in the right directory.
std::vector<SkSLCache> LoadSkSLs();

// Return mappings for all skp's accessible through the AssetManager
std::vector<std::unique_ptr<fml::Mapping>> GetSkpsFromAssetManager() const;

/// Set the asset manager from which PersistentCache can load SkLSs. A nullptr
/// can be provided to clear the asset manager.
static void SetAssetManager(std::shared_ptr<AssetManager> value);
Expand Down
1 change: 1 addition & 0 deletions shell/common/rasterizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ static sk_sp<SkData> ScreenshotLayerTreeAsPicture(
#if defined(OS_FUCHSIA)
SkSerialProcs procs = {0};
procs.fImageProc = SerializeImageWithoutData;
procs.fTypefaceProc = SerializeTypefaceWithoutData;
#else
SkSerialProcs procs = {0};
procs.fTypefaceProc = SerializeTypefaceWithData;
Expand Down
9 changes: 8 additions & 1 deletion shell/common/serialization_callbacks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@
#include "flutter/fml/logging.h"
#include "include/core/SkImage.h"
#include "include/core/SkPicture.h"
#include "include/core/SkSerialProcs.h"
#include "include/core/SkStream.h"
#include "include/core/SkTypeface.h"

namespace flutter {

sk_sp<SkData> SerializeTypefaceWithoutData(SkTypeface* typeface, void* ctx) {
return typeface->serialize(SkTypeface::SerializeBehavior::kDontIncludeData);
return SkData::MakeEmpty();
}

sk_sp<SkData> SerializeTypefaceWithData(SkTypeface* typeface, void* ctx) {
return typeface->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
}

sk_sp<SkTypeface> DeserializeTypefaceWithoutData(const void* data,
size_t length,
void* ctx) {
return SkTypeface::MakeDefault();
}

struct ImageMetaData {
int32_t width;
int32_t height;
Expand Down
3 changes: 3 additions & 0 deletions shell/common/serialization_callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ namespace flutter {

sk_sp<SkData> SerializeTypefaceWithoutData(SkTypeface* typeface, void* ctx);
sk_sp<SkData> SerializeTypefaceWithData(SkTypeface* typeface, void* ctx);
sk_sp<SkTypeface> DeserializeTypefaceWithoutData(const void* data,
size_t length,
void* ctx);

// Serializes only the metadata of the image and not the underlying pixel data.
sk_sp<SkData> SerializeImageWithoutData(SkImage* image, void* ctx);
Expand Down
68 changes: 68 additions & 0 deletions shell/common/shell_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <future>
#include <memory>

#include "assets/directory_asset_bundle.h"
#include "flutter/flow/layers/layer_tree.h"
#include "flutter/flow/layers/picture_layer.h"
#include "flutter/flow/layers/transform_layer.h"
Expand Down Expand Up @@ -2208,5 +2209,72 @@ TEST_F(ShellTest, EngineRootIsolateLaunchesDontTakeVMDataSettings) {
isolate_create_latch.Wait();
}

TEST_F(ShellTest, AssetManagerSingle) {
fml::ScopedTemporaryDirectory asset_dir;
fml::UniqueFD asset_dir_fd = fml::OpenDirectory(
asset_dir.path().c_str(), false, fml::FilePermission::kRead);

std::string filename = "test_name";
std::string content = "test_content";

bool success = fml::WriteAtomically(asset_dir_fd, filename.c_str(),
fml::DataMapping(content));
ASSERT_TRUE(success);

AssetManager asset_manager;
asset_manager.PushBack(
std::make_unique<DirectoryAssetBundle>(std::move(asset_dir_fd), false));

auto mapping = asset_manager.GetAsMapping(filename);
ASSERT_TRUE(mapping != nullptr);

std::string result(reinterpret_cast<const char*>(mapping->GetMapping()),
mapping->GetSize());

ASSERT_TRUE(result == content);
}

TEST_F(ShellTest, AssetManagerMulti) {
fml::ScopedTemporaryDirectory asset_dir;
fml::UniqueFD asset_dir_fd = fml::OpenDirectory(
asset_dir.path().c_str(), false, fml::FilePermission::kRead);

std::vector<std::string> filenames = {
"good0",
"bad0",
"good1",
"bad1",
};

for (auto filename : filenames) {
bool success = fml::WriteAtomically(asset_dir_fd, filename.c_str(),
fml::DataMapping(filename));
ASSERT_TRUE(success);
}

AssetManager asset_manager;
asset_manager.PushBack(
std::make_unique<DirectoryAssetBundle>(std::move(asset_dir_fd), false));

auto mappings = asset_manager.GetAsMappings("(.*)");
ASSERT_TRUE(mappings.size() == 4);

std::vector<std::string> expected_results = {
"good0",
"good1",
};

mappings = asset_manager.GetAsMappings("(.*)good(.*)");
ASSERT_TRUE(mappings.size() == expected_results.size());

for (auto& mapping : mappings) {
std::string result(reinterpret_cast<const char*>(mapping->GetMapping()),
mapping->GetSize());
ASSERT_NE(
std::find(expected_results.begin(), expected_results.end(), result),
expected_results.end());
}
}

} // namespace testing
} // namespace flutter
59 changes: 56 additions & 3 deletions shell/common/skp_shader_warmup_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,19 @@
#include "flutter/shell/common/switches.h"
#include "flutter/shell/version/version.h"
#include "flutter/testing/testing.h"
#include "include/core/SkFont.h"
#include "include/core/SkPicture.h"
#include "include/core/SkPictureRecorder.h"
#include "include/core/SkSerialProcs.h"
#include "include/core/SkTextBlob.h"

#if defined(OS_FUCHSIA)
#include "lib/sys/cpp/component_context.h"
#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h"

namespace flutter {
namespace testing {

#if defined(OS_FUCHSIA)

static void WaitForIO(Shell* shell) {
std::promise<bool> io_task_finished;
shell->GetTaskRunners().GetIOTaskRunner()->PostTask(
Expand Down Expand Up @@ -103,8 +107,13 @@ class SkpWarmupTest : public ShellTest {

SkDeserialProcs procs = {0};
procs.fImageProc = DeserializeImageWithoutData;
procs.fTypefaceProc = DeserializeTypefaceWithoutData;
sk_sp<SkPicture> picture =
SkPicture::MakeFromStream(stream.get(), &procs);
if (!picture) {
FML_LOG(ERROR) << "Failed to deserialize " << filename;
return true;
}
pictures.push_back(std::move(picture));
fd.reset();
}
Expand Down Expand Up @@ -242,7 +251,51 @@ TEST_F(SkpWarmupTest, Image) {
TestWarmup(draw_size, builder);
}

#endif
// Re-enable once https://bugs.chromium.org/p/skia/issues/detail?id=10404
// is fixed and integrated, or a workaround is found.
TEST_F(SkpWarmupTest, DISABLED_Text) {
auto context = sys::ComponentContext::Create();
fuchsia::fonts::ProviderSyncPtr sync_font_provider;
context->svc()->Connect(sync_font_provider.NewRequest());
auto font_mgr = SkFontMgr_New_Fuchsia(std::move(sync_font_provider));
auto raw_typeface =
font_mgr->matchFamilyStyle(nullptr, SkFontStyle::Normal());
auto typeface = sk_sp<SkTypeface>(raw_typeface);

SkFont font(typeface, 12);
auto text_blob =
SkTextBlob::MakeFromString("test", font, SkTextEncoding::kUTF8);

SkISize draw_size =
SkISize::Make(text_blob->bounds().width(), text_blob->bounds().height());
// We reuse this builder to draw the same content sever times in this test
LayerTreeBuilder builder = [&draw_size, &text_blob,
this](std::shared_ptr<ContainerLayer> root) {
SkPictureRecorder recorder;

auto canvas =
recorder.beginRecording(draw_size.width(), draw_size.height());

auto color_space = SkColorSpace::MakeSRGB();
auto paint = SkPaint(SkColors::kWhite, color_space.get());
canvas->drawTextBlob(text_blob, draw_size.width() / 2,
draw_size.height() / 2, paint);

auto picture = recorder.finishRecordingAsPicture();

fml::RefPtr<SkiaUnrefQueue> queue = fml::MakeRefCounted<SkiaUnrefQueue>(
this->GetCurrentTaskRunner(), fml::TimeDelta::FromSeconds(0));
auto picture_layer = std::make_shared<PictureLayer>(
SkPoint::Make(0, 0), SkiaGPUObject<SkPicture>(picture, queue),
/* is_complex */ false,
/* will_change */ false);
root->Add(picture_layer);
};

TestWarmup(draw_size, builder);
}

} // namespace testing
} // namespace flutter

#endif // defined(OS_FUCHSIA)
Loading

0 comments on commit 3105db8

Please sign in to comment.