Skip to content

[Impeller] Add Vulkan rendering backend for Linux and Windows desktops#183382

Draft
sero583 wants to merge 1 commit into
flutter:masterfrom
sero583:impeller-vulkan-desktop
Draft

[Impeller] Add Vulkan rendering backend for Linux and Windows desktops#183382
sero583 wants to merge 1 commit into
flutter:masterfrom
sero583:impeller-vulkan-desktop

Conversation

@sero583

@sero583 sero583 commented Mar 8, 2026

Copy link
Copy Markdown
Contributor

Description

Add Vulkan/Impeller rendering support for Flutter on Linux and Windows desktops.

The Flutter embedder API already supports Vulkan, and Impeller already has a mature Vulkan backend powering Android. This PR extends that support to desktop platforms by wiring the embedder's Vulkan surface into Impeller's existing KHR swapchain path, reusing the same rendering pipeline that powers Android — no new compositor or rendering pipeline was invented.

Note on PR size: This PR is large because it spans tightly interlinked components — embedder API extensions, platform-specific Vulkan managers (Linux + Windows), Impeller backend hardening, and framework-level rendering backend detection — where each piece depends on the others. Splitting into smaller PRs would leave non-functional intermediate states (e.g., a Vulkan manager with no embedder to wire it to, or an embedder path with no platform surface to feed it). The changes were developed and tested as a single unit to ensure correctness across the full integration path. I am aware that this isn't easy to review, and I am open to suggestions for how to make it more digestible.

Why this matters

Desktop Flutter currently renders through OpenGL (Linux) and ANGLE/OpenGL ES (Windows). Vulkan provides:

  • Direct GPU access without translation layers (ANGLE adds overhead on Windows)
  • Explicit resource management — the engine controls memory, synchronization, and command submission
  • Modern driver ecosystem — Vulkan drivers receive more active optimization from GPU vendors than legacy OpenGL
  • Parity with Android — Impeller already uses Vulkan on Android; desktop support closes the platform gap

Key design decisions

  1. Reuse Impeller's KHR swapchain path rather than building a new compositor. The embedder creates a VkSurfaceKHR from the platform window and passes it to Impeller's SurfaceContextVK, which manages swapchain lifecycle identically to Android. This means every rendering optimization and bugfix in the Android Vulkan path automatically applies to desktop.

  2. Frame throttling via in-flight submission tracking in CommandQueueVK prevents unbounded resource accumulation. Without this, sustained submission rates (e.g., during benchmark stress tests) exhaust host memory. The throttle uses a condition variable with a 5-second timeout — generous enough that no legitimate workload hits it, strict enough to prevent runaway allocation.

  3. VMA pool capping at 256 blocks × 4 MB = 1 GB in AllocatorVK. Without this cap, VMA's pool grows without bound when high-water-mark buffer demand spikes, and pool-internal fragmentation prevents block reuse even after individual allocations are freed.

  4. Windows Resizable BAR working set trimming in AllocatorVK. On GPUs with Resizable BAR (AMD RDNA, Intel Arc), the driver maps all VRAM into the process address space, inflating the working set to 2–4 GB even when actual CPU-side allocation is ~200 MB. Periodic EmptyWorkingSet() calls (gated by cooldown, RSS threshold, and RSS-to-VMA ratio) let the OS reclaim pages the GPU driver mapped but that aren't actively used by the CPU.

  5. Mesa dzn workarounds for WSL2's Direct3D 12 translation layer. Mesa's Vulkan-on-D3D12 driver reports minImageTransferGranularity of (0,0,0) and fails sub-region buffer-to-image copies. The workaround stages through a full-size temporary texture when skip_sub_region_buffer_to_image_copy is set.

  6. Framebuffer fetch compatibility — drivers that do not support subpass self-dependencies (e.g., Mesa dzn) can have input attachment references and self-dependencies conditionally omitted via SetFramebufferFetchEnabled(false) in RenderPassBuilderVK.

  7. Opt-in activation — Vulkan is not the default. On Linux, set FLUTTER_LINUX_RENDERER=vulkan; on Windows, set the renderer type to FlutterDesktopRendererVulkan before engine startup. OpenGL/ANGLE remain the defaults for full backward compatibility.

Related Issues

Related PRs

  • #182265 — "[Impeller] Dispose thread local caches on each frame when using GPUSurfaceVulkanImpeller with a delegate" (merged). During development, I independently identified the same thread-local command pool leak that this PR fixes. Our DisposeThreadLocalCachedResources() call in gpu_surface_vulkan_impeller.cc addresses the same issue for the non-delegate (embedder-managed image) path. I am glad this was caught and fixed upstream as well, as I was focused on this PR and had no time to submit a similar fix.

Changes

1. Vulkan proc table & surface abstractions

File Change
vulkan/procs/vulkan_proc_table.{cc,h} Added CreateWin32SurfaceKHR, CreateXlibSurfaceKHR, CreateWaylandSurfaceKHR function pointers and instance-level resolution
vulkan/procs/vulkan_interface.h Added Vulkan surface creation struct typedefs for Win32, X11, and Wayland
vulkan/vulkan_native_surface_linux.{cc,h} New. VulkanNativeSurfaceLinux supporting both X11 and Wayland via runtime detection
vulkan/vulkan_swapchain.h Extended platform guards to include FML_OS_LINUX
vulkan/BUILD.gn Added Linux surface sources and swapchain support

Why: The existing Vulkan proc table only resolved Android surface functions. Desktop platforms need Win32, X11, and Wayland surface creation. The Linux native surface class auto-detects the windowing system at construction time.

2. Embedder Vulkan surface integration

File Change
shell/platform/embedder/embedder_surface_vulkan_impeller.{cc,h} Extended to accept an optional VkSurfaceKHR. When provided, creates a SurfaceContextVK and uses Impeller's KHR swapchain path; otherwise falls back to the existing embedder-managed image path
shell/platform/embedder/embedder.{cc,h} Added FlutterVulkanSurfaceHandle typedef and surface field on FlutterVulkanRendererConfig. When non-null, the engine manages the swapchain internally (KHR path); when null, the legacy embedder-managed image callbacks are used
shell/platform/embedder/embedder_engine.{cc,h} Added SetSurfaceSizeUpdater() for platforms to handle swapchain resize on viewport changes
shell/platform/embedder/embedder_surface.{cc,h} Added UpdateSurfaceSize() virtual method for subclasses that manage their own swapchain

Why: The embedder already had a Vulkan path, but it used embedder-managed images (the host allocates VkImages and hands them to the engine). For desktop, it's more efficient and correct to let Impeller manage its own swapchain via SurfaceContextVK, which handles image acquisition, present timing, and swapchain recreation on resize. The surface field on FlutterVulkanRendererConfig lets each platform pass in a VkSurfaceKHR created from the native window handle (HWND, X11 Window, wl_surface). When present, the embedder skips the callback-based image path and delegates swapchain management entirely to Impeller.

3. GPU surface improvements

File Change
shell/gpu/gpu_surface_vulkan_impeller.{cc,h} Added frame throttling fences, per-frame resource recycling via DisposeThreadLocalCachedResources() and DidAcquireSurfaceFrame(), and swapchain transient management to prevent resource leaks in the non-KHR (embedder-managed image) path

Why: Without frame throttling, the GPU surface submits work faster than the GPU can complete it, causing VK_ERROR_OUT_OF_HOST_MEMORY. The fence-based throttle (WaitForFence + ResetFence) ensures each frame completes before the next begins. Per-frame resource recycling (command pools via Reclaim(), descriptor pools via pool recycler) prevents per-frame resource accumulation.

4. Impeller Vulkan backend hardening

File Change
render_pass_builder_vk.{cc,h} Added SetFramebufferFetchEnabled() to conditionally omit input attachment references and self-dependencies. Refactored subpass dependencies from hardcoded array indices to a counted builder pattern
blit_pass_vk.{cc,h} Added workaround to skip sub-region buffer-to-image copies on drivers with broken minImageTransferGranularity. Added allocator_ member for staging texture allocation
workarounds_vk.{cc,h} Added skip_sub_region_buffer_to_image_copy workaround flag, detected for Mesa dzn driver via is_mesa_dzn helper
context_vk.{cc,h} Relaxed VK_KHR_swapchain validation to log info instead of returning null when the extension is unavailable (it is optional for embedder-managed rendering)
driver_info_vk.{cc,h} Added Mesa dzn driver identification via VendorVK::kMesa and VK_DRIVER_ID_MESA_DOZEN driver ID check
command_pool_vk.{cc,h} Null-safety for early destruction during engine teardown. Added handle validation. Changed context_ from reference-to-weak_ptr to value copy for safe use after constructor scope. Added IPLR_GUARDED_BY(pool_mutex_) annotation on unused_command_buffers_
command_queue_vk.{cc,h} Added in-flight submission throttling with InFlightState struct, condition variable, and kMaxInFlightSubmissions cap
command_buffer_vk.cc Added tracked objects null-check for safe teardown
pipeline_vk.cc Null guard for pipeline library access during teardown
render_pass_vk.cc Propagate supports_framebuffer_fetch_ flag to render pass creation
descriptor_pool_vk.{cc,h} Pool maxSets is computed as the sum of per-type pool sizes (804 total). Fixed doc comment referring to wrong pool type
tracked_objects_vk.{cc,h} Integration point for per-frame resource lifecycle management
allocator_vk.cc Added VMA pool cap (256 blocks), Windows Resizable BAR working set trimming
capabilities_vk.cc Added VK_KHR_surface and VK_KHR_swapchain to required extensions for desktop
render_target_cache.{cc,h} Made MSAA resolve target cache resize-aware

Why each change was necessary:

  • render_pass_builder_vk: Mesa dzn doesn't support subpass self-dependencies, causing vkCreateRenderPass to fail. The refactored builder lets the context disable framebuffer fetch at runtime. Additionally, VK_DEPENDENCY_BY_REGION_BIT was removed from the incoming and outgoing external dependencies (VK_SUBPASS_EXTERNAL) where it is meaningless per Vulkan spec section 7.1 — the flag is only defined for self-dependencies.
  • blit_pass_vk: Mesa dzn reports minImageTransferGranularity = {0,0,0} and corrupts textures on sub-region copies. The staging workaround copies the entire buffer to a temporary texture, then blits only the needed region.
  • command_queue_vk: Without throttling, the host queues submissions faster than the GPU drains them. On a benchmark running at 1000+ FPS (debug, minimal scene), this exhausts host memory within minutes.
  • descriptor_pool_vk: Pool maxSets is now the sum of per-type pool sizes (804 total: 256 texture + 512 buffer + 32 storage + 4 subpass). Pool reset via Reclaim() in DescriptorPoolRecyclerVK prevents pool exhaustion across frames.
  • allocator_vk: VMA's memory pool grows monotonically. The 256-block cap prevents unbounded growth. The Windows EmptyWorkingSet trimming addresses a cosmetic but alarming RSS inflation caused by Resizable BAR.

5. Linux platform integration

File Change
shell/platform/linux/fl_vulkan_manager.{cc,h} New. GObject-based Vulkan resource manager. Manages Vulkan instance, device selection (prefers discrete GPUs), logical device, queue, and surface creation for both X11 and Wayland
shell/platform/linux/fl_engine.cc Added Vulkan renderer type handling, persistent cache directory setup, and native window callback integration
shell/platform/linux/fl_engine_private.h Exposed Vulkan manager accessors internally
shell/platform/linux/fl_view.cc Vulkan manager setup when renderer type is Vulkan — Impeller manages the swapchain directly via KHR swapchain mode (no compositor needed)
shell/platform/linux/public/flutter_linux/fl_engine.h Added FlRendererType enum (OpenGL, Software, Vulkan) and public fl_engine_get_rendering_backend() API
shell/platform/linux/BUILD.gn Added Vulkan manager and compositor sources with dependencies

Why: Linux needed a platform-specific Vulkan manager because GDK provides the native window handles (X11 Window or Wayland wl_surface). The manager handles:

  • Physical device selection (prefers VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
  • Thread-safe shutdown via g_atomic_int_set/g_atomic_int_get
  • VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT conditionally added based on caps.supportedUsageFlags (avoids swapchain creation failure on software/translation-layer drivers)
  • One-time availability check via g_once_init_enter/g_once_init_leave

6. Windows platform integration

File Change
shell/platform/windows/vulkan_manager.{cc,h} New. Vulkan resource manager for Windows. Creates Vulkan instance, selects physical device, creates logical device, manages Win32 surface and swapchain image views. Supports validation layers via FLUTTER_VULKAN_VALIDATION=1
shell/platform/windows/flutter_windows_engine.{cc,h} Added Vulkan initialization path: GetVulkanRendererConfig() passes VkSurfaceKHR via ReleaseSurface(), Vulkan device info, and no-op callbacks for KHR swapchain mode. Display refresh rate detection for Vulkan vsync
shell/platform/windows/flutter_window.{cc,h} Added GetWindowHandle() to expose HWND for Vulkan surface creation
shell/platform/windows/flutter_windows_view.{cc,h} Vulkan-aware compositor initialization
shell/platform/windows/flutter_windows.cc Added FlutterDesktopEngineGetRenderingBackend() public API implementation
shell/platform/windows/public/flutter_windows.h Added FlutterDesktopEngineGetRenderingBackend() public API and FlutterDesktopRendererType enum (OpenGL, Software, Vulkan)
shell/platform/windows/window_binding_handler.h / testing/mock_window_binding_handler.h Added GetWindowHandle() to window binding interface and mock
shell/platform/windows/BUILD.gn Added Vulkan manager sources and vulkan-1.lib dependency

Why: Windows integration follows the same pattern as Linux — a platform-specific Vulkan manager creates the instance, device, and surface, then passes the VkSurfaceKHR to the embedder. The FlutterDesktopRendererType enum (set via FlutterDesktopEngineProperties) allows apps to opt in to Vulkan before engine startup.

7. RenderingBackend API (framework)

File Change
lib/ui/platform_dispatcher.dart Added RenderingBackend enum (opengl, vulkan, software, metal, canvaskit, skwasm) and PlatformDispatcher.renderingBackend getter
lib/ui/dart_ui.cc C++ constants for rendering backend indices, set during engine initialization
lib/ui/natives.dart _renderingBackend variable set by the engine at startup
lib/web_ui/lib/platform_dispatcher.dart Web-side RenderingBackend enum (mirrors native) and abstract getter
lib/web_ui/lib/src/engine/platform_dispatcher.dart Web implementation: canvaskit for CanvasKitRenderer, skwasm for SkwasmRenderer
packages/flutter/lib/src/foundation/rendering_backend.dart Framework-level defaultRenderingBackend convenience getter
packages/flutter/lib/foundation.dart Export of rendering_backend.dart

Why: Currently, there is no public API for apps or tooling to query which rendering backend is active. The RenderingBackend enum covers all six backends (opengl, vulkan, software, metal, canvaskit, skwasm). The engine sets the value at startup via a native call, and the framework exposes it through PlatformDispatcher.renderingBackend. This enables:

  • Benchmark apps to display the active renderer
  • Conditional logic based on rendering backend (e.g., workarounds for backend-specific behaviors)
  • Diagnostic tooling (DevTools could show the active backend)

8. Flutter Tools

File Change
packages/flutter_tools/lib/src/desktop_device.dart When Impeller is enabled on Linux or Windows, also pass --impeller-backend=vulkan to request the Vulkan backend

9. Miscellaneous

File Change
display_manager.cc HMONITOR sign-extension fix -- mask to 32 bits to prevent DartConverter<unsigned long long> assertion overflow

Testing

Automated tests

Test file What it covers
fl_vulkan_manager_test.cc Vulkan manager creation, availability detection
vulkan_native_surface_linux_test.cc Linux Vulkan surface creation
fl_engine_test.cc Engine rendering backend getter, Vulkan env-var selection with fallback
vulkan_manager_unittests.cc Windows Vulkan manager creation
platform_dispatcher_test.dart (native) RenderingBackend enum values, renderingBackend getter
platform_dispatcher_test.dart (web) Web-specific rendering backend detection
rendering_backend_test.dart Framework defaultRenderingBackend getter
desktop_device_test.dart Vulkan backend flag passed when Impeller enabled on Linux/Windows

Manual stress testing

All manual testing used flutter-benchmark — a 9-scene GPU stress-test suite covering particles, nested widgets, bezier curves, image composition, text rendering, transforms, shader masks, deep opacity trees, and non-uniform text scaling.

Platform OS GPU Driver Result
Windows (native) Windows 10 Pro (build 19045) AMD Radeon RX 6750 XT (RDNA 2, 12 GB VRAM, Resizable BAR) Adrenalin 25.x PASS — Impeller Vulkan, all 9 scenes, multiple runs, no crashes or rendering artifacts
Windows (native) Windows 10 Pro (build 19045) AMD Radeon RX 6750 XT Adrenalin 25.x PASS — Skia/ANGLE baseline comparison, no regressions
WSL 2 Ubuntu 24.04, kernel 6.6.87 Mesa dzn (D3D12 translation via WSLg) Mesa 24.x PASS — Impeller Vulkan, all 9 scenes, zero errors
WSL 2 Ubuntu 24.04, kernel 6.6.87 Mesa dzn (D3D12 translation via WSLg) Mesa 24.x PASS — Skia/OpenGL baseline, no regressions
Android Android 15 (API 35) Samsung Xclipse 940 (Samsung Galaxy S24) Vulkan 1.3.279 PASS — app runs, see note below

Android note: The benchmark app runs on Android with this engine build. Most scenes complete without issue, but extreme stress tests (10,000-particle scenes, rapid text rendering with large glyph atlases) can trigger OOM or driver timeouts on mobile SoCs. This is not a regression — the same behavior occurs on the upstream engine without any of our changes. Desktop Vulkan is the focus of this PR; Android Vulkan was already supported and is unchanged by this PR.

Key stability metrics (Windows, Impeller Vulkan, Release build):

  • No VK_ERROR_OUT_OF_HOST_MEMORY after multiple sessions of continuous benchmark runs
  • Working set stabilizes at ~550 MB (Resizable BAR maps VRAM; actual CPU allocation ~180 MB)
  • No crashes, no text corruption, no rendering artifacts

More verifications welcome! My hardware is limited to AMD RDNA 2 + Samsung Exynos. Testing on NVIDIA, Intel, and other mobile SoCs would be valuable.

Build verification

Target Platform Result
flutter/shell/platform/windows:flutter_windows Windows (debug unopt) PASS
flutter/shell/platform/windows:flutter_windows Windows (release) PASS
flutter/shell/platform/linux:flutter_linux_gtk Linux (debug unopt) PASS
flutter/shell/platform/linux:flutter_linux_gtk Linux (release) PASS

Discussion Points

RSS working-set trim cooldown assumes 60 fps

The kTrimCooldownFrames = 300 constant in allocator_vk.cc yields a ~5 s cooldown at 60 fps but only ~1.25 s at 240 Hz. Since EmptyWorkingSet merely moves pages to the standby list (they fault back in on next access) and the trigger conditions are already conservative (RSS > 1 GB, RSS > 4x VMA), the practical impact is negligible at any refresh rate. A time-based cooldown via std::chrono would be more precise but adds per-frame clock overhead for no measurable benefit. Feedback welcome on whether a frame-count heuristic is acceptable here.

Runtime Vulkan crash recovery as a longer-term alternative?

The current approach (static blocklist via IsKnownBadDriver()) is reactive: we discover a bad GPU/driver, add it to the list, ship a new Flutter release, and users still suffer until they update. This raises a question worth discussing:

Could Flutter detect Vulkan failures at runtime and automatically fall back to GLES?

Today, if a Vulkan driver returns VK_ERROR_DEVICE_LOST or hangs during rendering, there is no recovery path — the app freezes or crashes. The rendering backend is locked in at startup. In principle, the engine could:

  1. Detect VK_ERROR_DEVICE_LOST or repeated command submission failures during rendering.
  2. Persist a "Vulkan failed on this device" flag (e.g., in SharedPreferences or a file in the app's cache directory).
  3. On next launch, check the flag and skip Vulkan entirely, going straight to GLES — similar to how Chrome's GPU process restart works.
  4. Optionally report the failure (GPU name, driver version, SoC, failure mode) back to a telemetry endpoint so the Flutter team can proactively update the static blocklist.

Benefits:

  • Self-healing: devices with bad Vulkan drivers would automatically fall back after one crash, without waiting for a Flutter release.
  • Data-driven: telemetry would replace the current manual process of discovering bad GPUs from GitHub issues.
  • Reduced blocklist maintenance: the static list could be kept minimal, with runtime detection as the safety net.

Challenges:

  • Data privacy: Any telemetry reporting would need to be opt-in and compliant with GDPR/platform privacy policies. Device identifiers (GPU name, driver version) are arguably not PII, but the reporting mechanism itself would need careful design and user consent.
  • Init-time hangs: If the driver hangs during ContextVK::Create() (as seen on Mali-G52), the crash detection never fires — the process is killed by Android's ANR watchdog. A persistent flag set before Vulkan init ("attempting Vulkan...") and cleared on success could handle this case, but adds complexity.
  • Complexity: Tearing down a Vulkan context mid-session and rebuilding with GLES while keeping the Dart isolate alive is architecturally very difficult. The per-launch flag approach (crash → flag → next launch uses GLES) is more practical.

This PR takes the pragmatic immediate fix (static block), but the runtime detection approach could be a valuable longer-term investment for the Impeller team, especially as the number of Android GPU/driver/SoC combinations continues to grow.

Engine reliability under extreme GPU stress

During stress testing with flutter-benchmark, I observed that the engine can crash on mobile SoCs (Samsung Xclipse 940) under extreme workloads — 10,000 simultaneous particles, rapid large-atlas text reflows, and concurrent heavy shader effects. The crashes are OOM kills or GPU driver timeouts, not Vulkan validation errors. Crucially, this is not a regression from this PR — the same crashes reproduce on the upstream engine with identical test scenes. No real-world app would sustain these workloads, but the observation suggests the engine could benefit from more graceful degradation under resource pressure (e.g., frame dropping, allocation throttling, or LOD reduction). This would be a separate effort outside the scope of this PR.

Notes for reviewers

Activation & backward compatibility

  • Opt-in only: Vulkan is not the default on any platform. Linux: FLUTTER_LINUX_RENDERER=vulkan. Windows: set FlutterDesktopRendererVulkan renderer type before engine startup.
  • No behavioral changes to the existing Android Vulkan path.
  • Purely additive: RenderingBackend enum, Vulkan managers, embedder callbacks, and workaround flags are all new — no existing APIs are modified or removed.

Thread safety

  • FlVulkanManager uses g_atomic_int_set/g_atomic_int_get for its shutting_down flag (accessed from both UI and raster threads).
  • CommandQueueVK::InFlightState uses std::mutex + std::condition_variable for in-flight submission tracking.
  • Windows VulkanManager is created on the platform thread and accessed from the raster thread; all shared state is set before engine start.

Driver compatibility

  • VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT conditionally added based on caps.supportedUsageFlags — avoids swapchain creation failures on software/translation-layer drivers.
  • Mesa dzn workarounds (sub-region copy, framebuffer fetch, no-wait for fence timeout) keyed on VK_DRIVER_ID_MESA_DOZEN via GetDriverID() (Vulkan 1.2+).
  • Graceful fallback: Linux → OpenGL; Windows → software rendering if Vulkan is unavailable.

Memory management

  • VMA pool capped at 256 blocks to prevent unbounded growth.
  • In-flight submission limit (kMaxInFlightSubmissions) prevents host memory exhaustion under sustained high-FPS workloads.
  • Windows Resizable BAR: periodic EmptyWorkingSet() trims inflated RSS (cooldown: 300 frames, threshold: RSS > 1 GB + VMA < 256 MB + RSS/VMA > 4×). This is cosmetic — the pages are GPU-mapped VRAM, not leaked memory.

Areas that may benefit from extra scrutiny

  1. Embedder API surface — the new FlutterVulkanSurfaceHandle surface field on FlutterVulkanRendererConfig, SetSurfaceSizeUpdater(), and UpdateSurfaceSize() are public API additions.
  2. Resource lifecycle — frame throttling, pool capping, and command pool recycling are central to stability under sustained workloads.
  3. Driver workarounds — the Mesa dzn workarounds are scoped to VK_DRIVER_ID_MESA_DOZEN; other translation-layer drivers may need similar treatment in the future.
  4. RenderingBackend enum — new framework-level API. The backing index values (0–5) are set by the engine at startup and should remain stable.

Pre-existing formatting deviations in adjacent files

During clang-format validation of this PR, I observed that the following upstream files in the repository contain pre-existing formatting deviations from the project's .clang-format style. These files are not modified by this PR and are listed here for transparency:

  • common/graphics/persistent_cache.cc
  • lib/ui/plugins/callback_cache.cc
  • shell/common/engine.cc
  • shell/common/shell.cc
  • shell/platform/windows/platform_handler.cc

All files modified by this PR have been formatted with clang-format --style=file.

Pre-launch Checklist

Add Vulkan rendering support for Flutter desktop applications on Linux
and Windows. This uses Impeller's existing KHR swapchain codepath (the
same path used by Android) so the engine manages the swapchain
internally, avoiding duplicated swapchain state in platform code.

Includes comprehensive Vulkan backend stability fixes discovered during
sustained stress testing on AMD RDNA 2 hardware (Radeon RX 6750 XT).

Linux Platform Integration:
- fl_vulkan_manager.{cc,h}: Vulkan instance, device, queue, and surface
  management for GTK. Supports X11 and Wayland via GDK with Wayland
  subsurface positioning for header-bar-aware rendering.
- fl_engine.cc: FLUTTER_LINUX_RENDERER=vulkan env var support with
  graceful fallback to OpenGL. Auto-enables Impeller when Vulkan is
  selected (no Skia+Vulkan desktop path exists).
- fl_view.cc: Vulkan mode setup, first-frame workaround, subsurface
  geometry updates. No compositor in Vulkan mode -- Impeller manages
  the swapchain directly via KHR swapchain.
- vulkan_native_surface_linux.{cc,h}: VulkanNativeSurface for X11
  (VK_KHR_xlib_surface) and Wayland (VK_KHR_wayland_surface).

Windows Platform Integration:
- vulkan_manager.{cc,h}: VkInstance/VkDevice/VkSurfaceKHR lifecycle for
  Win32 (VK_KHR_win32_surface). Discrete GPU preference, validation
  layer support gated behind FLUTTER_VULKAN_VALIDATION=1.
- flutter_windows_engine.cc: Vulkan renderer selection, KHR swapchain
  config, --impeller-backend=vulkan flag injection. EGL fallback when
  Vulkan surface creation fails.
- flutter_window.cc: WM_ACTIVATE handler with InvalidateRect for
  swapchain recovery after occlusion.

Embedder Integration:
- embedder.h: New FlutterVulkanSurfaceHandle typedef and surface field
  in FlutterVulkanRendererConfig (backward-compatible via struct_size).
- embedder_surface_vulkan_impeller.{cc,h}: KHR swapchain mode when
  VkSurfaceKHR is provided. Conditional VK_EXT_debug_utils detection.
  Initial surface extent query with Wayland fallback.
- embedder_engine.{cc,h}: SetSurfaceSizeUpdater posts resize to raster
  thread on SetViewportMetrics.

Vulkan Rendering Stability:
- blit_pass_vk.cc: Fix six barriers -- pre-copy barriers use correct
  eTransfer/eTransferWrite stages, post-copy barriers flush transfer
  write caches, mipmap barriers match actual current layout. Fixes
  corrupted atlas glyphs and SYNC-HAZARD-WRITE-AFTER-WRITE on AMD RDNA.
- render_pass_builder_vk.cc: Conditionally include depth/stencil stages
  and access flags in subpass dependencies when depth attachment present.
  Remove eByRegion from external dependencies (meaningless per Vulkan
  spec section 7.1 for VK_SUBPASS_EXTERNAL).
- khr_swapchain_impl_vk.cc: Re-signal synchronizer fence on failed
  acquireNextImageKHR. Prevents raster thread deadlock with
  kMaxFramesInFlight=2. Short-circuit if device is marked lost.
- khr_swapchain_vk.cc: Zero-extent surface guard for minimized windows.
- gpu_surface_vulkan_impeller.{cc,h}: Frame throttling fences
  (kMaxFramesInFlight=2) with timeout-based skip. Present barrier.
  Resize fence drain before destroying cached image views.

Memory Management:
- allocator_vk.cc: Staging buffer pool cap (maxBlockCount=256, 1 GB).
  Working set trim on Windows via EmptyWorkingSet() when RSS > 1 GB and
  > 4x VMA usage (300-frame cooldown). Reclaims Resizable BAR pages.
- render_target_cache.cc/h: Hard cap of 256 entries with stable
  partition eviction (used-this-frame first, unused FIFO).

Resource Lifecycle Safety:
- command_pool_vk.{cc,h}: AbandonForDriverCrash() releases handles
  without Vulkan API calls. Buffer release before resetCommandPool.
  Recycled pool eviction oldest-first, cap 8. IPLR_GUARDED_BY
  annotation for unused_command_buffers_. context_ stored by value.
- command_queue_vk.{cc,h}: On vkQueueSubmit failure: abandon tracked
  objects, mark device lost, log heap budgets, release fence. Chunked
  submission in batches of 64.
- context_vk.{cc,h}: Atomic device_lost_ flag with IsDeviceLost()/
  MarkDeviceLost(). CreateCommandBuffer() short-circuits when lost.
  Chunked flush (64 per batch).
- tracked_objects_vk.{cc,h}: AbandonForDriverCrash() releases command
  buffer handle, abandons pool, releases descriptor pools.
- descriptor_pool_vk.{cc,h}: AbandonForDriverCrash(). vkResetDescriptor-
  Pool on reclaim (previously stayed at capacity causing
  VK_ERROR_OUT_OF_POOL_MEMORY on every reuse).

Vulkan Infrastructure:
- vulkan_proc_table.{cc,h}: DestroySurfaceKHR, CreateWin32SurfaceKHR,
  CreateXlibSurfaceKHR, CreateWaylandSurfaceKHR procs. Swapchain procs
  shared across Android/Linux/Windows.
- vulkan_interface.h: Platform surface extension defines for Win32,
  X11, Wayland.
- capabilities_vk.cc: Enumerate instance layers in embedder mode.
- workarounds_vk.{cc,h}: Mesa dzn sub-region copy workaround.
- driver_info_vk.{cc,h}: GetDriverID() for driver-specific detection.

dart:ui API:
- RenderingBackend enum (opengl, vulkan, software, metal, canvaskit,
  skwasm) and PlatformDispatcher.renderingBackend getter on both native
  and web. Engine sets the value via Dart_SetField during init.
- Framework-level defaultRenderingBackend getter in foundation library.

Build and Tooling:
- linux/BUILD.gn: Vulkan sources and dependencies.
- windows/BUILD.gn: Vulkan manager sources and test.
- vulkan/BUILD.gn: Linux native surface sources.
- runtime/dart_vm.cc: Platform::Initialize() signature fix.

Validated on AMD Radeon RX 6750 XT (RDNA 2, 12 GB, Resizable BAR,
Windows 10 Pro) and Mesa dzn (D3D12 translation via WSL2). All 9
benchmark scenes (https://github.com/sero583/flutter-benchmark) complete
without crash, deadlock, or validation error under
VK_LAYER_KHRONOS_validation.

Fixes: flutter#181711
@sero583 sero583 requested review from a team and loic-sharma as code owners March 8, 2026 22:34
@github-actions github-actions Bot added tool Affects the "flutter" command-line tool. See also t: labels. framework flutter/packages/flutter repository. See also f: labels. engine flutter/engine related. See also e: labels. platform-windows Building on or for Windows specifically platform-web Web applications specifically platform-linux Building on or for Linux specifically a: desktop Running on desktop e: impeller Impeller rendering backend issues and features requests team-windows Owned by the Windows platform team team-linux Owned by the Linux platform team labels Mar 8, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Vulkan rendering support for Flutter on Linux and Windows desktops by integrating Impeller's existing Vulkan backend. The changes are extensive, spanning the embedder API, platform-specific Vulkan managers, and numerous stability and performance enhancements in the Impeller backend itself. Key improvements include robust resource management through frame throttling and pool capping, workarounds for specific driver issues like Mesa's dzn, and a new framework-level API to expose the active rendering backend. The implementation appears thorough and well-executed. My review includes a couple of suggestions for improving robustness and code clarity.

// budget_props.heapBudget[i] == 0 means the extension data wasn't
// filled (driver too old or extension not exposed). In that case we
// fall back to just logging the static heap size.
bool has_budget = budget_props.heapBudget[0] != 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Relying on heapBudget[0] != 0 to detect if the VK_EXT_memory_budget extension is active seems a bit fragile. While a heap budget of zero is unlikely for a usable heap, it's not strictly impossible for a driver to report that for the first heap. A more robust approach would be to directly check if the extension was enabled when the context was created.

You can get the capabilities from the context and check for the extension's presence, which would be a more direct and reliable signal.

Suggested change
bool has_budget = budget_props.heapBudget[0] != 0;
bool has_budget = context->GetCapabilities()->HasExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);

Comment on lines +264 to +278
#ifndef FLUTTER_RELEASE
// Honor explicit backend request in debug/profile builds.
// Vulkan is gated to debug/profile until the implementation stabilizes.
// TODO(sero583): Enable Vulkan in release builds once validated.
bool vulkan_requested = false;
for (const auto& sw : switches) {
if (sw == "--impeller-backend=vulkan") {
vulkan_requested = true;
break;
}
}
#else
bool vulkan_requested = false;
#endif // FLUTTER_RELEASE

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This preprocessor block can be simplified for better readability and to avoid redundancy. The vulkan_requested variable can be initialized to false once, and the #else block, which just duplicates this initialization, can be removed entirely.

Suggested change
#ifndef FLUTTER_RELEASE
// Honor explicit backend request in debug/profile builds.
// Vulkan is gated to debug/profile until the implementation stabilizes.
// TODO(sero583): Enable Vulkan in release builds once validated.
bool vulkan_requested = false;
for (const auto& sw : switches) {
if (sw == "--impeller-backend=vulkan") {
vulkan_requested = true;
break;
}
}
#else
bool vulkan_requested = false;
#endif // FLUTTER_RELEASE
bool vulkan_requested = false;
#ifndef FLUTTER_RELEASE
// Honor explicit backend request in debug/profile builds.
// Vulkan is gated to debug/profile until the implementation stabilizes.
// TODO(sero583): Enable Vulkan in release builds once validated.
for (const auto& sw : switches) {
if (sw == "--impeller-backend=vulkan") {
vulkan_requested = true;
break;
}
}
#endif // FLUTTER_RELEASE

/// * [RenderingBackend], the enum of possible rendering backends.
RenderingBackend get renderingBackend {
return RenderingBackend._fromIndex(_renderingBackend);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we punt on exposing the rendering backend? AFAICT this is not necessary for a minimum viable product. We will likely want a separate conversation on whether we should add this or not.

FlutterDesktopRendererSoftware = 1,
// Vulkan rendering via Impeller.
FlutterDesktopRendererVulkan = 2,
} FlutterDesktopRendererType;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding a public API, let's use flags for now similar to how Flutter Windows lets you opt-in to the Impeller preview:

switch (debuggingOptions.enableImpeller) {
case ImpellerStatus.enabled:
addFlag('enable-impeller=true');
case ImpellerStatus.disabled:
case ImpellerStatus.platformDefault:
addFlag('enable-impeller=false');
}

// Gets the rendering backend used by the engine.
// Valid after the engine has been created.
FLUTTER_EXPORT FlutterDesktopRendererType
FlutterDesktopEngineGetRenderingBackend(FlutterDesktopEngineRef engine);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this as well

#ifndef FLUTTER_RELEASE
// Honor explicit backend request in debug/profile builds.
// Vulkan is gated to debug/profile until the implementation stabilizes.
// TODO(sero583): Enable Vulkan in release builds once validated.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do the same thing as Impeller above. You can't set these flags in the apps you deploy using flutter build windows.

@loic-sharma

loic-sharma commented Mar 8, 2026

Copy link
Copy Markdown
Member

@sero583 Thanks for opening this pull request!

Because this is such a significant feature, I want to make sure it gets the right eyes on it. To help with that, could you please:

  • Create a design doc: This will help stakeholders like @gaaclarke (Impeller/Engine), @robert-ancell (Linux), and myself (Windows) align on the architecture. You can find the Design Doc process here.
  • Split the PR: To make reviews more manageable, I recommend breaking this into at least three PRs:
    1. Impeller + engine changes. This must land first.
    2. Windows changes. This can proceed once the engine changes land.
    3. Linux changes. This can also proceed in parallel with Windows once the engine is ready.

Just to set realistic expectations, landing a change of this magnitude is a significant undertaking. We're very grateful for the effort, but please be prepared for a rigorous review cycle.


// |WindowBindingHandler|
virtual void SetFlutterCursor(HCURSOR cursor) override;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???

// The current cursor set by the Flutter framework. Defaults to the standard
// arrow cursor. Restored in WM_SETCURSOR to prevent stale cursors from
// persisting when the mouse re-enters the client area from non-client areas.
HCURSOR current_cursor_ = LoadCursor(nullptr, IDC_ARROW);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is LoadCursor part of this PR?

@knopp

knopp commented Mar 9, 2026

Copy link
Copy Markdown
Member

This has a very vibe-coded feel to it. How much of this was written by hand?

Also while vulkan support makes sense on Linux, I'm not entirely sure about windows.

@knopp

knopp commented Mar 9, 2026

Copy link
Copy Markdown
Member

Also I don't think we want to go with the swapchain approach? This definitely needs more discussion, but in general swapchain makes it difficult/impossible to have resize synchronization and compositor integration. I also noticed the wayland subsurface is desync on linux, definitely a problem for resizing.

If we ever have platform view on windows swapchain will be a problem. Ideally we want to render to a dxgi surface.

@sero583 sero583 marked this pull request as draft March 9, 2026 10:29
@flutter-dashboard

Copy link
Copy Markdown

This pull request has been changed to a draft. The currently pending flutter-gold status will not be able to resolve until a new commit is pushed or the change is marked ready for review again.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@sero583

sero583 commented Mar 9, 2026

Copy link
Copy Markdown
Contributor Author

@loic-sharma Thanks for the guidance. I'lll

  1. Write a design doc covering architecture, tradeoffs (KHR swapchain vs compositor-based), and per-platform strategy. Quick question — does the Flutter team prefer a formal design doc over a detailed markdown like the current PR description, or is a short PR description with an extensive design doc better?
  2. Split into focused PRs as suggested (engine/Impeller first, then platform-specific)

Converting this to a draft for now since it needs further discussion and refinement.

@gaaclarke Since you own Impeller - would the Vulkan backend stability fixes (blit pass barrier corrections, command pool lifecycle safety, device-lost recovery, descriptor pool reset) be welcome as a standalone PR? These were discovered through sustained stress testing on AMD RDNA 2 and are independent of the desktop platform integration.

@sero583

sero583 commented Mar 9, 2026

Copy link
Copy Markdown
Contributor Author

@knopp Thanks for the review.

LoadCursor: Not Vulkan-specific - this is a general Windows fix for stale resize cursors. Will split it into its own PR.

Swapchain approach: Agreed on the limitations. The KHR swapchain path was chosen deliberately to reuse Impeller's battle-tested Android codepath (KHRSwapchainImplVK) and minimize new swapchain management code. That said, you're right that it blocks compositor integration and platform views on desktop. The design doc will evaluate:

  • Windows: DXGI swapchain as the primary path (native DWM integration, proper resize sync), with Vulkan as an option for ARM SoCs (Snapdragon X Elite/Plus, Mediatek) where Vulkan drivers often have stronger conformance than D3D12 translation layers
  • Linux/Wayland: Synchronized subsurface with proper commit coordination instead of desync mode
  • Linux/X11: Direct window surface (fewer constraints than Wayland)

Vulkan on Windows: I'd push back slightly on dropping it entirely. The Windows-on-ARM ecosystem is growing - Qualcomm Adreno and ARM Mali drivers on these devices ship Vulkan natively, and for some workloads Vulkan outperforms the D3D12 translation path. A hybrid approach (DXGI primary + Vulkan fallback) could serve both ecosystems without significant maintenance cost.

Wayland desync: Acknowledged, synchronized mode is the correct approach.

Re "vibe-coded" - this is several weeks of hands-on development with VK_LAYER_KHRONOS_validation sync validation, systematic barrier analysis (SYNC-HAZARD-WRITE-AFTER-WRITE on vkCmdBeginRenderPass, VUID-vkDestroyFence-fence-01120 after failed vkQueueSubmit), and stress testing across 9 benchmark scenes on AMD RDNA 2. Each stability fix traces to a specific validation error or crash scenario. Happy to walk through any change in detail.

@loic-sharma

loic-sharma commented Mar 9, 2026

Copy link
Copy Markdown
Member

Quick question — does the Flutter team prefer a formal design doc over a detailed markdown like the current PR description, or is a short PR description with an extensive design doc better?

@sero583 Please see the design Doc guidance. TLDR: A google doc that uses our template is preferred, stakeholders can leave feedback on the content. It's fine for a PR description to be short if it links to the design doc, but feel free to make the PR description detailed as well.

@knopp

knopp commented Mar 9, 2026

Copy link
Copy Markdown
Member

Windows: DXGI swapchain as the primary path

Actually no. Not the swapchain, not if we want to have platform views on windows at some point. I meant into a DXGI resource that we can present (or obtain through dcomp surface).

You keep mentioning d3d12 translation layers? What are those? I was under the impression that snapdragon has native d3d12 drivers.

@sero583

sero583 commented Mar 11, 2026

Copy link
Copy Markdown
Contributor Author

@knopp You're right on both counts. On the DXGI point - the design doc targets VkImage → DXGI resource → DComp, not swapchain. On "translation layers" - poor wording on my part; I was thinking of Mesa dzn (Vulkan-on-D3D12 in WSL2) and carelessly applied the term to Snapdragon, which has native drivers. Both corrections are reflected in the design doc: #183495

@sero583

sero583 commented Mar 11, 2026

Copy link
Copy Markdown
Contributor Author

Design doc and tracking issue are up: #183495 as already previously mentioned in my comment to knopp.

@loic-sharma @gaaclarke - feedback welcome. Holding off on PR changes until the architecture is agreed on.

Update: PR got merged, design doc is now up at https://flutter.dev/go/impeller-backend-desktop

sfshaza2 pushed a commit to flutter/website that referenced this pull request Mar 11, 2026
_Description of what this PR is changing or adding, and why: Adds a
redirect for a design document.

_Issues fixed by this PR (if any):_

_PRs or commits this PR depends on (if any):_
flutter/flutter#183382

## Presubmit checklist

- [x] If you are unwilling, or unable, to sign the CLA, even for a
_tiny_, one-word PR, please file an issue instead of a PR.
- [x] If this PR is not meant to land until a future stable release,
mark it as draft with an explanation.
- [x] This PR follows the [Google Developer Documentation Style
Guidelines](https://developers.google.com/style)—for example, it doesn't
use _i.e._ or _e.g._, and it avoids _I_ and _we_ (first-person
pronouns).
- [x] This PR uses [semantic line
breaks](https://github.com/dart-lang/site-shared/blob/main/doc/writing-for-dart-and-flutter-websites.md#semantic-line-breaks)
  of 80 characters or fewer.

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@sero583

sero583 commented Apr 8, 2026

Copy link
Copy Markdown
Contributor Author

Hey @loic-sharma and @jtmcdole, thanks for the feedback!

I've updated the design doc and left detailed replies to your comments. Specifically, I created a new tab called 'Addressing ANGLE concerns' to break down the translation layer costs, and replied to the Vulkan/OpenGL fallback thread. Let me know what you think when you have a chance to review.

@josetr

josetr commented Apr 28, 2026

Copy link
Copy Markdown

I've been trying to get my flutter app to work smoothly on all desktop platforms, and Linux Mint 22.3 seems to be the one where I can't do it with OpenGL + NVIDIA 3050.

Vulkan seems to solve my problem, but right now the image quality with this PR doesn't seem to be the same as OpenGL

Screenshot from 2026-04-28 18-01-02 Screenshot from 2026-04-28 18-02-30

@sero583

sero583 commented Apr 28, 2026

Copy link
Copy Markdown
Contributor Author

Hey @josetr,

thanks for the feedback! The visual difference you're noticing stems from the fact that the current OpenGL path uses Skia as its renderer, whereas this PR introduces Impeller with Vulkan support. The two engines do render slightly differently - this is an inherent tradeoff for Impeller's improved performance and the elimination of shader compilation jank.

Regarding the status of this PR: I'm currently awaiting feedback from the team on the proposed architecture via Google Docs, as the current PoC is still a bit rough around the edges. Work is on hold until we reach a consensus, though I believe the proposal is already heading in the right direction. It may just need a few adjustments here and there. I'm looking forward to finalizing this and getting it merged.

As for your OpenGL issue on Linux Mint 22.3 - could you share the output of flutter doctor -v, your NVIDIA driver version (nvidia-smi), and the full error log or stack trace you're seeing? It would also help to know whether you're running X11 or Wayland and which desktop environment you're using. If you've already opened a separate issue for this, feel free to link it here as well.

@josetr

josetr commented May 4, 2026

Copy link
Copy Markdown

Is Impeller supposed to render buttons like that one that poorly everywhere else it's being used right now? Feels like it may be related to this PR.

As for the OpenGL issue, it seems to be located at

glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, self->pixels);

Since I'm on Linux Mint - X11, self->shareable is false, and therefore I'll pay for glReadPixels every frame. The bigger I resize my app, the worse it gets.

Wayland users won't experience this problem since shareable will be true for them. I confirmed this after installing Ubuntu 26 (Wayland).

A workaround seems to be to use fl_dart_project_set_ui_thread_policy(project, FL_UI_THREAD_POLICY_RUN_ON_SEPARATE_THREAD), making it less noticeable. I still dont get 60fps using that, but it does help.

As an experiment, what worked for me was forking Flutter & using the GLX + X11 APIs directly. Only then I get consistent 60fps.

https://github.com/josetr/flutter/commits/glx

@sero583

sero583 commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

@josetr Thanks for the screenshots and all the detail about your setup.

Just to clarify scope: this PR wires the existing Impeller Vulkan backend into the Linux/Windows embedders and hardens that backend for stability. It doesn't add a new “desktop-only” rendering path, so the visual differences you're seeing between the left (Skia/OpenGL) and right (Impeller/Vulkan) captures aren't caused by the desktop wiring itself – they come from Impeller vs Skia using different rendering pipelines.

Some differences between Skia and Impeller are expected, but from your images it does look like the Impeller output is a quality regression rather than just "slightly different". That's something that should be tracked and tuned in the core Impeller/Vulkan backend (and compared with Android Impeller behavior), not left as-is.

If you're okay with it, I'd suggest opening a separate Impeller issue that links to your comment here and your GLX branch. That way the rendering team can look at the specific button case you've highlighted while this PR stays focused on getting the desktop Vulkan wiring and stability improvements landed.

@sero583

sero583 commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

Hi @loic-sharma @jtmcdole,

quick follow-up from my side: the design doc at https://flutter.dev/go/impeller-backend-desktop has been updated based on your earlier feedback (including the "Addressing ANGLE concerns" tab and the Vulkan vs OpenGL fallback discussion), and all open comments there have replies.

Before I start splitting this into the recommended sequence (Impeller/engine -> Windows -> Linux) and reworking the PoC to match the doc, I'd really appreciate a quick read on whether the proposed architecture looks acceptable in principle, or if there are any fundamental changes you would like to see first. I'd like to keep moving on this, but I want to make sure the direction is aligned with the team's expectations.

Once I have a green light on the high-level direction, I'll proceed with the split and send focused PRs for review.

@dongfengweixiao

Copy link
Copy Markdown

This effort is beneficial for enhancing video playback performance on the Linux desktop. During my testing, employing mpv to directly play videos consumed less than 5% of the CPU. However, when utilizing mpv as a backend to render videos within Flutter, CPU usage soared to 22%. The majority of this time is spent on a single task: transferring images from the GPU to the CPU and then back to the GPU. This redundant process is excessively time-consuming.

 194294 dee     20   0 6470268 359204 264616 S  21.9   1.3   0:02.69 test_video_play                                                                                                                                                                                                                                                                                                           
 193259 dee     20   0 2083460 205064 161160 S   4.6   0.7   0:07.55 mpv  

@sero583

sero583 commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

@dongfengweixiao Thanks, that means a lot - I really appreciate the feedback, and I'm glad to hear this work could help improve Linux video playback performance. At the moment, I’m mostly waiting on feedback to the design doc, since that will likely determine the broader direction for this work.
paste.txt

If things remain quiet for a while, I’ll probably start breaking out some of the smaller, self-contained enhancements into separate PRs when I have the time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: desktop Running on desktop e: impeller Impeller rendering backend issues and features requests engine flutter/engine related. See also e: labels. framework flutter/packages/flutter repository. See also f: labels. platform-linux Building on or for Linux specifically platform-web Web applications specifically platform-windows Building on or for Windows specifically team-linux Owned by the Linux platform team team-windows Owned by the Windows platform team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Linux] Add support for Vulkan

5 participants