mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Delete command pools held by the CommandPoolRecyclerVK after decoding an image on the IO thread (flutter/engine#55398)
In the Vulkan backend, the CommandPoolRecyclerVK stores command pools that can be reused while rendering a frame. For each frame, SurfaceContextVK::AcquireNextSurface calls CommandPoolRecyclerVK::Dispose to clear the cached pools. However, the CommandPoolRecyclerVK's cache of pools is placed in thread-local storage. So command pools used on the IO thread will not be cleaned up if frame rendering calls Dispose on the raster thread. This PR adds a Context API that the IO thread can call after using a command pool in order to ensure that cached resources are disposed. Fixes https://github.com/flutter/flutter/issues/155519
This commit is contained in:
parent
d8edec8449
commit
d333cf4224
@ -608,6 +608,10 @@ void ContextVK::InitializeCommonlyUsedShadersIfNeeded() const {
|
||||
auto pass = builder.Build(GetDevice());
|
||||
}
|
||||
|
||||
void ContextVK::DisposeThreadLocalCachedResources() {
|
||||
command_pool_recycler_->Dispose();
|
||||
}
|
||||
|
||||
const std::shared_ptr<YUVConversionLibraryVK>&
|
||||
ContextVK::GetYUVConversionLibrary() const {
|
||||
return yuv_conversion_library_;
|
||||
|
||||
@ -167,8 +167,12 @@ class ContextVK final : public Context,
|
||||
|
||||
void RecordFrameEndTime() const;
|
||||
|
||||
// |Context|
|
||||
void InitializeCommonlyUsedShadersIfNeeded() const override;
|
||||
|
||||
// |Context|
|
||||
void DisposeThreadLocalCachedResources() override;
|
||||
|
||||
/// @brief Whether the Android Surface control based swapchain should be
|
||||
/// disabled, even if the device is capable of supporting it.
|
||||
bool GetShouldDisableSurfaceControlSwapchain() const;
|
||||
|
||||
@ -72,6 +72,25 @@ TEST(ContextVKTest, DeletesCommandPoolsOnAllThreads) {
|
||||
ASSERT_FALSE(weak_pool_thread.lock());
|
||||
}
|
||||
|
||||
TEST(ContextVKTest, ThreadLocalCleanupDeletesCommandPool) {
|
||||
std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
|
||||
|
||||
fml::AutoResetWaitableEvent latch1, latch2;
|
||||
std::weak_ptr<CommandPoolVK> weak_pool;
|
||||
std::thread thread([&]() {
|
||||
weak_pool = context->GetCommandPoolRecycler()->Get();
|
||||
context->DisposeThreadLocalCachedResources();
|
||||
latch1.Signal();
|
||||
latch2.Wait();
|
||||
});
|
||||
|
||||
latch1.Wait();
|
||||
ASSERT_FALSE(weak_pool.lock());
|
||||
|
||||
latch2.Signal();
|
||||
thread.join();
|
||||
}
|
||||
|
||||
TEST(ContextVKTest, DeletePipelineAfterContext) {
|
||||
std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline;
|
||||
std::shared_ptr<std::vector<std::string>> functions;
|
||||
|
||||
@ -103,6 +103,10 @@ void SurfaceContextVK::InitializeCommonlyUsedShadersIfNeeded() const {
|
||||
parent_->InitializeCommonlyUsedShadersIfNeeded();
|
||||
}
|
||||
|
||||
void SurfaceContextVK::DisposeThreadLocalCachedResources() {
|
||||
parent_->DisposeThreadLocalCachedResources();
|
||||
}
|
||||
|
||||
const std::shared_ptr<ContextVK>& SurfaceContextVK::GetParent() const {
|
||||
return parent_;
|
||||
}
|
||||
|
||||
@ -80,8 +80,12 @@ class SurfaceContextVK : public Context,
|
||||
/// recreated on the next frame.
|
||||
void UpdateSurfaceSize(const ISize& size) const;
|
||||
|
||||
// |Context|
|
||||
void InitializeCommonlyUsedShadersIfNeeded() const override;
|
||||
|
||||
// |Context|
|
||||
void DisposeThreadLocalCachedResources() override;
|
||||
|
||||
const vk::Device& GetDevice() const;
|
||||
|
||||
const std::shared_ptr<ContextVK>& GetParent() const;
|
||||
|
||||
@ -196,6 +196,13 @@ class Context {
|
||||
/// shader variants, as well as forcing driver initialization.
|
||||
virtual void InitializeCommonlyUsedShadersIfNeeded() const {}
|
||||
|
||||
/// Dispose resources that are cached on behalf of the current thread.
|
||||
///
|
||||
/// Some backends such as Vulkan may cache resources that can be reused while
|
||||
/// executing a rendering operation. This API can be called after the
|
||||
/// operation completes in order to clear the cache.
|
||||
virtual void DisposeThreadLocalCachedResources() {}
|
||||
|
||||
protected:
|
||||
Context();
|
||||
|
||||
|
||||
@ -382,6 +382,8 @@ ImageDecoderImpeller::UnsafeUploadTextureToPrivate(
|
||||
return std::make_pair(nullptr, decode_error);
|
||||
}
|
||||
|
||||
context->DisposeThreadLocalCachedResources();
|
||||
|
||||
return std::make_pair(
|
||||
impeller::DlImageImpeller::Make(std::move(result_texture)),
|
||||
std::string());
|
||||
|
||||
@ -188,6 +188,8 @@ void ImageEncodingImpeller::ConvertDlImageToSkImage(
|
||||
.ok()) {
|
||||
FML_LOG(ERROR) << "Failed to submit commands.";
|
||||
}
|
||||
|
||||
impeller_context->DisposeThreadLocalCachedResources();
|
||||
}
|
||||
|
||||
void ImageEncodingImpeller::ConvertImageToRaster(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user