From 2ef107150286216da46c72c35dd46f47cc0fa992 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Fri, 9 Jan 2026 14:11:38 -0800 Subject: [PATCH 1/8] Re-prioritize pipeline compile jobs and perform them eagerly instead of waiting. (#180022) Also, removes "lazy shader mode" and re-enables eager PSO pre-flight. Impeller eagerly sets up the entire set of pipeline state objects (PSOs) it may need during renderer setup. This works fine on mid to high-end devices as the setup completes well before the first frame is rendered. However on low-end devices, not all PSOs may be ready before the first frame is rendered. Low-end device usually don't have as much available concurrency and are slower to boot. On these devices, the rendering thread had to wait for the background compile job to be completed. It was also observed that the relatively higher priority render thread was waiting on a background thread to finish a PSO compile job. The PSO compile job could also be stuck behind another job that was not immediately needed. This made the situation on low end devices less than ideal. To ameliorate this situation, a stop-gap was introduced called "lazy shader mode". This disabled PSO pre-flight entirely and only dispatched jobs when they were needed. This ameliorated somewhat the issue of unneeded jobs blocking the eagerly needed job but the other issues remained. It also meant that one could expect jank the first time a new PSO was needed. This mode was not widely used or advertised. In this patch, the lazy shader mode has been entirely removed and eager PSO pre-flight is the default in all configurations. Pipeline compile jobs are now handled by a separate compile queue. This queue operates like a transparent concurrent worker pool job dispatcher in the usual case. However, when the pipeline for a specific descriptor is needed, instead of waiting for the job to complete, the queue allows the job for that descriptor to skip to the head of the queue and be performed on the calling thread. This effectively make the calling thread do the job instead of waiting. Another nice side effect of this behavior is that the higher priority thread is now doing the job it was previously waiting on. This fixes all issues on lower end devices except one. During eager pre-flight, it would still be better if PSO compile jobs for that were somehow divined to be needed first were towards the front of the pre-flight queue. After all, only a handful of rendering features account for the majority of rendering operations. A future augmentation to the compile queue would be to allow higher prioritization of more widely used pipeline compile jobs as instrumented in https://github.com/flutter/flutter/issues/176660. This task is tracked in https://github.com/flutter/flutter/issues/176665. This patch only wires up the compile queue for Vulkan. https://github.com/flutter/flutter/issues/176657 tracks doing the same for OpenGL. The efficacy of the re-prioritizations can be traced using the PrioritiesElevated trace counter. On higher end devices, there should be zero of these. Fixes https://github.com/flutter/flutter/issues/176656 Fixes https://github.com/flutter/flutter/issues/176663 Fixes https://github.com/flutter/flutter/issues/176658 --- engine/src/flutter/impeller/base/flags.h | 3 - .../entity/contents/content_context.cc | 34 ++--- engine/src/flutter/impeller/renderer/BUILD.gn | 2 + .../backend/vulkan/pipeline_library_vk.cc | 12 +- .../backend/vulkan/pipeline_library_vk.h | 5 + .../src/flutter/impeller/renderer/pipeline.h | 7 +- .../renderer/pipeline_compile_queue.cc | 118 ++++++++++++++++++ .../renderer/pipeline_compile_queue.h | 100 +++++++++++++++ .../impeller/renderer/pipeline_library.cc | 4 + .../impeller/renderer/pipeline_library.h | 9 ++ .../android_context_dynamic_impeller.cc | 1 - .../platform/android/platform_view_android.cc | 2 - 12 files changed, 265 insertions(+), 32 deletions(-) create mode 100644 engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc create mode 100644 engine/src/flutter/impeller/renderer/pipeline_compile_queue.h diff --git a/engine/src/flutter/impeller/base/flags.h b/engine/src/flutter/impeller/base/flags.h index cb581c34fe5a2..2bc904e4d5efa 100644 --- a/engine/src/flutter/impeller/base/flags.h +++ b/engine/src/flutter/impeller/base/flags.h @@ -7,9 +7,6 @@ namespace impeller { struct Flags { - /// Whether to defer PSO construction until first use. Usage Will introduce - /// raster jank. - bool lazy_shader_mode = false; /// When turned on DrawLine will use the experimental antialiased path. bool antialiased_lines = false; }; diff --git a/engine/src/flutter/impeller/entity/contents/content_context.cc b/engine/src/flutter/impeller/entity/contents/content_context.cc index 6db866d3cd04f..2dcdc09165ef7 100644 --- a/engine/src/flutter/impeller/entity/contents/content_context.cc +++ b/engine/src/flutter/impeller/entity/contents/content_context.cc @@ -128,12 +128,8 @@ class Variants : public GenericVariants { context.GetPipelineLibrary()->LogPipelineCreation(*desc); options.ApplyToPipelineDescriptor(*desc); desc_ = desc; - if (context.GetFlags().lazy_shader_mode) { - SetDefault(options, nullptr); - } else { - SetDefault(options, std::make_unique(context, desc_, - /*async=*/true)); - } + SetDefault(options, std::make_unique(context, desc_, + /*async=*/true)); } PipelineHandleT* Get(const ContentContextOptions& options) const { @@ -164,7 +160,8 @@ template RenderPipelineHandleT* CreateIfNeeded( const ContentContext* context, Variants& container, - ContentContextOptions opts) { + ContentContextOptions opts, + PipelineCompileQueue* compile_queue) { if (!context->IsValid()) { return nullptr; } @@ -183,7 +180,7 @@ RenderPipelineHandleT* CreateIfNeeded( FML_CHECK(default_handle != nullptr); const std::shared_ptr>& pipeline = - default_handle->WaitAndGet(); + default_handle->WaitAndGet(compile_queue); if (!pipeline) { return nullptr; } @@ -204,11 +201,14 @@ template PipelineRef GetPipeline(const ContentContext* context, Variants& container, ContentContextOptions opts) { - TypedPipeline* pipeline = CreateIfNeeded(context, container, opts); + auto compile_queue = + context->GetContext()->GetPipelineLibrary()->GetPipelineCompileQueue(); + TypedPipeline* pipeline = + CreateIfNeeded(context, container, opts, compile_queue); if (!pipeline) { return raw_ptr>(); } - return raw_ptr(pipeline->WaitAndGet()); + return raw_ptr(pipeline->WaitAndGet(compile_queue)); } } // namespace @@ -692,14 +692,9 @@ ContentContext::ContentContext( } clip_pipeline_descriptor->SetColorAttachmentDescriptors( std::move(clip_color_attachments)); - if (GetContext()->GetFlags().lazy_shader_mode) { - pipelines_->clip.SetDefaultDescriptor(clip_pipeline_descriptor); - pipelines_->clip.SetDefault(options, nullptr); - } else { - pipelines_->clip.SetDefault( - options, - std::make_unique(*context_, clip_pipeline_descriptor)); - } + pipelines_->clip.SetDefault( + options, + std::make_unique(*context_, clip_pipeline_descriptor)); pipelines_->texture_downsample.CreateDefault( *context_, options_no_msaa_no_depth_stencil); pipelines_->texture_downsample_bounded.CreateDefault( @@ -1018,9 +1013,6 @@ void ContentContext::ResetTransientsBuffers() { } void ContentContext::InitializeCommonlyUsedShadersIfNeeded() const { - if (GetContext()->GetFlags().lazy_shader_mode) { - return; - } GetContext()->InitializeCommonlyUsedShadersIfNeeded(); } diff --git a/engine/src/flutter/impeller/renderer/BUILD.gn b/engine/src/flutter/impeller/renderer/BUILD.gn index 953baf89f3376..0340164b956f2 100644 --- a/engine/src/flutter/impeller/renderer/BUILD.gn +++ b/engine/src/flutter/impeller/renderer/BUILD.gn @@ -52,6 +52,8 @@ impeller_component("renderer") { "pipeline.h", "pipeline_builder.cc", "pipeline_builder.h", + "pipeline_compile_queue.cc", + "pipeline_compile_queue.h", "pipeline_descriptor.cc", "pipeline_descriptor.h", "pipeline_library.cc", diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc index 02c4e6087a4c8..0cbef862c2bd1 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc @@ -26,7 +26,8 @@ PipelineLibraryVK::PipelineLibraryVK( pso_cache_(std::make_shared(std::move(caps), device_holder, std::move(cache_directory))), - worker_task_runner_(std::move(worker_task_runner)) { + worker_task_runner_(std::move(worker_task_runner)), + compile_queue_(PipelineCompileQueue::Create(worker_task_runner_)) { FML_DCHECK(worker_task_runner_); if (!pso_cache_->IsValid() || !worker_task_runner_) { return; @@ -179,8 +180,6 @@ PipelineFuture PipelineLibraryVK::GetPipeline( auto thiz = weak_this.lock(); if (!thiz) { promise->set_value(nullptr); - VALIDATION_LOG << "Pipeline library was collected before the pipeline " - "could be created."; return; } @@ -193,7 +192,8 @@ PipelineFuture PipelineLibraryVK::GetPipeline( }; if (async) { - worker_task_runner_->PostTask(generation_task); + compile_queue_->PostJobForDescriptor(descriptor, + std::move(generation_task)); } else { generation_task(); } @@ -304,4 +304,8 @@ PipelineLibraryVK::GetWorkerTaskRunner() const { return worker_task_runner_; } +PipelineCompileQueue* PipelineLibraryVK::GetPipelineCompileQueue() const { + return compile_queue_.get(); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.h index 407b871dd0827..3ead3c7dc700d 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.h @@ -16,6 +16,7 @@ #include "impeller/renderer/backend/vulkan/pipeline_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/pipeline.h" +#include "impeller/renderer/pipeline_compile_queue.h" #include "impeller/renderer/pipeline_library.h" namespace impeller { @@ -48,6 +49,7 @@ class PipelineLibraryVK final PipelineKey pipeline_key_ IPLR_GUARDED_BY(pipelines_mutex_) = 1; bool is_valid_ = false; bool cache_dirty_ = false; + std::shared_ptr compile_queue_; PipelineLibraryVK( const std::shared_ptr& device_holder, @@ -76,6 +78,9 @@ class PipelineLibraryVK final void RemovePipelinesWithEntryPoint( std::shared_ptr function) override; + // |PipelineLibrary| + PipelineCompileQueue* GetPipelineCompileQueue() const override; + std::unique_ptr CreateComputePipeline( const ComputePipelineDescriptor& desc, PipelineKey pipeline_key); diff --git a/engine/src/flutter/impeller/renderer/pipeline.h b/engine/src/flutter/impeller/renderer/pipeline.h index 989c33998425a..ec410896dd562 100644 --- a/engine/src/flutter/impeller/renderer/pipeline.h +++ b/engine/src/flutter/impeller/renderer/pipeline.h @@ -13,6 +13,7 @@ #include "impeller/renderer/compute_pipeline_descriptor.h" #include "impeller/renderer/context.h" #include "impeller/renderer/pipeline_builder.h" +#include "impeller/renderer/pipeline_compile_queue.h" #include "impeller/renderer/pipeline_descriptor.h" #include "impeller/renderer/shader_stage_compatibility_checker.h" @@ -125,12 +126,16 @@ class GenericRenderPipelineHandle { virtual ~GenericRenderPipelineHandle() = default; - std::shared_ptr> WaitAndGet() { + std::shared_ptr> WaitAndGet( + PipelineCompileQueue* queue) { if (did_wait_) { return pipeline_; } did_wait_ = true; if (pipeline_future_.IsValid()) { + if (queue != nullptr && pipeline_future_.descriptor.has_value()) { + queue->PerformJobEagerly(pipeline_future_.descriptor.value()); + } pipeline_ = pipeline_future_.Get(); } return pipeline_; diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc new file mode 100644 index 0000000000000..124e11e177346 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc @@ -0,0 +1,118 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/renderer/pipeline_compile_queue.h" + +#include "flutter/fml/logging.h" +#include "flutter/fml/trace_event.h" + +namespace impeller { + +std::shared_ptr PipelineCompileQueue::Create( + std::shared_ptr worker_task_runner) { + return std::shared_ptr( + new PipelineCompileQueue(std::move(worker_task_runner))); +} + +PipelineCompileQueue::PipelineCompileQueue( + std::shared_ptr worker_task_runner) + : worker_task_runner_(std::move(worker_task_runner)) {} + +PipelineCompileQueue::~PipelineCompileQueue() { + FinishAllJobs(); +} + +bool PipelineCompileQueue::PostJobForDescriptor(const PipelineDescriptor& desc, + const fml::closure& job) { + if (!job) { + return false; + } + + { + Lock lock(pending_jobs_mutex_); + auto insertion_result = pending_jobs_.insert(std::make_pair(desc, job)); + if (!insertion_result.second) { + // This bit is being extremely conservative. If insertion did not take + // place, someone gave the compile queue a job for the same description. + // This is highly unusual but technically not impossible. Just run the job + // eagerly. + FML_LOG(ERROR) << "Got multiple compile jobs for the same descriptor. " + "Running eagerly."; + // Don't invoke the job here has there are we have currently acquired a + // mutex. + worker_task_runner_->PostTask(job); + return true; + } + } + + worker_task_runner_->PostTask([weak_queue = weak_from_this()]() { + if (auto queue = weak_queue.lock()) { + queue->DoOneJob(); + } + }); + return true; +} + +fml::closure PipelineCompileQueue::TakeNextJob() { + Lock lock(pending_jobs_mutex_); + if (pending_jobs_.empty()) { + return nullptr; + } + auto job_iterator = pending_jobs_.begin(); + auto job = job_iterator->second; + pending_jobs_.erase(job_iterator); + return job; +} + +fml::closure PipelineCompileQueue::TakeJob(const PipelineDescriptor& desc) { + Lock lock(pending_jobs_mutex_); + auto found = pending_jobs_.find(desc); + if (found == pending_jobs_.end()) { + return nullptr; + } + // The pipeline compile job was somewhere in the task queue. However, a + // rendering operation needed the job to be done ASAP. Instead of waiting for + // the pipeline compile queue to eventually get to finishing job, the thread + // waiting on the job just decided to take the job from the queue and do it + // itself. If there were jobs ahead of this one, it means that they were + // mis-prioritized. This counter dumps the number of job re-prioritizations. + priorities_elevated_++; + FML_TRACE_COUNTER("impeller", "PipelineCompileQueue", + reinterpret_cast(this), // Trace Counter ID + "PrioritiesElevated", priorities_elevated_); + auto job = found->second; + pending_jobs_.erase(found); + return job; +} + +void PipelineCompileQueue::DoOneJob() { + if (auto job = TakeNextJob()) { + job(); + } +} + +void PipelineCompileQueue::FinishAllJobs() { + // This doesn't have to be fast. Just ensures the task queue is flushed when + // the compile queue is shutting down with jobs still in it. + while (true) { + bool has_jobs = false; + { + Lock lock(pending_jobs_mutex_); + has_jobs = !pending_jobs_.empty(); + } + if (!has_jobs) { + return; + } + // Allow any remaining worker threads to take jobs from this queue. + DoOneJob(); + } +} + +void PipelineCompileQueue::PerformJobEagerly(const PipelineDescriptor& desc) { + if (auto job = TakeJob(desc)) { + job(); + } +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h new file mode 100644 index 0000000000000..5ba506e4af701 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h @@ -0,0 +1,100 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_RENDERER_PIPELINE_COMPILE_QUEUE_H_ +#define FLUTTER_IMPELLER_RENDERER_PIPELINE_COMPILE_QUEUE_H_ + +#include + +#include "flutter/fml/closure.h" +#include "flutter/fml/concurrent_message_loop.h" +#include "impeller/base/thread.h" +#include "impeller/renderer/pipeline_descriptor.h" + +namespace impeller { + +//------------------------------------------------------------------------------ +/// @brief A task queue designed for managing compilation of pipeline state +/// objects. +/// +/// The task queue attempts to perform compile jobs as quickly as +/// possible by dispatching tasks to a concurrent task runner. These +/// tasks are dispatched during renderer creation and usually +/// complete before the first frame is rendered. In this ideal case, +/// this queue is entirely unnecessary and and serves as a thin +/// wrapper around just posting the compile jobs to a concurrent +/// task runner. +/// +/// If however, usually on lower end device, the compile jobs cannot +/// be completed before the first frame is rendered, the implicit +/// act of waiting for the compile job to be done can instead be +/// augmented to take the pending job and perform it eagerly on the +/// waiters thread. This effectively turns an idle wait into the job +/// skipping to the front of the line and being done on the callers +/// thread. +/// +/// Again, the entire point of this class is the reduce startup +/// times on the lowest end devices. On high end device, a queue is +/// entirely optional. The queue skipping mechanism all assume the +/// optional availability of a compile queue. +/// +class PipelineCompileQueue final + : public std::enable_shared_from_this { + public: + static std::shared_ptr Create( + std::shared_ptr worker_task_runner); + + virtual ~PipelineCompileQueue(); + + PipelineCompileQueue(const PipelineCompileQueue&) = delete; + + PipelineCompileQueue& operator=(const PipelineCompileQueue&) = delete; + + //---------------------------------------------------------------------------- + /// @brief Post a compile job for the specified descriptor. + /// + /// @param[in] desc The description + /// @param[in] job The job + /// + /// @return If the job was successfully posted to the parallel task + /// runners. + /// + bool PostJobForDescriptor(const PipelineDescriptor& desc, + const fml::closure& job); + + //---------------------------------------------------------------------------- + /// @brief If the task has not yet been done, perform it eagerly on the + /// calling thread. This can be used in lieu of an idle wait for + /// the task completion on the calling thread. + /// + /// @param[in] desc The description + /// + void PerformJobEagerly(const PipelineDescriptor& desc); + + private: + std::shared_ptr worker_task_runner_; + Mutex pending_jobs_mutex_; + size_t priorities_elevated_ = {}; + + std::unordered_map, + ComparableEqual> + pending_jobs_ IPLR_GUARDED_BY(pending_jobs_mutex_); + + explicit PipelineCompileQueue( + std::shared_ptr worker_task_runner); + + fml::closure TakeJob(const PipelineDescriptor& desc); + + fml::closure TakeNextJob(); + + void DoOneJob(); + + void FinishAllJobs(); +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_RENDERER_PIPELINE_COMPILE_QUEUE_H_ diff --git a/engine/src/flutter/impeller/renderer/pipeline_library.cc b/engine/src/flutter/impeller/renderer/pipeline_library.cc index 0a39a35d4b0c6..28647af867549 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_library.cc +++ b/engine/src/flutter/impeller/renderer/pipeline_library.cc @@ -74,4 +74,8 @@ PipelineLibrary::GetPipelineUseCounts() const { return counts; } +PipelineCompileQueue* PipelineLibrary::GetPipelineCompileQueue() const { + return nullptr; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/pipeline_library.h b/engine/src/flutter/impeller/renderer/pipeline_library.h index 6126aa6363399..c9f563d3d6d5c 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_library.h +++ b/engine/src/flutter/impeller/renderer/pipeline_library.h @@ -12,6 +12,7 @@ #include "impeller/base/thread.h" #include "impeller/base/thread_safety.h" #include "impeller/renderer/pipeline.h" +#include "impeller/renderer/pipeline_compile_queue.h" #include "impeller/renderer/pipeline_descriptor.h" namespace impeller { @@ -86,6 +87,14 @@ class PipelineLibrary : public std::enable_shared_from_this { ComparableEqual> GetPipelineUseCounts() const; + //---------------------------------------------------------------------------- + /// @brief If this library has a configurable compile queue, return a + /// pointer to it. + /// + /// @return The pipeline compile queue if one is present. + /// + virtual PipelineCompileQueue* GetPipelineCompileQueue() const; + protected: PipelineLibrary(); diff --git a/engine/src/flutter/shell/platform/android/android_context_dynamic_impeller.cc b/engine/src/flutter/shell/platform/android/android_context_dynamic_impeller.cc index 2e84fb09a372f..8c24261a54f8a 100644 --- a/engine/src/flutter/shell/platform/android/android_context_dynamic_impeller.cc +++ b/engine/src/flutter/shell/platform/android/android_context_dynamic_impeller.cc @@ -126,7 +126,6 @@ GetActualRenderingAPIForImpeller( .enable_surface_control = settings.enable_surface_control, .impeller_flags = { - .lazy_shader_mode = settings.impeller_flags.lazy_shader_mode, .antialiased_lines = settings.impeller_flags.antialiased_lines, }, diff --git a/engine/src/flutter/shell/platform/android/platform_view_android.cc b/engine/src/flutter/shell/platform/android/platform_view_android.cc index 86aa18fcf6c5b..02ed4df41e5c1 100644 --- a/engine/src/flutter/shell/platform/android/platform_view_android.cc +++ b/engine/src/flutter/shell/platform/android/platform_view_android.cc @@ -59,8 +59,6 @@ AndroidContext::ContextSettings CreateContextSettings( settings.enable_gpu_tracing = p_settings.enable_vulkan_gpu_tracing; settings.enable_validation = p_settings.enable_vulkan_validation; settings.enable_surface_control = p_settings.enable_surface_control; - settings.impeller_flags.lazy_shader_mode = - p_settings.impeller_enable_lazy_shader_mode; settings.impeller_flags.antialiased_lines = p_settings.impeller_antialiased_lines; return settings; From 5705b7547da86c93b75b797d9057052585134205 Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Fri, 13 Mar 2026 23:10:52 +0800 Subject: [PATCH 2/8] Add io task runner to pipeline library gles. Because IO thread is the owner of resource context, pipeline library gles can load resource by IO thread. --- .../renderer/backend/gles/context_gles.cc | 15 +++++++++------ .../impeller/renderer/backend/gles/context_gles.h | 6 ++++-- .../backend/gles/pipeline_library_gles.cc | 7 +++++-- .../renderer/backend/gles/pipeline_library_gles.h | 5 ++++- .../flutter/shell/platform/embedder/embedder.cc | 3 ++- .../embedder/embedder_surface_gl_impeller.cc | 5 +++-- .../embedder/embedder_surface_gl_impeller.h | 3 ++- 7 files changed, 29 insertions(+), 15 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc index 084b74d4e0ec5..070591eba3a7e 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc @@ -22,16 +22,19 @@ std::shared_ptr ContextGLES::Create( const Flags& flags, std::unique_ptr gl, const std::vector>& shader_libraries, - bool enable_gpu_tracing) { - return std::shared_ptr(new ContextGLES( - flags, std::move(gl), shader_libraries, enable_gpu_tracing)); + bool enable_gpu_tracing, + fml::RefPtr io_task_runner) { + return std::shared_ptr( + new ContextGLES(flags, std::move(gl), shader_libraries, + enable_gpu_tracing, std::move(io_task_runner))); } ContextGLES::ContextGLES( const Flags& flags, std::unique_ptr gl, const std::vector>& shader_libraries_mappings, - bool enable_gpu_tracing) + bool enable_gpu_tracing, + fml::RefPtr io_task_runner) : Context(flags) { reactor_ = std::make_shared(std::move(gl)); if (!reactor_->IsValid()) { @@ -52,8 +55,8 @@ ContextGLES::ContextGLES( // Create the pipeline library. { - pipeline_library_ = - std::shared_ptr(new PipelineLibraryGLES(reactor_)); + pipeline_library_ = std::shared_ptr( + new PipelineLibraryGLES(reactor_, std::move(io_task_runner))); } // Create allocators. diff --git a/engine/src/flutter/impeller/renderer/backend/gles/context_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/context_gles.h index 44f2f873bb23e..ed1c4ab52920a 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/context_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/context_gles.h @@ -28,7 +28,8 @@ class ContextGLES final : public Context, const Flags& flags, std::unique_ptr gl, const std::vector>& shader_libraries, - bool enable_gpu_tracing); + bool enable_gpu_tracing, + fml::RefPtr io_task_runner = nullptr); // |Context| ~ContextGLES() override; @@ -64,7 +65,8 @@ class ContextGLES final : public Context, const Flags& flags, std::unique_ptr gl, const std::vector>& shader_libraries, - bool enable_gpu_tracing); + bool enable_gpu_tracing, + fml::RefPtr io_task_runner); // |Context| std::string DescribeGpuModel() const override; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc index 240891dfc4b60..ba7893d4a1de2 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc @@ -16,8 +16,11 @@ namespace impeller { -PipelineLibraryGLES::PipelineLibraryGLES(std::shared_ptr reactor) - : reactor_(std::move(reactor)) {} +PipelineLibraryGLES::PipelineLibraryGLES( + std::shared_ptr reactor, + fml::RefPtr io_task_runner) + : reactor_(std::move(reactor)), + io_task_runner_(std::move(io_task_runner)) {} static std::string GetShaderInfoLog(const ProcTableGLES& gl, GLuint shader) { GLint log_length = 0; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h index 25c51c8113d38..7c0103151c942 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h @@ -9,6 +9,7 @@ #include #include "flutter/fml/hash_combine.h" +#include "flutter/fml/task_runner.h" #include "impeller/base/thread.h" #include "impeller/renderer/backend/gles/reactor_gles.h" #include "impeller/renderer/backend/gles/unique_handle_gles.h" @@ -91,8 +92,10 @@ class PipelineLibraryGLES final PipelineMap pipelines_; Mutex programs_mutex_; ProgramMap programs_ IPLR_GUARDED_BY(programs_mutex_); + fml::RefPtr io_task_runner_; - explicit PipelineLibraryGLES(std::shared_ptr reactor); + explicit PipelineLibraryGLES(std::shared_ptr reactor, + fml::RefPtr io_task_runner); // |PipelineLibrary| bool IsValid() const override; diff --git a/engine/src/flutter/shell/platform/embedder/embedder.cc b/engine/src/flutter/shell/platform/embedder/embedder.cc index 27390d7239127..016fe5747e51a 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder.cc @@ -492,7 +492,8 @@ InferOpenGLPlatformViewCreationCallback( shell.GetTaskRunners(), // task runners std::make_unique( gl_dispatch_table, fbo_reset_after_present, - view_embedder), // embedder_surface + view_embedder, // embedder_surface + shell.GetTaskRunners().GetIOTaskRunner()), platform_dispatch_table, // embedder platform dispatch table view_embedder // external view embedder ); diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_gl_impeller.cc b/engine/src/flutter/shell/platform/embedder/embedder_surface_gl_impeller.cc index 779c37b482a0d..3df93096b62f1 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_surface_gl_impeller.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_gl_impeller.cc @@ -45,7 +45,8 @@ class ReactorWorker final : public impeller::ReactorGLES::Worker { EmbedderSurfaceGLImpeller::EmbedderSurfaceGLImpeller( EmbedderSurfaceGLSkia::GLDispatchTable gl_dispatch_table, bool fbo_reset_after_present, - std::shared_ptr external_view_embedder) + std::shared_ptr external_view_embedder, + fml::RefPtr io_task_runner) : gl_dispatch_table_(std::move(gl_dispatch_table)), fbo_reset_after_present_(fbo_reset_after_present), external_view_embedder_(std::move(external_view_embedder)), @@ -82,7 +83,7 @@ EmbedderSurfaceGLImpeller::EmbedderSurfaceGLImpeller( impeller_context_ = impeller::ContextGLES::Create( impeller::Flags{}, std::move(gl), shader_mappings, - /*enable_gpu_tracing=*/false); + /*enable_gpu_tracing=*/false, std::move(io_task_runner)); if (!impeller_context_) { FML_LOG(ERROR) << "Could not create Impeller context."; diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_gl_impeller.h b/engine/src/flutter/shell/platform/embedder/embedder_surface_gl_impeller.h index 52febc2b378ee..205aeb1c3d73b 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_surface_gl_impeller.h +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_gl_impeller.h @@ -25,7 +25,8 @@ class EmbedderSurfaceGLImpeller final : public EmbedderSurface, EmbedderSurfaceGLImpeller( EmbedderSurfaceGLSkia::GLDispatchTable gl_dispatch_table, bool fbo_reset_after_present, - std::shared_ptr external_view_embedder); + std::shared_ptr external_view_embedder, + fml::RefPtr io_task_runner); ~EmbedderSurfaceGLImpeller() override; From 8c6e07f2c26199915b8a94ff8ed282448379953f Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Sat, 14 Mar 2026 05:03:52 +0800 Subject: [PATCH 3/8] Implement pipeline compile queue for gles --- .../gles/pipeline_compile_queue_gles.cc | 59 +++++++++++++++++++ .../gles/pipeline_compile_queue_gles.h | 45 ++++++++++++++ .../backend/gles/pipeline_library_gles.cc | 10 +++- .../backend/gles/pipeline_library_gles.h | 3 + .../renderer/pipeline_compile_queue.cc | 4 +- .../renderer/pipeline_compile_queue.h | 6 +- 6 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc create mode 100644 engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc new file mode 100644 index 0000000000000..3513bc6dc28c5 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/renderer/backend/gles/pipeline_compile_queue_gles.h" + +#include "flutter/fml/logging.h" +#include "flutter/fml/trace_event.h" + +namespace impeller { + +std::shared_ptr PipelineCompileQueueGLES::Create( + fml::RefPtr task_runner) { + return std::shared_ptr( + new PipelineCompileQueueGLES(std::move(task_runner))); +} + +PipelineCompileQueueGLES::PipelineCompileQueueGLES( + fml::RefPtr task_runner) + : PipelineCompileQueue(nullptr), task_runner_(std::move(task_runner)) {} + +PipelineCompileQueueGLES::~PipelineCompileQueueGLES() { + FinishAllJobs(); +} + +bool PipelineCompileQueueGLES::PostJobForDescriptor( + const PipelineDescriptor& desc, + const fml::closure& job) { + if (!job) { + return false; + } + + { + Lock lock(pending_jobs_mutex_); + auto insertion_result = pending_jobs_.insert(std::make_pair(desc, job)); + if (!insertion_result.second) { + // This bit is being extremely conservative. If insertion did not take + // place, someone gave the compile queue a job for the same description. + // This is highly unusual but technically not impossible. Just run the job + // eagerly. + FML_LOG(ERROR) << "Got multiple compile jobs for the same descriptor. " + "Running eagerly."; + // Don't invoke the job here has there are we have currently acquired a + // mutex. + task_runner_->PostTask(job); + return true; + } + } + + task_runner_->PostTask([weak_queue = weak_from_this()]() { + if (auto queue = std::static_pointer_cast( + weak_queue.lock())) { + queue->DoOneJob(); + } + }); + return true; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h new file mode 100644 index 0000000000000..4d1971bd33d37 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h @@ -0,0 +1,45 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_PIPELINE_COMPILE_QUEUE_GLES_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_PIPELINE_COMPILE_QUEUE_GLES_H_ + +#include "flutter/fml/closure.h" +#include "flutter/fml/task_runner.h" +#include "impeller/renderer/pipeline_compile_queue.h" + +namespace impeller { + +class PipelineCompileQueueGLES : public PipelineCompileQueue { + public: + static std::shared_ptr Create( + fml::RefPtr task_runner); + + explicit PipelineCompileQueueGLES(fml::RefPtr task_runner); + + ~PipelineCompileQueueGLES() override; + + PipelineCompileQueueGLES(const PipelineCompileQueueGLES&) = delete; + + PipelineCompileQueueGLES& operator=(const PipelineCompileQueueGLES&) = delete; + + //---------------------------------------------------------------------------- + /// @brief Post a compile job for the specified descriptor. + /// + /// @param[in] desc The description + /// @param[in] job The job + /// + /// @return If the job was successfully posted to the parallel task + /// runners. + /// + bool PostJobForDescriptor(const PipelineDescriptor& desc, + const fml::closure& job) override; + + private: + fml::RefPtr task_runner_; +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_PIPELINE_COMPILE_QUEUE_GLES_H_ diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc index ba7893d4a1de2..0f69a867722e3 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc @@ -20,7 +20,11 @@ PipelineLibraryGLES::PipelineLibraryGLES( std::shared_ptr reactor, fml::RefPtr io_task_runner) : reactor_(std::move(reactor)), - io_task_runner_(std::move(io_task_runner)) {} + io_task_runner_(std::move(io_task_runner)), + compile_queue_( + PipelineCompileQueue::Create(std::shared_ptr( + io_task_runner_.get(), + [runner = io_task_runner_](fml::BasicTaskRunner*) {}))) {} static std::string GetShaderInfoLog(const ProcTableGLES& gl, GLuint shader) { GLint log_length = 0; @@ -376,4 +380,8 @@ void PipelineLibraryGLES::SetProgramForKey( programs_[key] = std::move(program); } +PipelineCompileQueue* PipelineLibraryGLES::GetPipelineCompileQueue() const { + return compile_queue_.get(); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h index 7c0103151c942..62f9a837c65c0 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h @@ -93,6 +93,7 @@ class PipelineLibraryGLES final Mutex programs_mutex_; ProgramMap programs_ IPLR_GUARDED_BY(programs_mutex_); fml::RefPtr io_task_runner_; + std::shared_ptr compile_queue_; explicit PipelineLibraryGLES(std::shared_ptr reactor, fml::RefPtr io_task_runner); @@ -130,6 +131,8 @@ class PipelineLibraryGLES final void SetProgramForKey(const ProgramKey& key, std::shared_ptr program); + // |PipelineLibrary| + PipelineCompileQueue* GetPipelineCompileQueue() const override; }; } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc index 124e11e177346..2b9a453bf267d 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc @@ -10,13 +10,13 @@ namespace impeller { std::shared_ptr PipelineCompileQueue::Create( - std::shared_ptr worker_task_runner) { + std::shared_ptr worker_task_runner) { return std::shared_ptr( new PipelineCompileQueue(std::move(worker_task_runner))); } PipelineCompileQueue::PipelineCompileQueue( - std::shared_ptr worker_task_runner) + std::shared_ptr worker_task_runner) : worker_task_runner_(std::move(worker_task_runner)) {} PipelineCompileQueue::~PipelineCompileQueue() { diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h index 5ba506e4af701..6c23ba3101be8 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h @@ -43,7 +43,7 @@ class PipelineCompileQueue final : public std::enable_shared_from_this { public: static std::shared_ptr Create( - std::shared_ptr worker_task_runner); + std::shared_ptr worker_task_runner); virtual ~PipelineCompileQueue(); @@ -73,7 +73,7 @@ class PipelineCompileQueue final void PerformJobEagerly(const PipelineDescriptor& desc); private: - std::shared_ptr worker_task_runner_; + std::shared_ptr worker_task_runner_; Mutex pending_jobs_mutex_; size_t priorities_elevated_ = {}; @@ -84,7 +84,7 @@ class PipelineCompileQueue final pending_jobs_ IPLR_GUARDED_BY(pending_jobs_mutex_); explicit PipelineCompileQueue( - std::shared_ptr worker_task_runner); + std::shared_ptr worker_task_runner); fml::closure TakeJob(const PipelineDescriptor& desc); From fe44e391f4d3bb12bafd8d0bac949e28644502ed Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Mon, 16 Mar 2026 23:04:24 +0800 Subject: [PATCH 4/8] Fix build error --- .../impeller/renderer/backend/gles/BUILD.gn | 2 ++ .../gles/pipeline_compile_queue_gles.cc | 35 +++---------------- .../gles/pipeline_compile_queue_gles.h | 8 ++--- .../backend/gles/pipeline_library_gles.cc | 5 +-- .../backend/gles/pipeline_library_gles.h | 3 +- .../renderer/pipeline_compile_queue.cc | 12 +++++-- .../renderer/pipeline_compile_queue.h | 18 +++++++--- 7 files changed, 36 insertions(+), 47 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/backend/gles/BUILD.gn b/engine/src/flutter/impeller/renderer/backend/gles/BUILD.gn index 38c9771b4be9e..e91c75671d3fb 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/BUILD.gn +++ b/engine/src/flutter/impeller/renderer/backend/gles/BUILD.gn @@ -68,6 +68,8 @@ impeller_component("gles") { "gpu_tracer_gles.h", "handle_gles.cc", "handle_gles.h", + "pipeline_compile_queue_gles.cc", + "pipeline_compile_queue_gles.h", "pipeline_gles.cc", "pipeline_gles.h", "pipeline_library_gles.cc", diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc index 3513bc6dc28c5..a2b51004e6a7d 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc @@ -19,41 +19,14 @@ PipelineCompileQueueGLES::PipelineCompileQueueGLES( fml::RefPtr task_runner) : PipelineCompileQueue(nullptr), task_runner_(std::move(task_runner)) {} -PipelineCompileQueueGLES::~PipelineCompileQueueGLES() { - FinishAllJobs(); -} +PipelineCompileQueueGLES::~PipelineCompileQueueGLES() {} -bool PipelineCompileQueueGLES::PostJobForDescriptor( - const PipelineDescriptor& desc, - const fml::closure& job) { +void PipelineCompileQueueGLES::PostJob(const fml::closure& job) { if (!job) { - return false; - } - - { - Lock lock(pending_jobs_mutex_); - auto insertion_result = pending_jobs_.insert(std::make_pair(desc, job)); - if (!insertion_result.second) { - // This bit is being extremely conservative. If insertion did not take - // place, someone gave the compile queue a job for the same description. - // This is highly unusual but technically not impossible. Just run the job - // eagerly. - FML_LOG(ERROR) << "Got multiple compile jobs for the same descriptor. " - "Running eagerly."; - // Don't invoke the job here has there are we have currently acquired a - // mutex. - task_runner_->PostTask(job); - return true; - } + return; } - task_runner_->PostTask([weak_queue = weak_from_this()]() { - if (auto queue = std::static_pointer_cast( - weak_queue.lock())) { - queue->DoOneJob(); - } - }); - return true; + task_runner_->PostTask(job); } } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h index 4d1971bd33d37..c35f0d34b7a23 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h @@ -25,16 +25,14 @@ class PipelineCompileQueueGLES : public PipelineCompileQueue { PipelineCompileQueueGLES& operator=(const PipelineCompileQueueGLES&) = delete; //---------------------------------------------------------------------------- - /// @brief Post a compile job for the specified descriptor. + /// @brief Post a job to the worker task runner. /// - /// @param[in] desc The description /// @param[in] job The job /// /// @return If the job was successfully posted to the parallel task - /// runners. + /// runners. /// - bool PostJobForDescriptor(const PipelineDescriptor& desc, - const fml::closure& job) override; + void PostJob(const fml::closure& job) override; private: fml::RefPtr task_runner_; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc index 0f69a867722e3..70d2223cce3b9 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc @@ -21,10 +21,7 @@ PipelineLibraryGLES::PipelineLibraryGLES( fml::RefPtr io_task_runner) : reactor_(std::move(reactor)), io_task_runner_(std::move(io_task_runner)), - compile_queue_( - PipelineCompileQueue::Create(std::shared_ptr( - io_task_runner_.get(), - [runner = io_task_runner_](fml::BasicTaskRunner*) {}))) {} + compile_queue_(PipelineCompileQueueGLES::Create(io_task_runner_)) {} static std::string GetShaderInfoLog(const ProcTableGLES& gl, GLuint shader) { GLint log_length = 0; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h index 62f9a837c65c0..fa36a88294144 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.h @@ -11,6 +11,7 @@ #include "flutter/fml/hash_combine.h" #include "flutter/fml/task_runner.h" #include "impeller/base/thread.h" +#include "impeller/renderer/backend/gles/pipeline_compile_queue_gles.h" #include "impeller/renderer/backend/gles/reactor_gles.h" #include "impeller/renderer/backend/gles/unique_handle_gles.h" #include "impeller/renderer/pipeline_library.h" @@ -93,7 +94,7 @@ class PipelineLibraryGLES final Mutex programs_mutex_; ProgramMap programs_ IPLR_GUARDED_BY(programs_mutex_); fml::RefPtr io_task_runner_; - std::shared_ptr compile_queue_; + std::shared_ptr compile_queue_; explicit PipelineLibraryGLES(std::shared_ptr reactor, fml::RefPtr io_task_runner); diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc index 2b9a453bf267d..87e3f4fa8d4a2 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc @@ -41,12 +41,12 @@ bool PipelineCompileQueue::PostJobForDescriptor(const PipelineDescriptor& desc, "Running eagerly."; // Don't invoke the job here has there are we have currently acquired a // mutex. - worker_task_runner_->PostTask(job); + PostJob(job); return true; } } - worker_task_runner_->PostTask([weak_queue = weak_from_this()]() { + PostJob([weak_queue = weak_from_this()]() { if (auto queue = weak_queue.lock()) { queue->DoOneJob(); } @@ -115,4 +115,12 @@ void PipelineCompileQueue::PerformJobEagerly(const PipelineDescriptor& desc) { } } +void PipelineCompileQueue::PostJob(const fml::closure& job) { + if (!job) { + return; + } + + worker_task_runner_->PostTask(job); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h index 6c23ba3101be8..dd81b5f623a52 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h @@ -39,12 +39,15 @@ namespace impeller { /// entirely optional. The queue skipping mechanism all assume the /// optional availability of a compile queue. /// -class PipelineCompileQueue final +class PipelineCompileQueue : public std::enable_shared_from_this { public: static std::shared_ptr Create( std::shared_ptr worker_task_runner); + explicit PipelineCompileQueue( + std::shared_ptr worker_task_runner); + virtual ~PipelineCompileQueue(); PipelineCompileQueue(const PipelineCompileQueue&) = delete; @@ -72,6 +75,16 @@ class PipelineCompileQueue final /// void PerformJobEagerly(const PipelineDescriptor& desc); + //---------------------------------------------------------------------------- + /// @brief Post a job to the worker task runner. + /// + /// @param[in] job The job + /// + /// @return If the job was successfully posted to the parallel task + /// runners. + /// + virtual void PostJob(const fml::closure& job); + private: std::shared_ptr worker_task_runner_; Mutex pending_jobs_mutex_; @@ -83,9 +96,6 @@ class PipelineCompileQueue final ComparableEqual> pending_jobs_ IPLR_GUARDED_BY(pending_jobs_mutex_); - explicit PipelineCompileQueue( - std::shared_ptr worker_task_runner); - fml::closure TakeJob(const PipelineDescriptor& desc); fml::closure TakeNextJob(); From 352d92d757d92410b7b06e80788d3c95d88fe537 Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Tue, 17 Mar 2026 00:18:49 +0800 Subject: [PATCH 5/8] Add pipeline_compile_queue_vulkan.h --- .../gles/pipeline_compile_queue_gles.cc | 11 ++--- .../gles/pipeline_compile_queue_gles.h | 10 ++--- .../impeller/renderer/backend/vulkan/BUILD.gn | 2 + .../vulkan/pipeline_compile_queue_vulkan.cc | 33 +++++++++++++++ .../vulkan/pipeline_compile_queue_vulkan.h | 42 +++++++++++++++++++ .../backend/vulkan/pipeline_library_vk.cc | 2 +- .../backend/vulkan/pipeline_library_vk.h | 4 +- .../renderer/pipeline_compile_queue.cc | 18 -------- .../renderer/pipeline_compile_queue.h | 9 +--- 9 files changed, 92 insertions(+), 39 deletions(-) create mode 100644 engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_compile_queue_vulkan.cc create mode 100644 engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_compile_queue_vulkan.h diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc index a2b51004e6a7d..334b7e29a1894 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc @@ -10,14 +10,15 @@ namespace impeller { std::shared_ptr PipelineCompileQueueGLES::Create( - fml::RefPtr task_runner) { + fml::RefPtr worker_task_runner) { return std::shared_ptr( - new PipelineCompileQueueGLES(std::move(task_runner))); + new PipelineCompileQueueGLES(std::move(worker_task_runner))); } PipelineCompileQueueGLES::PipelineCompileQueueGLES( - fml::RefPtr task_runner) - : PipelineCompileQueue(nullptr), task_runner_(std::move(task_runner)) {} + fml::RefPtr worker_task_runner) + : PipelineCompileQueue(), + worker_task_runner_(std::move(worker_task_runner)) {} PipelineCompileQueueGLES::~PipelineCompileQueueGLES() {} @@ -26,7 +27,7 @@ void PipelineCompileQueueGLES::PostJob(const fml::closure& job) { return; } - task_runner_->PostTask(job); + worker_task_runner_->PostTask(job); } } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h index c35f0d34b7a23..31fc6a528e48e 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.h @@ -14,9 +14,10 @@ namespace impeller { class PipelineCompileQueueGLES : public PipelineCompileQueue { public: static std::shared_ptr Create( - fml::RefPtr task_runner); + fml::RefPtr worker_task_runner); - explicit PipelineCompileQueueGLES(fml::RefPtr task_runner); + explicit PipelineCompileQueueGLES( + fml::RefPtr worker_task_runner); ~PipelineCompileQueueGLES() override; @@ -29,13 +30,10 @@ class PipelineCompileQueueGLES : public PipelineCompileQueue { /// /// @param[in] job The job /// - /// @return If the job was successfully posted to the parallel task - /// runners. - /// void PostJob(const fml::closure& job) override; private: - fml::RefPtr task_runner_; + fml::RefPtr worker_task_runner_; }; } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn b/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn index 12fbcd6aea5ef..2cb67f2920249 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/BUILD.gn @@ -80,6 +80,8 @@ impeller_component("vulkan") { "pipeline_cache_data_vk.h", "pipeline_cache_vk.cc", "pipeline_cache_vk.h", + "pipeline_compile_queue_vulkan.cc", + "pipeline_compile_queue_vulkan.h", "pipeline_library_vk.cc", "pipeline_library_vk.h", "pipeline_vk.cc", diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_compile_queue_vulkan.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_compile_queue_vulkan.cc new file mode 100644 index 0000000000000..3ecaabb16bdcc --- /dev/null +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_compile_queue_vulkan.cc @@ -0,0 +1,33 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/renderer/backend/vulkan/pipeline_compile_queue_vulkan.h" + +#include "flutter/fml/logging.h" +#include "flutter/fml/trace_event.h" + +namespace impeller { + +std::shared_ptr PipelineCompileQueueVulkan::Create( + std::shared_ptr worker_task_runner) { + return std::shared_ptr( + new PipelineCompileQueueVulkan(std::move(worker_task_runner))); +} + +PipelineCompileQueueVulkan::PipelineCompileQueueVulkan( + std::shared_ptr worker_task_runner) + : PipelineCompileQueue(), + worker_task_runner_(std::move(worker_task_runner)) {} + +PipelineCompileQueueVulkan::~PipelineCompileQueueVulkan() {} + +void PipelineCompileQueueVulkan::PostJob(const fml::closure& job) { + if (!job) { + return; + } + + worker_task_runner_->PostTask(job); +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_compile_queue_vulkan.h b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_compile_queue_vulkan.h new file mode 100644 index 0000000000000..9f6474c9f958c --- /dev/null +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_compile_queue_vulkan.h @@ -0,0 +1,42 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_PIPELINE_COMPILE_QUEUE_VULKAN_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_PIPELINE_COMPILE_QUEUE_VULKAN_H_ + +#include "flutter/fml/closure.h" +#include "flutter/fml/task_runner.h" +#include "impeller/renderer/pipeline_compile_queue.h" + +namespace impeller { + +class PipelineCompileQueueVulkan : public PipelineCompileQueue { + public: + static std::shared_ptr Create( + std::shared_ptr worker_task_runner); + + explicit PipelineCompileQueueVulkan( + std::shared_ptr worker_task_runner); + + ~PipelineCompileQueueVulkan() override; + + PipelineCompileQueueVulkan(const PipelineCompileQueueVulkan&) = delete; + + PipelineCompileQueueVulkan& operator=(const PipelineCompileQueueVulkan&) = + delete; + + //---------------------------------------------------------------------------- + /// @brief Post a job to the worker task runner. + /// + /// @param[in] job The job + /// + void PostJob(const fml::closure& job) override; + + private: + std::shared_ptr worker_task_runner_; +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_PIPELINE_COMPILE_QUEUE_VULKAN_H_ diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc index 0cbef862c2bd1..50ae6b3efb352 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc @@ -27,7 +27,7 @@ PipelineLibraryVK::PipelineLibraryVK( device_holder, std::move(cache_directory))), worker_task_runner_(std::move(worker_task_runner)), - compile_queue_(PipelineCompileQueue::Create(worker_task_runner_)) { + compile_queue_(PipelineCompileQueueVulkan::Create(worker_task_runner)) { FML_DCHECK(worker_task_runner_); if (!pso_cache_->IsValid() || !worker_task_runner_) { return; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.h index 3ead3c7dc700d..4304db9b58293 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.h @@ -13,10 +13,10 @@ #include "impeller/base/thread.h" #include "impeller/renderer/backend/vulkan/compute_pipeline_vk.h" #include "impeller/renderer/backend/vulkan/pipeline_cache_vk.h" +#include "impeller/renderer/backend/vulkan/pipeline_compile_queue_vulkan.h" #include "impeller/renderer/backend/vulkan/pipeline_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/pipeline.h" -#include "impeller/renderer/pipeline_compile_queue.h" #include "impeller/renderer/pipeline_library.h" namespace impeller { @@ -49,7 +49,7 @@ class PipelineLibraryVK final PipelineKey pipeline_key_ IPLR_GUARDED_BY(pipelines_mutex_) = 1; bool is_valid_ = false; bool cache_dirty_ = false; - std::shared_ptr compile_queue_; + std::shared_ptr compile_queue_; PipelineLibraryVK( const std::shared_ptr& device_holder, diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc index 87e3f4fa8d4a2..ad6f0fc6e0969 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc @@ -9,16 +9,6 @@ namespace impeller { -std::shared_ptr PipelineCompileQueue::Create( - std::shared_ptr worker_task_runner) { - return std::shared_ptr( - new PipelineCompileQueue(std::move(worker_task_runner))); -} - -PipelineCompileQueue::PipelineCompileQueue( - std::shared_ptr worker_task_runner) - : worker_task_runner_(std::move(worker_task_runner)) {} - PipelineCompileQueue::~PipelineCompileQueue() { FinishAllJobs(); } @@ -115,12 +105,4 @@ void PipelineCompileQueue::PerformJobEagerly(const PipelineDescriptor& desc) { } } -void PipelineCompileQueue::PostJob(const fml::closure& job) { - if (!job) { - return; - } - - worker_task_runner_->PostTask(job); -} - } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h index dd81b5f623a52..e6418946cdff6 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h @@ -42,11 +42,7 @@ namespace impeller { class PipelineCompileQueue : public std::enable_shared_from_this { public: - static std::shared_ptr Create( - std::shared_ptr worker_task_runner); - - explicit PipelineCompileQueue( - std::shared_ptr worker_task_runner); + PipelineCompileQueue() = default; virtual ~PipelineCompileQueue(); @@ -83,10 +79,9 @@ class PipelineCompileQueue /// @return If the job was successfully posted to the parallel task /// runners. /// - virtual void PostJob(const fml::closure& job); + virtual void PostJob(const fml::closure& job) = 0; private: - std::shared_ptr worker_task_runner_; Mutex pending_jobs_mutex_; size_t priorities_elevated_ = {}; From f4672ccc03d893eef4ff08d55c31795858be681d Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Tue, 17 Mar 2026 04:41:14 +0800 Subject: [PATCH 6/8] Update GetPipeline method when sync == true --- .../backend/gles/pipeline_library_gles.cc | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc index 70d2223cce3b9..a3486f4550e63 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_library_gles.cc @@ -300,17 +300,34 @@ PipelineFuture PipelineLibraryGLES::GetPipeline( PipelineFuture{descriptor, promise->get_future()}; pipelines_[descriptor] = pipeline_future; - const auto result = reactor_->AddOperation([promise, // - weak_this = weak_from_this(), // - descriptor, // - vert_function, // - frag_function, // - threadsafe // - ](const ReactorGLES& reactor) { - promise->set_value(CreatePipeline(weak_this, descriptor, vert_function, - frag_function, threadsafe)); - }); - FML_CHECK(result); + auto weak_this = weak_from_this(); + auto reactor = reactor_; + auto generation_task = [promise, weak_this, descriptor, vert_function, + frag_function, threadsafe, reactor]() { + auto thiz = weak_this.lock(); + if (!thiz) { + promise->set_value(nullptr); + return; + } + const auto result = reactor->AddOperation([promise, // + weak_this, // + descriptor, // + vert_function, // + frag_function, // + threadsafe // + ](const ReactorGLES& reactor) { + promise->set_value(CreatePipeline(weak_this, descriptor, vert_function, + frag_function, threadsafe)); + }); + FML_CHECK(result); + }; + + if (async) { + compile_queue_->PostJobForDescriptor(descriptor, + std::move(generation_task)); + } else { + generation_task(); + } return pipeline_future; } From c4f4f4ce66d4f684f622f607ce0d33cbd9195923 Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Fri, 27 Mar 2026 18:00:48 +0800 Subject: [PATCH 7/8] Make link program after schedule frame on IO thread --- .../gles/pipeline_compile_queue_gles.cc | 2 +- .../renderer/pipeline_compile_queue.cc | 24 ++++++++++++++----- .../renderer/pipeline_compile_queue.h | 8 +++++++ engine/src/flutter/shell/common/shell.cc | 20 +++++++++++++++- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc index 334b7e29a1894..e3e3e1debadb4 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_compile_queue_gles.cc @@ -17,7 +17,7 @@ std::shared_ptr PipelineCompileQueueGLES::Create( PipelineCompileQueueGLES::PipelineCompileQueueGLES( fml::RefPtr worker_task_runner) - : PipelineCompileQueue(), + : PipelineCompileQueue(true), worker_task_runner_(std::move(worker_task_runner)) {} PipelineCompileQueueGLES::~PipelineCompileQueueGLES() {} diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc index ad6f0fc6e0969..639b5da2d0346 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc @@ -9,6 +9,9 @@ namespace impeller { +PipelineCompileQueue::PipelineCompileQueue(bool wait_until_rendering) + : wait_until_rendering_(wait_until_rendering) {} + PipelineCompileQueue::~PipelineCompileQueue() { FinishAllJobs(); } @@ -35,12 +38,13 @@ bool PipelineCompileQueue::PostJobForDescriptor(const PipelineDescriptor& desc, return true; } } - - PostJob([weak_queue = weak_from_this()]() { - if (auto queue = weak_queue.lock()) { - queue->DoOneJob(); - } - }); + if (!WaitUntilRendering()) { + PostJob([weak_queue = weak_from_this()]() { + if (auto queue = weak_queue.lock()) { + queue->DoOneJob(); + } + }); + } return true; } @@ -82,6 +86,14 @@ void PipelineCompileQueue::DoOneJob() { } } +void PipelineCompileQueue::FlushPendingJobs() { + PostJob([weak_queue = weak_from_this()]() { + if (auto queue = weak_queue.lock()) { + queue->FinishAllJobs(); + } + }); +} + void PipelineCompileQueue::FinishAllJobs() { // This doesn't have to be fast. Just ensures the task queue is flushed when // the compile queue is shutting down with jobs still in it. diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h index e6418946cdff6..eb88d69eb787c 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h @@ -43,6 +43,7 @@ class PipelineCompileQueue : public std::enable_shared_from_this { public: PipelineCompileQueue() = default; + PipelineCompileQueue(bool wait_until_rendering); virtual ~PipelineCompileQueue(); @@ -81,6 +82,13 @@ class PipelineCompileQueue /// virtual void PostJob(const fml::closure& job) = 0; + bool WaitUntilRendering() { return wait_until_rendering_; }; + + void FlushPendingJobs(); + + protected: + bool wait_until_rendering_ = false; + private: Mutex pending_jobs_mutex_; size_t priorities_elevated_ = {}; diff --git a/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc index 762663b061d1c..3aee225d65663 100644 --- a/engine/src/flutter/shell/common/shell.cc +++ b/engine/src/flutter/shell/common/shell.cc @@ -1006,6 +1006,20 @@ void Shell::OnPlatformViewCreated(std::unique_ptr surface) { } }; + auto flush_task = [io_manager = io_manager_->GetWeakPtr()] { + if (io_manager && io_manager->GetImpellerContext()) { + auto impeller_context = io_manager->GetImpellerContext(); + if (impeller_context && impeller_context->GetPipelineLibrary()) { + auto pipeline_compile_queue = + impeller_context->GetPipelineLibrary()->GetPipelineCompileQueue(); + if (pipeline_compile_queue && + pipeline_compile_queue->WaitUntilRendering()) { + pipeline_compile_queue->FlushPendingJobs(); + } + } + } + }; + // Threading: Capture platform view by raw pointer and not the weak pointer. // We are going to use the pointer on the IO thread which is not safe with a // weak pointer. However, we are preventing the platform view from being @@ -1017,7 +1031,7 @@ void Shell::OnPlatformViewCreated(std::unique_ptr surface) { auto io_task = [io_manager = io_manager_->GetWeakPtr(), platform_view, ui_task_runner = task_runners_.GetUITaskRunner(), ui_task, raster_task_runner = task_runners_.GetRasterTaskRunner(), - raster_task, should_post_raster_task, &latch] { + raster_task, should_post_raster_task, &latch, flush_task] { if (io_manager && !io_manager->GetResourceContext()) { sk_sp resource_context = platform_view->CreateResourceContext(); @@ -1032,6 +1046,10 @@ void Shell::OnPlatformViewCreated(std::unique_ptr surface) { if (should_post_raster_task) { fml::TaskRunner::RunNowOrPostTask(raster_task_runner, raster_task); } + + // Step 3: Tell the IO thread that it could be start to link program. + fml::TaskRunner::RunNowOrPostTask(raster_task_runner, flush_task); + latch.Signal(); }; From 9c19a962b4ffd4718879c3e5167936afeb848ad6 Mon Sep 17 00:00:00 2001 From: Xiaowei Guan Date: Thu, 30 Apr 2026 01:43:00 +0800 Subject: [PATCH 8/8] Fix codereview issues --- .../renderer/pipeline_compile_queue.cc | 1 + .../impeller/renderer/pipeline_compile_queue.h | 2 +- engine/src/flutter/shell/common/shell.cc | 18 +++++++++--------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc index 639b5da2d0346..b04a66228346c 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.cc @@ -87,6 +87,7 @@ void PipelineCompileQueue::DoOneJob() { } void PipelineCompileQueue::FlushPendingJobs() { + wait_until_rendering_ = false; PostJob([weak_queue = weak_from_this()]() { if (auto queue = weak_queue.lock()) { queue->FinishAllJobs(); diff --git a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h index eb88d69eb787c..e3e64e5289073 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h +++ b/engine/src/flutter/impeller/renderer/pipeline_compile_queue.h @@ -87,7 +87,7 @@ class PipelineCompileQueue void FlushPendingJobs(); protected: - bool wait_until_rendering_ = false; + std::atomic wait_until_rendering_ = false; private: Mutex pending_jobs_mutex_; diff --git a/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc index 3aee225d65663..b1871e1e30b49 100644 --- a/engine/src/flutter/shell/common/shell.cc +++ b/engine/src/flutter/shell/common/shell.cc @@ -1007,14 +1007,14 @@ void Shell::OnPlatformViewCreated(std::unique_ptr surface) { }; auto flush_task = [io_manager = io_manager_->GetWeakPtr()] { - if (io_manager && io_manager->GetImpellerContext()) { - auto impeller_context = io_manager->GetImpellerContext(); - if (impeller_context && impeller_context->GetPipelineLibrary()) { - auto pipeline_compile_queue = - impeller_context->GetPipelineLibrary()->GetPipelineCompileQueue(); - if (pipeline_compile_queue && - pipeline_compile_queue->WaitUntilRendering()) { - pipeline_compile_queue->FlushPendingJobs(); + if (io_manager) { + if (auto impeller_context = io_manager->GetImpellerContext()) { + if (auto pipeline_library = impeller_context->GetPipelineLibrary()) { + if (auto pipeline_compile_queue = + pipeline_library->GetPipelineCompileQueue()) + if (pipeline_compile_queue->WaitUntilRendering()) { + pipeline_compile_queue->FlushPendingJobs(); + } } } } @@ -1047,7 +1047,7 @@ void Shell::OnPlatformViewCreated(std::unique_ptr surface) { fml::TaskRunner::RunNowOrPostTask(raster_task_runner, raster_task); } - // Step 3: Tell the IO thread that it could be start to link program. + // Step 3: Flush pending pipeline compilation jobs. fml::TaskRunner::RunNowOrPostTask(raster_task_runner, flush_task); latch.Signal();