Skip to content

Commit 9c0f239

Browse files
authored
Put shaders under a 'shaders' section in the manifest (#106752)
1 parent 02f0b2d commit 9c0f239

9 files changed

Lines changed: 145 additions & 26 deletions

File tree

packages/flutter_tools/lib/src/asset.dart

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,17 @@ abstract class AssetBundleFactory {
6363
AssetBundle createBundle();
6464
}
6565

66+
enum AssetKind {
67+
regular,
68+
font,
69+
shader,
70+
}
71+
6672
abstract class AssetBundle {
6773
Map<String, DevFSContent> get entries;
6874

75+
Map<String, AssetKind> get entryKinds;
76+
6977
/// The files that were specified under the deferred components assets sections
7078
/// in pubspec.
7179
Map<String, Map<String, DevFSContent>> get deferredComponentsEntries;
@@ -135,6 +143,9 @@ class ManifestAssetBundle implements AssetBundle {
135143
@override
136144
final Map<String, DevFSContent> entries = <String, DevFSContent>{};
137145

146+
@override
147+
final Map<String, AssetKind> entryKinds = <String, AssetKind>{};
148+
138149
@override
139150
final Map<String, Map<String, DevFSContent>> deferredComponentsEntries = <String, Map<String, DevFSContent>>{};
140151

@@ -218,6 +229,7 @@ class ManifestAssetBundle implements AssetBundle {
218229
_lastBuildTimestamp = DateTime.now();
219230
if (flutterManifest.isEmpty) {
220231
entries[_kAssetManifestJson] = DevFSStringContent('{}');
232+
entryKinds[_kAssetManifestJson] = AssetKind.regular;
221233
return 0;
222234
}
223235

@@ -370,6 +382,7 @@ class ManifestAssetBundle implements AssetBundle {
370382
inputFiles.add(variantFile);
371383
assert(variantFile.existsSync());
372384
entries[variant.entryUri.path] ??= DevFSFileContent(variantFile);
385+
entryKinds[variant.entryUri.path] ??= variant.assetKind;
373386
}
374387
}
375388
// Save the contents of each deferred component image, image variant, and font
@@ -418,6 +431,7 @@ class ManifestAssetBundle implements AssetBundle {
418431
final File assetFile = asset.lookupAssetFile(_fileSystem);
419432
assert(assetFile.existsSync(), 'Missing ${assetFile.path}');
420433
entries[asset.entryUri.path] ??= DevFSFileContent(assetFile);
434+
entryKinds[asset.entryUri.path] ??= asset.assetKind;
421435
}
422436

423437
// Update wildcard directories we can detect changes in them.
@@ -449,23 +463,25 @@ class ManifestAssetBundle implements AssetBundle {
449463
_fileSystem.file('DOES_NOT_EXIST_RERUN_FOR_WILDCARD$suffix').absolute);
450464
}
451465

452-
_setIfChanged(_kAssetManifestJson, assetManifest);
453-
_setIfChanged(kFontManifestJson, fontManifest);
466+
_setIfChanged(_kAssetManifestJson, assetManifest, AssetKind.regular);
467+
_setIfChanged(kFontManifestJson, fontManifest, AssetKind.regular);
454468
_setLicenseIfChanged(licenseResult.combinedLicenses, targetPlatform);
455469
return 0;
456470
}
457471

458472
@override
459473
List<File> additionalDependencies = <File>[];
460474

461-
void _setIfChanged(String key, DevFSStringContent content) {
475+
void _setIfChanged(String key, DevFSStringContent content, AssetKind assetKind) {
462476
if (!entries.containsKey(key)) {
463477
entries[key] = content;
478+
entryKinds[key] = assetKind;
464479
return;
465480
}
466481
final DevFSStringContent? oldContent = entries[key] as DevFSStringContent?;
467482
if (oldContent?.string != content.string) {
468483
entries[key] = content;
484+
entryKinds[key] = assetKind;
469485
}
470486
}
471487

@@ -477,7 +493,7 @@ class ManifestAssetBundle implements AssetBundle {
477493
// dart:io to decompress it. So use the standard _setIfChanged to check if
478494
// the strings still match.
479495
if (targetPlatform == TargetPlatform.web_javascript) {
480-
_setIfChanged(_kNoticeFile, DevFSStringContent(combinedLicenses));
496+
_setIfChanged(_kNoticeFile, DevFSStringContent(combinedLicenses), AssetKind.regular);
481497
return;
482498
}
483499

@@ -495,6 +511,7 @@ class ManifestAssetBundle implements AssetBundle {
495511
// common English words with domain specific words like copyright.
496512
hintString: 'copyrightsoftwaretothisinandorofthe',
497513
);
514+
entryKinds[_kNoticeZippedFile] = AssetKind.regular;
498515
}
499516
}
500517

@@ -519,6 +536,7 @@ class ManifestAssetBundle implements AssetBundle {
519536
relativeUri: Uri(path: entryUri.pathSegments.last),
520537
entryUri: entryUri,
521538
package: null,
539+
assetKind: AssetKind.font,
522540
));
523541
}
524542
}
@@ -546,6 +564,7 @@ class ManifestAssetBundle implements AssetBundle {
546564
relativeUri: Uri(path: entryUri.pathSegments.last),
547565
entryUri: entryUri,
548566
package: null,
567+
assetKind: AssetKind.shader,
549568
));
550569
}
551570

@@ -745,6 +764,21 @@ class ManifestAssetBundle implements AssetBundle {
745764
}
746765
}
747766

767+
for (final Uri shaderUri in flutterManifest.shaders) {
768+
_parseAssetFromFile(
769+
packageConfig,
770+
flutterManifest,
771+
assetBase,
772+
cache,
773+
result,
774+
shaderUri,
775+
excludeDirs: excludeDirs,
776+
packageName: packageName,
777+
attributedPackage: attributedPackage,
778+
assetKind: AssetKind.shader,
779+
);
780+
}
781+
748782
// Add assets referenced in the fonts section of the manifest.
749783
for (final Font font in flutterManifest.fonts) {
750784
for (final FontAsset fontAsset in font.fontAssets) {
@@ -754,6 +788,7 @@ class ManifestAssetBundle implements AssetBundle {
754788
fontAsset.assetUri,
755789
packageName,
756790
attributedPackage,
791+
assetKind: AssetKind.font,
757792
);
758793
final File baseAssetFile = baseAsset.lookupAssetFile(_fileSystem);
759794
if (!baseAssetFile.existsSync()) {
@@ -816,13 +851,15 @@ class ManifestAssetBundle implements AssetBundle {
816851
List<String> excludeDirs = const <String>[],
817852
String? packageName,
818853
Package? attributedPackage,
854+
AssetKind assetKind = AssetKind.regular,
819855
}) {
820856
final _Asset asset = _resolveAsset(
821857
packageConfig,
822858
assetBase,
823859
assetUri,
824860
packageName,
825861
attributedPackage,
862+
assetKind: assetKind,
826863
);
827864
final List<_Asset> variants = <_Asset>[];
828865
final File assetFile = asset.lookupAssetFile(_fileSystem);
@@ -839,6 +876,7 @@ class ManifestAssetBundle implements AssetBundle {
839876
entryUri: entryUri,
840877
relativeUri: relativeUri,
841878
package: attributedPackage,
879+
assetKind: assetKind,
842880
),
843881
);
844882
}
@@ -852,8 +890,9 @@ class ManifestAssetBundle implements AssetBundle {
852890
String assetsBaseDir,
853891
Uri assetUri,
854892
String? packageName,
855-
Package? attributedPackage,
856-
) {
893+
Package? attributedPackage, {
894+
AssetKind assetKind = AssetKind.regular,
895+
}) {
857896
final String assetPath = _fileSystem.path.fromUri(assetUri);
858897
if (assetUri.pathSegments.first == 'packages'
859898
&& !_fileSystem.isFileSync(_fileSystem.path.join(assetsBaseDir, assetPath))) {
@@ -863,6 +902,7 @@ class ManifestAssetBundle implements AssetBundle {
863902
assetUri,
864903
packageConfig,
865904
attributedPackage,
905+
assetKind: assetKind,
866906
);
867907
if (packageAsset != null) {
868908
return packageAsset;
@@ -876,10 +916,16 @@ class ManifestAssetBundle implements AssetBundle {
876916
: Uri(pathSegments: <String>['packages', packageName, ...assetUri.pathSegments]), // Asset from, and declared in $packageName.
877917
relativeUri: assetUri,
878918
package: attributedPackage,
919+
assetKind: assetKind,
879920
);
880921
}
881922

882-
_Asset? _resolvePackageAsset(Uri assetUri, PackageConfig packageConfig, Package? attributedPackage) {
923+
_Asset? _resolvePackageAsset(
924+
Uri assetUri,
925+
PackageConfig packageConfig,
926+
Package? attributedPackage, {
927+
AssetKind assetKind = AssetKind.regular,
928+
}) {
883929
assert(assetUri.pathSegments.first == 'packages');
884930
if (assetUri.pathSegments.length > 1) {
885931
final String packageName = assetUri.pathSegments[1];
@@ -891,6 +937,7 @@ class ManifestAssetBundle implements AssetBundle {
891937
entryUri: assetUri,
892938
relativeUri: Uri(pathSegments: assetUri.pathSegments.sublist(2)),
893939
package: attributedPackage,
940+
assetKind: assetKind,
894941
);
895942
}
896943
}
@@ -910,6 +957,7 @@ class _Asset {
910957
required this.relativeUri,
911958
required this.entryUri,
912959
required this.package,
960+
this.assetKind = AssetKind.regular,
913961
});
914962

915963
final String baseDir;
@@ -923,6 +971,8 @@ class _Asset {
923971
/// A platform-independent URL representing the entry for the asset manifest.
924972
final Uri entryUri;
925973

974+
final AssetKind assetKind;
975+
926976
File lookupAssetFile(FileSystem fileSystem) {
927977
return fileSystem.file(fileSystem.path.join(baseDir, fileSystem.path.fromUri(relativeUri)));
928978
}
@@ -951,7 +1001,8 @@ class _Asset {
9511001
return other is _Asset
9521002
&& other.baseDir == baseDir
9531003
&& other.relativeUri == relativeUri
954-
&& other.entryUri == entryUri;
1004+
&& other.entryUri == entryUri
1005+
&& other.assetKind == assetKind;
9551006
}
9561007

9571008
@override

packages/flutter_tools/lib/src/build_system/targets/assets.dart

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ Future<Depfile> copyAssets(
8888
if (skslBundle != null)
8989
kSkSLShaderBundlePath: skslBundle,
9090
};
91+
final Map<String, AssetKind> entryKinds = <String, AssetKind>{
92+
...assetBundle.entryKinds,
93+
};
9194

9295
await Future.wait<void>(
9396
assetEntries.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async {
@@ -100,19 +103,31 @@ Future<Depfile> copyAssets(
100103
// and the native APIs will look for files this way.
101104
final File file = environment.fileSystem.file(
102105
environment.fileSystem.path.join(outputDirectory.path, entry.key));
106+
final AssetKind assetKind = entryKinds[entry.key] ?? AssetKind.regular;
103107
outputs.add(file);
104108
file.parent.createSync(recursive: true);
105109
final DevFSContent content = entry.value;
106110
if (content is DevFSFileContent && content.file is File) {
107111
inputs.add(content.file as File);
108-
if (!await iconTreeShaker.subsetFont(
109-
input: content.file as File,
110-
outputPath: file.path,
111-
relativePath: entry.key,
112-
) && !await shaderCompiler.compileShader(
113-
input: content.file as File,
114-
outputPath: file.path,
115-
)) {
112+
bool doCopy = true;
113+
switch (assetKind) {
114+
case AssetKind.regular:
115+
break;
116+
case AssetKind.font:
117+
doCopy = !await iconTreeShaker.subsetFont(
118+
input: content.file as File,
119+
outputPath: file.path,
120+
relativePath: entry.key,
121+
);
122+
break;
123+
case AssetKind.shader:
124+
doCopy = !await shaderCompiler.compileShader(
125+
input: content.file as File,
126+
outputPath: file.path,
127+
);
128+
break;
129+
}
130+
if (doCopy) {
116131
await (content.file as File).copy(file.path);
117132
}
118133
} else {
@@ -127,8 +142,8 @@ Future<Depfile> copyAssets(
127142
// The assets are included in assetBundle.entries as a normal asset when
128143
// building as debug.
129144
if (environment.defines[kDeferredComponents] == 'true' && buildMode != null) {
130-
await Future.wait<void>(
131-
assetBundle.deferredComponentsEntries.entries.map<Future<void>>((MapEntry<String, Map<String, DevFSContent>> componentEntries) async {
145+
await Future.wait<void>(assetBundle.deferredComponentsEntries.entries.map<Future<void>>(
146+
(MapEntry<String, Map<String, DevFSContent>> componentEntries) async {
132147
final Directory componentOutputDir =
133148
environment.projectDir
134149
.childDirectory('build')

packages/flutter_tools/lib/src/bundle_builder.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ Future<AssetBundle?> buildAssets({
134134
Future<void> writeBundle(
135135
Directory bundleDir,
136136
Map<String, DevFSContent> assetEntries,
137+
Map<String, AssetKind> entryKinds,
137138
{ Logger? loggerOverride }
138139
) async {
139140
loggerOverride ??= globals.logger;

packages/flutter_tools/lib/src/commands/test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
477477
}
478478
if (_needRebuild(assetBundle.entries)) {
479479
await writeBundle(globals.fs.directory(globals.fs.path.join('build', 'unit_test_assets')),
480-
assetBundle.entries);
480+
assetBundle.entries, assetBundle.entryKinds);
481481
}
482482
}
483483

packages/flutter_tools/lib/src/flutter_manifest.dart

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,33 @@ class FlutterManifest {
370370
return fonts;
371371
}
372372

373+
374+
late final List<Uri> shaders = _extractShaders();
375+
376+
List<Uri> _extractShaders() {
377+
if (!_flutterDescriptor.containsKey('shaders')) {
378+
return <Uri>[];
379+
}
380+
381+
final List<Object?>? shaders = _flutterDescriptor['shaders'] as List<Object?>?;
382+
if (shaders == null) {
383+
return const <Uri>[];
384+
}
385+
final List<Uri> results = <Uri>[];
386+
for (final Object? shader in shaders) {
387+
if (shader is! String || shader == null || shader == '') {
388+
_logger.printError('Shader manifest contains a null or empty uri.');
389+
continue;
390+
}
391+
try {
392+
results.add(Uri(pathSegments: shader.split('/')));
393+
} on FormatException {
394+
_logger.printError('Shader manifest contains invalid uri: $shader.');
395+
}
396+
}
397+
return results;
398+
}
399+
373400
/// Whether a synthetic flutter_gen package should be generated.
374401
///
375402
/// This can be provided to the [Pub] interface to inject a new entry
@@ -498,7 +525,17 @@ void _validateFlutter(YamlMap? yaml, List<String> errors) {
498525
break;
499526
case 'assets':
500527
if (yamlValue is! YamlList) {
501-
528+
errors.add('Expected "$yamlKey" to be a list, but got $yamlValue (${yamlValue.runtimeType}).');
529+
} else if (yamlValue.isEmpty) {
530+
break;
531+
} else if (yamlValue[0] is! String) {
532+
errors.add(
533+
'Expected "$yamlKey" to be a list of strings, but the first element is $yamlValue (${yamlValue.runtimeType}).',
534+
);
535+
}
536+
break;
537+
case 'shaders':
538+
if (yamlValue is! YamlList) {
502539
errors.add('Expected "$yamlKey" to be a list, but got $yamlValue (${yamlValue.runtimeType}).');
503540
} else if (yamlValue.isEmpty) {
504541
break;

packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,10 @@ Future<void> _buildAssets(
124124
throwToolExit('Unable to find assets.', exitCode: 1);
125125
}
126126

127-
final Map<String, DevFSContent> assetEntries =
128-
Map<String, DevFSContent>.of(assets.entries);
129-
await writeBundle(globals.fs.directory(assetDir), assetEntries);
127+
final Map<String, DevFSContent> assetEntries = Map<String, DevFSContent>.of(
128+
assets.entries,
129+
);
130+
await writeBundle(globals.fs.directory(assetDir), assetEntries, assets.entryKinds);
130131

131132
final String appName = fuchsiaProject.project.manifest.appName;
132133
final String outDir = getFuchsiaBuildDirectory();

packages/flutter_tools/lib/src/isolated/devfs_web.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,7 @@ class WebDevFS implements DevFS {
843843
await writeBundle(
844844
globals.fs.directory(getAssetBuildDirectory()),
845845
bundle.entries,
846+
bundle.entryKinds,
846847
);
847848
}
848849
}

0 commit comments

Comments
 (0)