Freiling warmup memory (flutter/engine#22984)

* [fuchsia] enable boot time shader warmup even when LEGACY_FUCHSIA_EMBEDDER is defined

* [fuchsia] decouple shader warmup from embedder api

* [fuchsia] change warmup context flush() to flushAndSubmit() to reduce memory footprint of warmup

* [fuchsia] Fix GPU resource lifecycle issue with shader warmup

This fixes an issue with the shader warmup where gpu resources could end
up deleted before the gpu work that needed them was complete, leading to
GPU page faults. This was because although the sk_sp<SkSurface> will normally
keep resources alive throughout its lifetime, the SurfaceProducerSurface will
call VkDestroyMemory on the memory backing the SkSurface when it is deleted,
even if the SkSurface wrapping that VkMemory is still alive.

This change also deletes some related but unused code from
CompositorContext that I noticed while refactoring.
This commit is contained in:
freiling 2020-12-10 15:27:44 -08:00 committed by GitHub
parent 1c54e6cc84
commit 879027fc8f
5 changed files with 64 additions and 28 deletions

View File

@ -154,13 +154,7 @@ CompositorContext::CompositorContext(
std::shared_ptr<flutter::SceneUpdateContext> scene_update_context)
: session_connection_(session_connection),
surface_producer_(surface_producer),
scene_update_context_(scene_update_context) {
SkISize size = SkISize::Make(1024, 600);
skp_warmup_surface_ = surface_producer_.ProduceOffscreenSurface(size);
if (!skp_warmup_surface_) {
FML_LOG(ERROR) << "SkSurface::MakeRenderTarget returned null";
}
}
scene_update_context_(scene_update_context) {}
CompositorContext::~CompositorContext() = default;
@ -179,9 +173,4 @@ CompositorContext::AcquireFrame(
session_connection_, surface_producer_, scene_update_context_);
}
void CompositorContext::WarmupSkp(const sk_sp<SkPicture> picture) {
skp_warmup_surface_->getCanvas()->drawPicture(picture);
surface_producer_.gr_context()->flush();
}
} // namespace flutter_runner

View File

@ -27,13 +27,11 @@ class CompositorContext final : public flutter::CompositorContext {
std::shared_ptr<flutter::SceneUpdateContext> scene_update_context);
~CompositorContext() override;
void WarmupSkp(sk_sp<SkPicture> picture);
private:
SessionConnection& session_connection_;
VulkanSurfaceProducer& surface_producer_;
std::shared_ptr<flutter::SceneUpdateContext> scene_update_context_;
sk_sp<SkSurface> skp_warmup_surface_;
// |flutter::CompositorContext|
std::unique_ptr<ScopedFrame> AcquireFrame(

View File

@ -250,12 +250,22 @@ Engine::Engine(Delegate& delegate,
// Setup the callback that will instantiate the rasterizer.
flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer;
#if defined(LEGACY_FUCHSIA_EMBEDDER)
on_create_rasterizer = [this](flutter::Shell& shell) {
on_create_rasterizer = [this, &product_config](flutter::Shell& shell) {
if (use_legacy_renderer_) {
FML_DCHECK(session_connection_);
FML_DCHECK(surface_producer_);
FML_DCHECK(legacy_external_view_embedder_);
if (product_config.enable_shader_warmup()) {
FML_DCHECK(surface_producer_);
WarmupSkps(shell.GetDartVM()
->GetConcurrentMessageLoop()
->GetTaskRunner()
.get(),
shell.GetTaskRunners().GetRasterTaskRunner().get(),
surface_producer_.value());
}
auto compositor_context =
std::make_unique<flutter_runner::CompositorContext>(
session_connection_.value(), surface_producer_.value(),
@ -263,6 +273,15 @@ Engine::Engine(Delegate& delegate,
return std::make_unique<flutter::Rasterizer>(
shell, std::move(compositor_context));
} else {
if (product_config.enable_shader_warmup()) {
FML_DCHECK(surface_producer_);
WarmupSkps(shell.GetDartVM()
->GetConcurrentMessageLoop()
->GetTaskRunner()
.get(),
shell.GetTaskRunners().GetRasterTaskRunner().get(),
surface_producer_.value());
}
return std::make_unique<flutter::Rasterizer>(shell);
}
};
@ -641,9 +660,13 @@ void Engine::WarmupSkps(fml::BasicTaskRunner* concurrent_task_runner,
fml::BasicTaskRunner* raster_task_runner,
VulkanSurfaceProducer& surface_producer) {
SkISize size = SkISize::Make(1024, 600);
auto skp_warmup_surface = surface_producer.ProduceOffscreenSurface(size);
// We use a raw pointer here because we want to keep this alive until all gpu
// work is done and the callbacks skia takes for this are function pointers
// so we are unable to use a lambda that captures the smart pointer.
SurfaceProducerSurface* skp_warmup_surface =
surface_producer.ProduceOffscreenSurface(size).release();
if (!skp_warmup_surface) {
FML_LOG(ERROR) << "SkSurface::MakeRenderTarget returned null";
FML_LOG(ERROR) << "Failed to create offscreen warmup surface";
return;
}
@ -655,8 +678,17 @@ void Engine::WarmupSkps(fml::BasicTaskRunner* concurrent_task_runner,
std::vector<std::unique_ptr<fml::Mapping>> skp_mappings =
flutter::PersistentCache::GetCacheForProcess()
->GetSkpsFromAssetManager();
size_t total_size = 0;
for (auto& mapping : skp_mappings) {
total_size += mapping->GetSize();
}
FML_LOG(INFO) << "Shader warmup got " << skp_mappings.size()
<< " skp's with a total size of " << total_size << " bytes";
std::vector<sk_sp<SkPicture>> pictures;
int i = 0;
unsigned int i = 0;
for (auto& mapping : skp_mappings) {
std::unique_ptr<SkMemoryStream> stream =
SkMemoryStream::MakeDirect(mapping->GetMapping(), mapping->GetSize());
@ -672,12 +704,28 @@ void Engine::WarmupSkps(fml::BasicTaskRunner* concurrent_task_runner,
// Tell raster task runner to warmup have the compositor
// context warm up the newly deserialized picture
raster_task_runner->PostTask(
[skp_warmup_surface, picture, &surface_producer] {
TRACE_DURATION("flutter", "WarmupSkp");
skp_warmup_surface->getCanvas()->drawPicture(picture);
surface_producer.gr_context()->flush();
});
raster_task_runner->PostTask([skp_warmup_surface, picture,
&surface_producer, i,
count = skp_mappings.size()] {
TRACE_DURATION("flutter", "WarmupSkp");
skp_warmup_surface->GetSkiaSurface()->getCanvas()->drawPicture(picture);
if (i < count - 1) {
// For all but the last skp we fire and forget
surface_producer.gr_context()->flushAndSubmit();
} else {
// For the last skp we provide a callback that frees the warmup
// surface
struct GrFlushInfo flush_info;
flush_info.fFinishedContext = skp_warmup_surface;
flush_info.fFinishedProc = [](void* skp_warmup_surface) {
delete static_cast<SurfaceProducerSurface*>(skp_warmup_surface);
};
surface_producer.gr_context()->flush(flush_info);
surface_producer.gr_context()->submit();
}
});
i++;
}
});

View File

@ -271,9 +271,9 @@ void VulkanSurfaceProducer::SubmitSurface(
surface_pool_->SubmitSurface(std::move(surface));
}
sk_sp<SkSurface> VulkanSurfaceProducer::ProduceOffscreenSurface(
const SkISize& size) {
return surface_pool_->CreateSurface(size)->GetSkiaSurface();
std::unique_ptr<SurfaceProducerSurface>
VulkanSurfaceProducer::ProduceOffscreenSurface(const SkISize& size) {
return surface_pool_->CreateSurface(size);
}
} // namespace flutter_runner

View File

@ -35,7 +35,8 @@ class VulkanSurfaceProducer final : public SurfaceProducer,
std::unique_ptr<SurfaceProducerSurface> ProduceSurface(
const SkISize& size) override;
sk_sp<SkSurface> ProduceOffscreenSurface(const SkISize& size);
std::unique_ptr<SurfaceProducerSurface> ProduceOffscreenSurface(
const SkISize& size);
// |SurfaceProducer|
void SubmitSurface(std::unique_ptr<SurfaceProducerSurface> surface) override;