Skip to content

[Flutter GPU] Flutter GPU ShaderLibrary in-place reload for shader hot reload#186793

Merged
auto-submit[bot] merged 10 commits into
flutter:masterfrom
bdero:bdero/fluttergpu-shader-reload
May 27, 2026
Merged

[Flutter GPU] Flutter GPU ShaderLibrary in-place reload for shader hot reload#186793
auto-submit[bot] merged 10 commits into
flutter:masterfrom
bdero:bdero/fluttergpu-shader-reload

Conversation

@bdero

@bdero bdero commented May 20, 2026

Copy link
Copy Markdown
Member

Resolves #186344.

Adds in-place shader hot reload to Flutter GPU's ShaderLibrary, mirroring the existing FragmentProgram protocol:

  • Per-shader IsDirty() / SetClean() dirty bit. Fresh shaders start dirty.
  • ShaderLibrary::ReloadFromAsset re-fetches and reparses the bundle in place. Existing Shader entries whose names appear in the new bundle are mutated via Shader::ResetFrom, preserving Dart object identity and the scoped library_id.
  • Shader::RegisterSync evicts a stale registration on the dirty path (UnregisterFunction + RemovePipelinesWithEntryPoint) before re-registering, matching RuntimeEffectContents::RegisterShader.
  • Dart-side ShaderLibrary._registry keyed by asset path, public ShaderLibrary.reinitialize, and the ext.ui.gpu.reinitializeShaderLibrary service extension lazily registered in debug mode on first fromAsset.

Tool-side integration

The engine API here is intentionally producer-agnostic. reinitialize is keyed by asset path and no-ops when nothing is registered at that key, so flutter_tools never has to classify assets: it can dispatch ext.ui.gpu.reinitializeShaderLibrary opportunistically for any changed asset path ending in .shaderbundle, and the engine ignores paths it never loaded.

Because of that, the feature works regardless of how the bundle was produced (a build hook output listed under flutter.assets:, a future DataAsset, an asset transformer, or a hand-built bundle), and it needs no new AssetKind and no dedicated flutter.gpu_shader_bundles: pubspec block. The tool-side wiring (reframed around this dispatch) is tracked in #186345, and the asset-transformer dependency-tracking piece it depends on is #187051.

Pre-launch Checklist

…eload

Mirrors FragmentProgram's hot reload protocol for flutter_gpu's
ShaderLibrary: a per-shader dirty bit, in-place reload that preserves
Dart object identity, eviction triple-call in pipeline registration,
plus a Dart-side library registry and ext.ui.gpu.reinitializeShaderLibrary
service extension.

Issue: flutter#186344
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label May 20, 2026
@github-actions github-actions Bot added engine flutter/engine related. See also e: labels. flutter-gpu team-fluttergpu Owned by Flutter GPU team labels May 20, 2026
@github-project-automation github-project-automation Bot moved this to 🤔 Needs Triage in Flutter GPU May 20, 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 implements hot reload support for Flutter GPU shader libraries by introducing a caching mechanism and a service extension for reinitialization. It enables in-place updates of native shader objects to preserve Dart object identity, ensuring stale pipelines are evicted and shader functions are re-registered. Review feedback suggests adding safety null checks when accessing the asset manager and simplifying string concatenation in the C++ implementation.

Comment thread engine/src/flutter/lib/gpu/shader_library.cc
Comment thread engine/src/flutter/lib/gpu/shader_library.cc Outdated
@github-actions github-actions Bot removed the CICD Run CI/CD label May 20, 2026
@bdero bdero added the CICD Run CI/CD label May 20, 2026
Compare code bytes in Shader::ResetFrom and only flip is_dirty_ when
they differ. A shader bundle is the unit of asset distribution, so a
one-shader edit ships a whole new bundle; without dedupe every
unchanged shader in the bundle would still be evicted and re-registered
on reload. Adds a debug-only InternalFlutterGpu_Shader_DebugIsDirty
export so the test can observe the dirty bit.
@github-actions github-actions Bot removed the CICD Run CI/CD label May 20, 2026
@bdero bdero requested a review from gaaclarke May 20, 2026 10:13
@bdero bdero changed the title [Impeller] Flutter GPU ShaderLibrary in-place reload for shader hot reload [Flutter GPU] Flutter GPU ShaderLibrary in-place reload for shader hot reload May 20, 2026
@bdero bdero moved this from 🤔 Needs Triage to ⚙️ In Progress in Flutter GPU May 20, 2026
@bdero bdero added the CICD Run CI/CD label May 20, 2026
// `ext.ui.gpu.reinitializeShaderLibrary` service extension (debug only).
// `registerExtension` throws `ArgumentError` if the same name is registered
// twice, so re-registering it confirms the lazy hook installed it.
test('Loading a shader library registers the reinitialize service extension', () async {

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 move these into shader_reload_test.dart.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Moved to new file in ec0c253.

is_dirty_ = false;
}

void Shader::ResetFrom(Shader& other) {

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 you add unit tests for these, please?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in 4b1c64b.

Comment on lines +1090 to +1092
gpu.ShaderLibrary.reinitialize('test.shaderbundle');
expect(identical(library['UnlitVertex'], vertex), isTrue);
expect(identical(library['UnlitFragment'], fragment), isTrue);

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.

Shouldn't we have a test where the loaded shaders are not identical?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in ec0c253.

…shader test

- Include pipeline_library.h in shader.cc so RemovePipelinesWithEntryPoint
  sees the full type (fixes the host_debug compile failure).
- Move the ShaderLibrary reload tests out of gpu_test.dart into a new
  shader_reload_test.dart.
- Add a fixture bundle (test_reload.shaderbundle) whose UnlitFragment
  source differs, and a test asserting reload marks only the changed
  shader dirty while the unchanged vertex stays clean.
- Add a debug-only ShaderLibrary.debugReinitializeFromAsset hook so the
  test can simulate an edited bundle.
@github-actions github-actions Bot added e: impeller Impeller rendering backend issues and features requests CICD Run CI/CD and removed CICD Run CI/CD labels May 22, 2026
bdero added 2 commits May 25, 2026 01:37
master landed testing/dart/vm_service/shader_reload_test.dart (the
FragmentProgram reload test). gn flattens kernel output to the basename,
so two shader_reload_test.dart files collide on
gen/shader_reload_test.dart.dill. Rename the Flutter GPU one to
gpu_shader_reload_test.dart.
Cover IsDirty/SetClean directly: freshly parsed shaders start dirty and
registration clears the bit.
@github-actions github-actions Bot removed the CICD Run CI/CD label May 25, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label May 26, 2026
@bdero bdero added the CICD Run CI/CD label May 26, 2026
Whether ext.ui.gpu.reinitializeShaderLibrary actually registers depends
on the build mode (asserts on but service extensions stripped in some
release configs), which is not cleanly detectable from Dart. The
reinitialize behavior is covered by the other reload tests, so drop this
plumbing-only test and its unused helper and import.
@github-actions github-actions Bot removed the CICD Run CI/CD label May 26, 2026
@bdero bdero added CICD Run CI/CD and removed CICD Run CI/CD labels May 26, 2026
@fluttergithubbot

Copy link
Copy Markdown
Contributor

An existing Git SHA, f2eaf6ef307e05c8a777b321c527463d75f12d79, was detected, and no actions were taken.

To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with --force) that already was pushed before, push a blank commit (git commit --allow-empty -m "Trigger Build") or rebase to continue.

@gaaclarke gaaclarke left a comment

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.

lgtm, you'll need to push an empty commit to retrigger ci

@github-actions github-actions Bot removed the CICD Run CI/CD label May 26, 2026
@bdero bdero added autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD labels May 26, 2026
@auto-submit

auto-submit Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/186793, because - The status or check suite Mac mac_unopt has failed. Please fix the issues identified (or deflake) before re-applying this label.

@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label May 27, 2026
@bdero bdero added the autosubmit Merge PR when tree becomes green via auto submit App label May 27, 2026
@auto-submit auto-submit Bot added this pull request to the merge queue May 27, 2026
Merged via the queue into flutter:master with commit 53bed8d May 27, 2026
211 of 212 checks passed
@github-project-automation github-project-automation Bot moved this from ⚙️ In Progress to ✅ Done in Flutter GPU May 27, 2026
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label May 27, 2026
@bdero bdero deleted the bdero/fluttergpu-shader-reload branch May 27, 2026 04:07
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request May 27, 2026
flutter/flutter@f3a4b98...c8f2f16

2026-05-27 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[Flutter GPU] Add explicit draw counts (#186639)" (flutter/flutter#187170)
2026-05-27 engine-flutter-autoroll@skia.org Roll Dart SDK from 7dcea971af6b to f3db7b7d9801 (2 revisions) (flutter/flutter#187144)
2026-05-27 bdero@google.com [Flutter GPU] Add explicit draw counts (flutter/flutter#186639)
2026-05-27 engine-flutter-autoroll@skia.org Roll Skia from f9db7748563e to fa944af10f91 (1 revision) (flutter/flutter#187139)
2026-05-27 bdero@google.com [Flutter GPU] Flutter GPU ShaderLibrary in-place reload for shader hot reload (flutter/flutter#186793)
2026-05-27 engine-flutter-autoroll@skia.org Roll Skia from a692cbf38952 to f9db7748563e (8 revisions) (flutter/flutter#187135)
2026-05-27 burak.karahan@mail.ru Use local semantics tester in Material button tests (flutter/flutter#186667)
2026-05-27 rmolivares@renzo-olivares.dev Filter out `a: text input` from `team-framework` PR triage  (flutter/flutter#187129)
2026-05-27 bkonyi@google.com [Engine] Fix silent buffer mismatch bug in FML Win32 CommandLineFromPlatform (flutter/flutter#187120)
2026-05-27 srawlins@google.com examples: Remove unused parameters (flutter/flutter#185819)
2026-05-27 116356835+AbdeMohlbi@users.noreply.github.com Remove another `String.valueOf` (flutter/flutter#186628)
2026-05-27 alex.medinsh@gmail.com Print trace when skipping flavor-specific and platform-specific assets (flutter/flutter#187045)
2026-05-26 adilhanney@disroot.org Fix `InteractiveViewer` memory leak from undisposed `CurvedAnimation`s (flutter/flutter#185826)
2026-05-26 meylis@divine.video Fix AccessibilityBridge startup crash on vendor-modified Android (flutter/flutter#184630)
2026-05-26 keertip@users.noreply.github.com Update data driven fixes docs (flutter/flutter#186217)
2026-05-26 ahmedsameha1@gmail.com Add more 0x0 size tests part10 (flutter/flutter#186201)
2026-05-26 46920873+gabrimatic@users.noreply.github.com Disable spell check for obscured text (flutter/flutter#186329)
2026-05-26 chris@bracken.jp [iOS] Migrate VSyncClient and DisplayLinkManager to Swift (flutter/flutter#187001)
2026-05-26 bkonyi@google.com [flutter_tools, devicelab] Add safety filesystem guard to tests (flutter/flutter#186748)
2026-05-26 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from Itd2Jq_ZIABH2rW7B... to k9EizfEGJO4WwQN9-... (flutter/flutter#187115)
2026-05-26 engine-flutter-autoroll@skia.org Roll Dart SDK from 00e625453c43 to 7dcea971af6b (1 revision) (flutter/flutter#187117)
2026-05-26 rmacnak@google.com Remove use of deprecated copy_trees. (flutter/flutter#187091)
2026-05-26 15619084+vashworth@users.noreply.github.com Use resolved implementation plugins with SwiftPM (flutter/flutter#187097)
2026-05-26 engine-flutter-autoroll@skia.org Roll Skia from 27a819894f7c to a692cbf38952 (3 revisions) (flutter/flutter#187109)
2026-05-26 engine-flutter-autoroll@skia.org Roll Packages from 69cf959 to fc795e5 (4 revisions) (flutter/flutter#187114)
2026-05-26 mvincentong@gmail.com Handle simctl process exceptions during discovery (flutter/flutter#186501)
2026-05-26 mvincentong@gmail.com Clarify precache enabled platforms help (flutter/flutter#186878)
2026-05-26 bkonyi@google.com [tool] Refactor artifacts.dart to use enhanced enums and reduce duplication (flutter/flutter#187063)
2026-05-26 jason-simmons@users.noreply.github.com Build script updates for syncing engine sources and building artifacts on linux-arm64 (flutter/flutter#186917)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC boetger@google.com,stuartmorgan@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
mboetger pushed a commit to mboetger/flutter that referenced this pull request May 27, 2026
Relands flutter#186639, which was reverted in flutter#187170.

The original PR landed clean, but broke the macOS and Linux builds
because `engine/src/flutter/testing/dart/gpu_shader_reload_test.dart`
(added concurrently by flutter#186793, which was in the merge queue at the same
time) still called the old `bindVertexBuffer(view, count)` / `draw()`
API. This reland is identical to flutter#186639 plus a one-spot migration of
that test to `bindVertexBuffer(view)` + `draw(3)`.

---

Moves the vertex and index count off the buffer-binding calls and onto
the draw call.

A simple (breaking) change that fixes a very silly design flaw that I
built into the API near the very beginning. Moves Flutter GPU draws
towards a design that matches virtually all modern graphics APIs,
including today's Impeller! Now is the right time to make changes like
this to Flutter GPU, since the API is not yet considered stable.

Before, `bindVertexBuffer` and `bindIndexBuffer` each took a count, and
a single argument-less `draw()` guessed vertex versus index based on
whether an index buffer happened to be bound.

Sooooo many reasons this was the wrong design:

- **Wrong object.** A draw count belongs on the draw, not on a buffer
binding.
- **Implicit kind.** Indexed vs. non-indexed was inferred from what
happened to be bound, not stated.
- **Colliding counts.** Vertex and index counts shared one field; the
vertex count was dropped when an index buffer was bound.
- **Slot-0-only.** The count came from vertex slot 0; values on other
slots were silently ignored.
- **Opaque draws.** `draw()` told you nothing; you had to trace every
bind to know what it drew.
- **Sticky state.** The count leaked across draws in a pass.
- **Redundant re-binds.** Changing only the count forced re-binding the
buffer.
- **No room to grow.** Nowhere natural for per-draw params like
`instanceCount` or `baseVertex`.
- **Unconventional.** WebGPU, Vulkan, Metal, and D3D all put counts on
the draw.
- **Late errors.** Bad counts failed at `draw()` time, far from the
mistaken line.

Now:
- `bindVertexBuffer` and `bindIndexBuffer` only bind buffers.
- `draw(vertexCount)` does a non-indexed draw.
- `drawIndexed(indexCount)` does an indexed draw.

Instanced draws can be landed later via `draw` and `drawIndexed` gaining
an `instanceCount` parameter later on, assuming the Impeller-side
instancing support in flutter#186653 lands.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
creatorpiyush pushed a commit to creatorpiyush/packages that referenced this pull request Jun 10, 2026
…r#11795)

flutter/flutter@f3a4b98...c8f2f16

2026-05-27 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[Flutter GPU] Add explicit draw counts (#186639)" (flutter/flutter#187170)
2026-05-27 engine-flutter-autoroll@skia.org Roll Dart SDK from 7dcea971af6b to f3db7b7d9801 (2 revisions) (flutter/flutter#187144)
2026-05-27 bdero@google.com [Flutter GPU] Add explicit draw counts (flutter/flutter#186639)
2026-05-27 engine-flutter-autoroll@skia.org Roll Skia from f9db7748563e to fa944af10f91 (1 revision) (flutter/flutter#187139)
2026-05-27 bdero@google.com [Flutter GPU] Flutter GPU ShaderLibrary in-place reload for shader hot reload (flutter/flutter#186793)
2026-05-27 engine-flutter-autoroll@skia.org Roll Skia from a692cbf38952 to f9db7748563e (8 revisions) (flutter/flutter#187135)
2026-05-27 burak.karahan@mail.ru Use local semantics tester in Material button tests (flutter/flutter#186667)
2026-05-27 rmolivares@renzo-olivares.dev Filter out `a: text input` from `team-framework` PR triage  (flutter/flutter#187129)
2026-05-27 bkonyi@google.com [Engine] Fix silent buffer mismatch bug in FML Win32 CommandLineFromPlatform (flutter/flutter#187120)
2026-05-27 srawlins@google.com examples: Remove unused parameters (flutter/flutter#185819)
2026-05-27 116356835+AbdeMohlbi@users.noreply.github.com Remove another `String.valueOf` (flutter/flutter#186628)
2026-05-27 alex.medinsh@gmail.com Print trace when skipping flavor-specific and platform-specific assets (flutter/flutter#187045)
2026-05-26 adilhanney@disroot.org Fix `InteractiveViewer` memory leak from undisposed `CurvedAnimation`s (flutter/flutter#185826)
2026-05-26 meylis@divine.video Fix AccessibilityBridge startup crash on vendor-modified Android (flutter/flutter#184630)
2026-05-26 keertip@users.noreply.github.com Update data driven fixes docs (flutter/flutter#186217)
2026-05-26 ahmedsameha1@gmail.com Add more 0x0 size tests part10 (flutter/flutter#186201)
2026-05-26 46920873+gabrimatic@users.noreply.github.com Disable spell check for obscured text (flutter/flutter#186329)
2026-05-26 chris@bracken.jp [iOS] Migrate VSyncClient and DisplayLinkManager to Swift (flutter/flutter#187001)
2026-05-26 bkonyi@google.com [flutter_tools, devicelab] Add safety filesystem guard to tests (flutter/flutter#186748)
2026-05-26 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from Itd2Jq_ZIABH2rW7B... to k9EizfEGJO4WwQN9-... (flutter/flutter#187115)
2026-05-26 engine-flutter-autoroll@skia.org Roll Dart SDK from 00e625453c43 to 7dcea971af6b (1 revision) (flutter/flutter#187117)
2026-05-26 rmacnak@google.com Remove use of deprecated copy_trees. (flutter/flutter#187091)
2026-05-26 15619084+vashworth@users.noreply.github.com Use resolved implementation plugins with SwiftPM (flutter/flutter#187097)
2026-05-26 engine-flutter-autoroll@skia.org Roll Skia from 27a819894f7c to a692cbf38952 (3 revisions) (flutter/flutter#187109)
2026-05-26 engine-flutter-autoroll@skia.org Roll Packages from 69cf959 to fc795e5 (4 revisions) (flutter/flutter#187114)
2026-05-26 mvincentong@gmail.com Handle simctl process exceptions during discovery (flutter/flutter#186501)
2026-05-26 mvincentong@gmail.com Clarify precache enabled platforms help (flutter/flutter#186878)
2026-05-26 bkonyi@google.com [tool] Refactor artifacts.dart to use enhanced enums and reduce duplication (flutter/flutter#187063)
2026-05-26 jason-simmons@users.noreply.github.com Build script updates for syncing engine sources and building artifacts on linux-arm64 (flutter/flutter#186917)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC boetger@google.com,stuartmorgan@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
…t reload (flutter#186793)

Resolves flutter#186344.

Adds in-place shader hot reload to Flutter GPU's `ShaderLibrary`,
mirroring the existing `FragmentProgram` protocol:

- Per-shader `IsDirty()` / `SetClean()` dirty bit. Fresh shaders start
dirty.
- `ShaderLibrary::ReloadFromAsset` re-fetches and reparses the bundle in
place. Existing `Shader` entries whose names appear in the new bundle
are mutated via `Shader::ResetFrom`, preserving Dart object identity and
the scoped `library_id`.
- `Shader::RegisterSync` evicts a stale registration on the dirty path
(`UnregisterFunction` + `RemovePipelinesWithEntryPoint`) before
re-registering, matching `RuntimeEffectContents::RegisterShader`.
- Dart-side `ShaderLibrary._registry` keyed by asset path, public
`ShaderLibrary.reinitialize`, and the
`ext.ui.gpu.reinitializeShaderLibrary` service extension lazily
registered in debug mode on first `fromAsset`.

## Tool-side integration

The engine API here is intentionally producer-agnostic. `reinitialize`
is keyed by asset path and no-ops when nothing is registered at that
key, so `flutter_tools` never has to classify assets: it can dispatch
`ext.ui.gpu.reinitializeShaderLibrary` opportunistically for any changed
asset path ending in `.shaderbundle`, and the engine ignores paths it
never loaded.

Because of that, the feature works regardless of how the bundle was
produced (a build hook output listed under `flutter.assets:`, a future
`DataAsset`, an asset transformer, or a hand-built bundle), and it needs
no new `AssetKind` and no dedicated `flutter.gpu_shader_bundles:`
pubspec block. The tool-side wiring (reframed around this dispatch) is
tracked in flutter#186345, and the asset-transformer
dependency-tracking piece it depends on is flutter#187051.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
Relands flutter#186639, which was reverted in flutter#187170.

The original PR landed clean, but broke the macOS and Linux builds
because `engine/src/flutter/testing/dart/gpu_shader_reload_test.dart`
(added concurrently by flutter#186793, which was in the merge queue at the same
time) still called the old `bindVertexBuffer(view, count)` / `draw()`
API. This reland is identical to flutter#186639 plus a one-spot migration of
that test to `bindVertexBuffer(view)` + `draw(3)`.

---

Moves the vertex and index count off the buffer-binding calls and onto
the draw call.

A simple (breaking) change that fixes a very silly design flaw that I
built into the API near the very beginning. Moves Flutter GPU draws
towards a design that matches virtually all modern graphics APIs,
including today's Impeller! Now is the right time to make changes like
this to Flutter GPU, since the API is not yet considered stable.

Before, `bindVertexBuffer` and `bindIndexBuffer` each took a count, and
a single argument-less `draw()` guessed vertex versus index based on
whether an index buffer happened to be bound.

Sooooo many reasons this was the wrong design:

- **Wrong object.** A draw count belongs on the draw, not on a buffer
binding.
- **Implicit kind.** Indexed vs. non-indexed was inferred from what
happened to be bound, not stated.
- **Colliding counts.** Vertex and index counts shared one field; the
vertex count was dropped when an index buffer was bound.
- **Slot-0-only.** The count came from vertex slot 0; values on other
slots were silently ignored.
- **Opaque draws.** `draw()` told you nothing; you had to trace every
bind to know what it drew.
- **Sticky state.** The count leaked across draws in a pass.
- **Redundant re-binds.** Changing only the count forced re-binding the
buffer.
- **No room to grow.** Nowhere natural for per-draw params like
`instanceCount` or `baseVertex`.
- **Unconventional.** WebGPU, Vulkan, Metal, and D3D all put counts on
the draw.
- **Late errors.** Bad counts failed at `draw()` time, far from the
mistaken line.

Now:
- `bindVertexBuffer` and `bindIndexBuffer` only bind buffers.
- `draw(vertexCount)` does a non-indexed draw.
- `drawIndexed(indexCount)` does an indexed draw.

Instanced draws can be landed later via `draw` and `drawIndexed` gaining
an `instanceCount` parameter later on, assuming the Impeller-side
instancing support in flutter#186653 lands.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD e: impeller Impeller rendering backend issues and features requests engine flutter/engine related. See also e: labels. flutter-gpu team-fluttergpu Owned by Flutter GPU team

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

[Impeller] Flutter GPU ShaderLibrary supports in-place reload for shader hot reload

3 participants