Skip to content

[flutter_tools] FragmentProgram hot reload doesn't watch transitive #include headers #186343

Description

@bdero

What

When a user authors a FragmentProgram-backed shader (.frag registered under the shaders: pubspec block) that #includes another file, editing the included file does not trigger hot reload. The user sees stale shader output until they edit the top-level .frag itself (which is in the asset watch set) or restart the app.

Why

packages/flutter_tools/lib/src/devfs.dart only watches files registered under flutter.assets: and flutter.shaders: in pubspec, derived from bundle.entries. A .glsl header that's #included from a .frag is unknown to the watcher, so no change event is generated when it's edited.

packages/flutter_tools/lib/src/build_system/tools/shader_compiler.dart invokes impellerc with --input, --sl, --include, and the target flags. It does not pass --depfile, so the dependency information impellerc would happily emit (via OutputDepfile at impeller/compiler/impellerc_main.cc:178) is discarded.

Repro

shaders/
  main.frag             # listed under flutter.shaders: in pubspec
  helpers.glsl          # #included by main.frag, not listed anywhere
  1. Run the app, observe the FragmentProgram output.
  2. Edit helpers.glsl. Save.
  3. Hot reload is not triggered. The shader on screen continues to use the old helpers.glsl.
  4. Edit main.frag (anything, even a whitespace change). Save.
  5. Hot reload fires. Now the latest helpers.glsl content takes effect.

Fix

This is pure flutter_tools work; the engine half (impellerc writing depfiles) already works for the single-shader compile path:

  1. ShaderCompiler.compileShader (build_system/tools/shader_compiler.dart) passes --depfile=<adjacent path> to impellerc.
  2. After a successful compile, parse the depfile and feed the listed paths into the devfs watch set.
  3. When any watched include's mtime changes, re-trigger recompileShader for every shader that depends on it.

The watch-set semantics need to become dynamic (today's watch set is static, derived from pubspec at startup). The depfile format is the Ninja-style single-line <target>: <dep1> <dep2> ... that Compiler::CreateDepfileContents emits.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listc: new featureNothing broken; request for a new capabilitye: impellerImpeller rendering backend issues and features requeststeam-toolOwned by Flutter Tool teamtoolAffects the "flutter" command-line tool. See also t: labels.triaged-toolTriaged by Flutter Tool team

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions