From 68f6e920370becb8a202ddf64b570100b4ebf2d2 Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Wed, 15 Jul 2026 23:21:18 +0800 Subject: [PATCH 1/4] Support vulkan pileline cache --- engine/src/flutter/shell/platform/embedder/embedder.cc | 2 +- engine/src/flutter/shell/platform/embedder/embedder.h | 5 +++++ .../platform/embedder/embedder_surface_vulkan_impeller.cc | 5 ++++- .../platform/embedder/embedder_surface_vulkan_impeller.h | 3 ++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/engine/src/flutter/shell/platform/embedder/embedder.cc b/engine/src/flutter/shell/platform/embedder/embedder.cc index 41970ce55c6d6..fcd8b6c281b52 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder.cc @@ -683,7 +683,7 @@ InferVulkanPlatformViewCreationCallback( static_cast(config->vulkan.device), config->vulkan.queue_family_index, static_cast(config->vulkan.queue), vulkan_dispatch_table, - view_embedder); + view_embedder,config->vulkan.cache_path); return fml::MakeCopyable( [embedder_surface = std::move(embedder_surface), diff --git a/engine/src/flutter/shell/platform/embedder/embedder.h b/engine/src/flutter/shell/platform/embedder/embedder.h index 5475f275ed112..c88b158d588c1 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.h +++ b/engine/src/flutter/shell/platform/embedder/embedder.h @@ -1059,6 +1059,11 @@ typedef struct { /// that external texture details can be supplied to the engine for subsequent /// composition. FlutterVulkanTextureFrameCallback external_texture_frame_callback; + /// The path to the Vulkan pipeline cache data. + /// The string can be collected after the call to `FlutterEngineRun` returns. + /// The string must be NULL terminated. + /// If NULL, Impeller will not use the Vulkan pipeline cache. + const char* cache_path; } FlutterVulkanRendererConfig; typedef struct { diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc index c19dfcae3fa9f..43845ed0d7cb8 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc @@ -29,7 +29,8 @@ EmbedderSurfaceVulkanImpeller::EmbedderSurfaceVulkanImpeller( uint32_t queue_family_index, VkQueue queue, const VulkanDispatchTable& vulkan_dispatch_table, - std::shared_ptr external_view_embedder) + std::shared_ptr external_view_embedder, + const char* cache_path) : vk_(fml::MakeRefCounted( vulkan_dispatch_table.get_instance_proc_address)), vulkan_dispatch_table_(vulkan_dispatch_table), @@ -54,6 +55,8 @@ EmbedderSurfaceVulkanImpeller::EmbedderSurfaceVulkanImpeller( settings.shader_libraries_data = shader_mappings; settings.proc_address_callback = vulkan_dispatch_table.get_instance_proc_address; + settings.cache_directory = + OpenDirectory(cache_path, false, fml::FilePermission::kRead); impeller::ContextVK::EmbedderData data; data.instance = instance; diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h index 961c3a34ee569..2e0691945a182 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h @@ -39,7 +39,8 @@ class EmbedderSurfaceVulkanImpeller final : public EmbedderSurface, uint32_t queue_family_index, VkQueue queue, const VulkanDispatchTable& vulkan_dispatch_table, - std::shared_ptr external_view_embedder); + std::shared_ptr external_view_embedder, + const char* cache_path); ~EmbedderSurfaceVulkanImpeller() override; From f4ee3e6994bd82e3749de9a8438df0b9b39ff1d7 Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Thu, 16 Jul 2026 00:01:02 +0800 Subject: [PATCH 2/4] Fix code review issue --- .../platform/embedder/embedder_surface_vulkan_impeller.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc index 43845ed0d7cb8..ace586b2dd150 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc @@ -55,8 +55,10 @@ EmbedderSurfaceVulkanImpeller::EmbedderSurfaceVulkanImpeller( settings.shader_libraries_data = shader_mappings; settings.proc_address_callback = vulkan_dispatch_table.get_instance_proc_address; - settings.cache_directory = - OpenDirectory(cache_path, false, fml::FilePermission::kRead); + if (cache_path != nullptr) { + settings.cache_directory = + OpenDirectory(cache_path, false, fml::FilePermission::kRead); + } impeller::ContextVK::EmbedderData data; data.instance = instance; From 1f6bf003ccdcbd164e2097b4ba1fcce27d55e364 Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Thu, 16 Jul 2026 22:27:12 +0800 Subject: [PATCH 3/4] Fix no cache issue --- .../flutter/shell/gpu/gpu_surface_vulkan_impeller.cc | 10 ++++++++++ .../embedder/embedder_surface_vulkan_impeller.cc | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc index e022e8965a8e7..6c4ac54a82051 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -158,6 +158,16 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( impeller::ContextVK& context_vk = impeller::ContextVK::Cast(*impeller_context_); + // The embedder path does not go through + // SurfaceContextVK::AcquireNextSurface (which calls MarkFrameEnd → + // DidAcquireSurfaceFrame). Without this call, the pipeline cache is never + // persisted to disk. Manually call DidAcquireSurfaceFrame to ensure the + // Vulkan pipeline cache is written. + if (auto pipeline_library = context_vk.GetPipelineLibrary()) { + impeller::PipelineLibraryVK::Cast(*pipeline_library) + .DidAcquireSurfaceFrame(); + } + context_vk.DisposeThreadLocalCachedResources(); impeller::vk::Image vk_image = diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc index ace586b2dd150..b3bceb398b8f5 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc @@ -57,7 +57,7 @@ EmbedderSurfaceVulkanImpeller::EmbedderSurfaceVulkanImpeller( vulkan_dispatch_table.get_instance_proc_address; if (cache_path != nullptr) { settings.cache_directory = - OpenDirectory(cache_path, false, fml::FilePermission::kRead); + OpenDirectory(cache_path, false, fml::FilePermission::kReadWrite); } impeller::ContextVK::EmbedderData data; From f5a841962eb0cd2f35be81d9dc94d77d949dceb5 Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Fri, 17 Jul 2026 02:51:42 +0800 Subject: [PATCH 4/4] [vulkan] Move MarkFrameEnd to ContextVK to fix embedder layering violation Promote MarkFrameEnd() from SurfaceContextVK to ContextVK so the embedder path can call it directly instead of manually replicating its logic (which also missed DebugTraceMemoryStatistics). --- .../impeller/renderer/backend/vulkan/context_vk.cc | 8 ++++++++ .../impeller/renderer/backend/vulkan/context_vk.h | 6 ++++++ .../renderer/backend/vulkan/surface_context_vk.cc | 7 +------ .../shell/gpu/gpu_surface_vulkan_impeller.cc | 14 ++++---------- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc index 99d4da1cd2980..47c2fe9677371 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc @@ -727,6 +727,14 @@ void ContextVK::DisposeThreadLocalCachedResources() { command_pool_recycler_->Dispose(); } +void ContextVK::MarkFrameEnd() { + if (auto pipeline_library = GetPipelineLibrary()) { + PipelineLibraryVK::Cast(*pipeline_library).DidAcquireSurfaceFrame(); + } + DisposeThreadLocalCachedResources(); + GetResourceAllocator()->DebugTraceMemoryStatistics(); +} + const std::shared_ptr& ContextVK::GetYUVConversionLibrary() const { return yuv_conversion_library_; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h index 1486a93a676fd..da7de3cb083c9 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h @@ -227,6 +227,12 @@ class ContextVK final : public Context, // |Context| void DisposeThreadLocalCachedResources() override; + /// @brief Perform frame-end maintenance: persist the pipeline cache to + /// disk periodically and dispose thread-local cached resources. + /// Called by SurfaceContextVK::MarkFrameEnd and directly by + /// embedder paths that bypass AcquireNextSurface. + void MarkFrameEnd(); + /// @brief Whether the Android Surface control based swapchain should be /// enabled bool GetShouldEnableSurfaceControlSwapchain() const; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc index e14320f134d5f..aefbce6e67282 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc @@ -99,12 +99,7 @@ std::unique_ptr SurfaceContextVK::AcquireNextSurface() { } void SurfaceContextVK::MarkFrameEnd() { - if (auto pipeline_library = parent_->GetPipelineLibrary()) { - impeller::PipelineLibraryVK::Cast(*pipeline_library) - .DidAcquireSurfaceFrame(); - } - parent_->DisposeThreadLocalCachedResources(); - parent_->GetResourceAllocator()->DebugTraceMemoryStatistics(); + parent_->MarkFrameEnd(); } void SurfaceContextVK::UpdateSurfaceSize(const ISize& size) const { diff --git a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc index 6c4ac54a82051..0aa9b436cc0af 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -159,16 +159,10 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( impeller::ContextVK::Cast(*impeller_context_); // The embedder path does not go through - // SurfaceContextVK::AcquireNextSurface (which calls MarkFrameEnd → - // DidAcquireSurfaceFrame). Without this call, the pipeline cache is never - // persisted to disk. Manually call DidAcquireSurfaceFrame to ensure the - // Vulkan pipeline cache is written. - if (auto pipeline_library = context_vk.GetPipelineLibrary()) { - impeller::PipelineLibraryVK::Cast(*pipeline_library) - .DidAcquireSurfaceFrame(); - } - - context_vk.DisposeThreadLocalCachedResources(); + // SurfaceContextVK::AcquireNextSurface (which calls MarkFrameEnd). + // Call MarkFrameEnd directly to ensure the Vulkan pipeline cache is + // periodically persisted to disk and thread-local resources are cleaned up. + context_vk.MarkFrameEnd(); impeller::vk::Image vk_image = impeller::vk::Image(reinterpret_cast(flutter_image.image));