Repository navigation
Import flutter_shaders package - #12583
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request imports the flutter_shaders package into the repository, providing utilities like AnimatedSampler, ShaderInkFeature, SetUniforms, and ShaderBuilder to simplify working with the FragmentProgram API. Feedback on the implementation highlights a native memory leak in AnimatedSampler due to an undisposed ui.Scene, an incorrect radius calculation in ShaderInkFeature that ignores the tap position, and an optimization opportunity in ShaderBuilder to prevent redundant concurrent asset loading.
| return builder.build().toImageSync( | ||
| (pixelRatio * bounds.width).ceil(), | ||
| (pixelRatio * bounds.height).ceil(), | ||
| ); |
There was a problem hiding this comment.
The ui.Scene returned by builder.build() is a native resource that must be explicitly disposed to avoid memory leaks. Since _buildChildScene is called on every frame of an animation, this will cause a continuous native memory leak. Store the scene in a local variable and dispose it in a finally block.
| return builder.build().toImageSync( | |
| (pixelRatio * bounds.width).ceil(), | |
| (pixelRatio * bounds.height).ceil(), | |
| ); | |
| final ui.Scene scene = builder.build(); | |
| try { | |
| return scene.toImageSync( | |
| (pixelRatio * bounds.width).ceil(), | |
| (pixelRatio * bounds.height).ceil(), | |
| ); | |
| } finally { | |
| scene.dispose(); | |
| } |
| final Size size = rectCallback != null ? rectCallback().size : referenceBox.size; | ||
| final double d1 = size.bottomRight(Offset.zero).distance; | ||
| final double d2 = (size.topRight(Offset.zero) - size.bottomLeft(Offset.zero)).distance; | ||
| return math.max(d1, d2) / 2.0; |
There was a problem hiding this comment.
The _getTargetRadius function calculates the target radius as half of the diagonal of the bounding box, completely ignoring the tap position. If a user taps near a corner or edge, the splash will not expand enough to cover the entire widget. To ensure the splash covers the entire widget, the target radius should be the maximum distance from the tap position to the four corners of the bounding box.
final Size size = rectCallback != null ? rectCallback().size : referenceBox.size;
final double d1 = position.distance;
final double d2 = (position - size.topRight(Offset.zero)).distance;
final double d3 = (position - size.bottomLeft(Offset.zero)).distance;
final double d4 = (position - size.bottomRight(Offset.zero)).distance;
return math.max(math.max(d1, d2), math.max(d3, d4));| static final Map<String, ui.FragmentProgram> _shaderCache = <String, ui.FragmentProgram>{}; | ||
|
|
||
| @override | ||
| void initState() { | ||
| super.initState(); | ||
| _loadShader(widget.assetKey); | ||
| } | ||
|
|
||
| @override | ||
| void didUpdateWidget(covariant ShaderBuilder oldWidget) { | ||
| super.didUpdateWidget(oldWidget); | ||
| if (oldWidget.assetKey != widget.assetKey) { | ||
| _loadShader(widget.assetKey); | ||
| } | ||
| } | ||
|
|
||
| void _loadShader(String assetKey) { | ||
| if (_shaderCache.containsKey(assetKey)) { | ||
| program = _shaderCache[assetKey]; | ||
| shader = program!.fragmentShader(); | ||
| return; | ||
| } | ||
|
|
||
| ui.FragmentProgram.fromAsset(assetKey).then( | ||
| (ui.FragmentProgram program) { | ||
| if (!mounted) { | ||
| return; | ||
| } | ||
| setState(() { | ||
| this.program = program; | ||
| shader = program.fragmentShader(); | ||
| _shaderCache[assetKey] = program; | ||
| }); | ||
| }, | ||
| onError: (Object error, StackTrace stackTrace) { | ||
| FlutterError.reportError(FlutterErrorDetails(exception: error, stack: stackTrace)); | ||
| }, | ||
| ); | ||
| } |
There was a problem hiding this comment.
If multiple ShaderBuilder widgets with the same assetKey are initialized concurrently before the first one finishes loading, they will all trigger redundant ui.FragmentProgram.fromAsset calls. We can optimize this by keeping a map of pending futures to share the loading process, while still caching the completed FragmentProgram for synchronous access on subsequent builds.
static final Map<String, ui.FragmentProgram> _shaderCache = <String, ui.FragmentProgram>{};
static final Map<String, Future<ui.FragmentProgram>> _pendingLoads = <String, Future<ui.FragmentProgram>>{};
@override
void initState() {
super.initState();
_loadShader(widget.assetKey);
}
@override
void didUpdateWidget(covariant ShaderBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.assetKey != widget.assetKey) {
_loadShader(widget.assetKey);
}
}
void _loadShader(String assetKey) {
if (_shaderCache.containsKey(assetKey)) {
program = _shaderCache[assetKey];
shader = program!.fragmentShader();
return;
}
final Future<ui.FragmentProgram> future = _pendingLoads.putIfAbsent(
assetKey,
() => ui.FragmentProgram.fromAsset(assetKey),
);
future.then(
(ui.FragmentProgram loadedProgram) {
_shaderCache[assetKey] = loadedProgram;
_pendingLoads.remove(assetKey);
if (!mounted) {
return;
}
setState(() {
program = loadedProgram;
shader = loadedProgram.fragmentShader();
});
},
onError: (Object error, StackTrace stackTrace) {
_pendingLoads.remove(assetKey);
FlutterError.reportError(FlutterErrorDetails(exception: error, stack: stackTrace));
},
);
}|
The failing golden test was generated with material 2, the material 3 version is not very interesting. I can swap them, but it might be better to find something better maybe? |
It's not clear to me exactly what it's intended to test. Let's just swap in the current golden, and the new owners can decide if they want to adjust the test later. |
stuartmorgan-g
left a comment
There was a problem hiding this comment.
The changes relative to the initial import all LGTM. Thanks for tackling that test class implements issue with the refactor!
80eae96 to
6021657
Compare
Imports flutter_shaders into the repository and updates it to conform to repository conventions: - Updates package metadata and repository URLs in pubspec.yaml. - Adds topics (shaders, graphics) in pubspec.yaml. - Updates SDK constraints to Flutter >=3.38.0 and Dart ^3.10.0. - Adds flutter_shaders to repository README.md and .github/labeler.yml. - Removes standalone GitHub Actions workflows and pubspec.lock. - Standardizes license headers across source, example, test, and shader files. - Adds FloatUniformsSetter interface for configuring float uniforms. - Adds comprehensive documentation comments for public APIs. - Fixes analysis warnings and formats code according to repo style. - Updates test harness in test/set_uniforms_test.dart to avoid mocking base classes. - Updates golden files and test configuration for platform compatibility. - Bumps package version to 0.1.4 and updates CHANGELOG.md.
6021657 to
f458c13
Compare
flutter/packages@7660d46...54706bd 2026-10-08 [email protected] [image_picker_ios] Return an error for undecodable image data (flutter/packages#12267) 2026-10-07 [email protected] [flutter shaders] update min flutter version (flutter/packages#13160) 2026-10-07 [email protected] Import flutter_shaders package (flutter/packages#12583) 2026-10-07 [email protected] [material_ui] Migrate M3 Typography template to use new gen_defaults (flutter/packages#13074) 2026-10-07 [email protected] Sync release-material_ui-1.6.0 to main (flutter/packages#13149) 2026-10-07 [email protected] [pigeon] Fix native interop (JNI) calls in minified Android release builds (flutter/packages#13151) 2026-10-06 [email protected] [material_ui] Migrate ListTile and SwitchListTile API doc snippets to {@example} (batch 10) (flutter/packages#13097) 2026-10-06 [email protected] Sync release-cupertino_ui-1.1.2 to main (flutter/packages#13150) 2026-10-06 [email protected] [material_ui] Fix `TabBar` assertion to allow `indicatorWeight: 0` with a themed `indicator` (flutter/packages#12696) 2026-10-06 [email protected] [material_ui] Fix time picker input validation for 24-hour locales (flutter/packages#13033) 2026-10-06 [email protected] [material_ui] Migrate Checkbox, CheckboxListTile, Radio, and RadioListTile API doc snippets to {@example} (batch 9) (flutter/packages#13112) 2026-10-06 [email protected] [quick_actions_android] Return null from getLaunchAction when no activity is attached (flutter/packages#12331) If this roll has caused a breakage, revert this CL and set the roller to dry run mode using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: 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
flutter/packages@7660d46...54706bd 2026-10-08 [email protected] [image_picker_ios] Return an error for undecodable image data (flutter/packages#12267) 2026-10-07 [email protected] [flutter shaders] update min flutter version (flutter/packages#13160) 2026-10-07 [email protected] Import flutter_shaders package (flutter/packages#12583) 2026-10-07 [email protected] [material_ui] Migrate M3 Typography template to use new gen_defaults (flutter/packages#13074) 2026-10-07 [email protected] Sync release-material_ui-1.6.0 to main (flutter/packages#13149) 2026-10-07 [email protected] [pigeon] Fix native interop (JNI) calls in minified Android release builds (flutter/packages#13151) 2026-10-06 [email protected] [material_ui] Migrate ListTile and SwitchListTile API doc snippets to {@example} (batch 10) (flutter/packages#13097) 2026-10-06 [email protected] Sync release-cupertino_ui-1.1.2 to main (flutter/packages#13150) 2026-10-06 [email protected] [material_ui] Fix `TabBar` assertion to allow `indicatorWeight: 0` with a themed `indicator` (flutter/packages#12696) 2026-10-06 [email protected] [material_ui] Fix time picker input validation for 24-hour locales (flutter/packages#13033) 2026-10-06 [email protected] [material_ui] Migrate Checkbox, CheckboxListTile, Radio, and RadioListTile API doc snippets to {@example} (batch 9) (flutter/packages#13112) 2026-10-06 [email protected] [quick_actions_android] Return null from getLaunchAction when no activity is attached (flutter/packages#12331) If this roll has caused a breakage, revert this CL and set the roller to dry run mode using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: 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

autosubmitReviewers: Please DO NOT add the
autosubmitlabel to this PR. This is an initial repository migration and must be landed manually following the repository transfer process.Description
This PR imports
flutter_shadersintoflutter/packagesfrom its original repository:Source Repository: https://github.com/jonahwilliams/flutter_shaders
The commit history from the original repository was preserved via git subtree/merge up to commit
2802b9e47b.Reviewer Guide
Summary of Changes Relative to Initial Import
pubspec.yamlwith theflutter/packagesmono-reporepositoryandissue_trackerURLs, and addedtopics: [shaders, graphics].p: flutter_shadersto.github/labeler.yml.flutter_shadersto the packages table in the rootREADME.md.// Copyright 2013 The Flutter Authors).pubspec.yamlandexample/pubspec.yamlto Flutter>=3.38.0/ Dart^3.10.0.set_uniforms: ExtractedFloatUniformsSetteras an abstract base class/interface so uniform conversion logic can be tested and extended without implementingui.FragmentShader(which is abase classin Dart 3 and cannot be implemented outsidedart:ui). KeptUniformsSetternon-nullable and backwards-compatible.animated_sampler_test: Updated test callbacks from 4 arguments to 3 arguments (expectAsync3) to match theAnimatedSamplerBuildersignature (theoffsetparameter was removed in0.0.6).setColors w/ premultiplywhere a zero-alpha color was expected to have non-zero alpha.UniformsSetterandShaderInkFeatureFactory.prefer_foreach, control body newlines) and formatted all files withdart format.0.1.4inpubspec.yaml.CHANGELOG.mdentry describing the package transfer and changes.Verification
dart run script/tool/bin/flutter_plugin_tools.dart validate --packages flutter_shaderspasses.dart run script/tool/bin/flutter_plugin_tools.dart analyze --packages flutter_shaderspasses with 0 issues.dart run script/tool/bin/flutter_plugin_tools.dart dart-test --packages flutter_shaderspasses (all unit and example tests pass).dart run script/tool/bin/flutter_plugin_tools.dart license-checkpasses.Reminder: DO NOT ADD
autosubmit.